mirror of
https://github.com/boostorg/build.git
synced 2026-02-15 13:02:11 +00:00
Merged tools, system, filesystem from trunk at 41106
[SVN r41109]
This commit is contained in:
@@ -331,18 +331,16 @@ stage installed : application : <dll-path>/usr/lib/snake
|
||||
<para>It is desirable to declare standard libraries available on a
|
||||
given system. Putting target declaration in Jamfile is not really
|
||||
good, since locations of the libraries can vary. The solution is
|
||||
to put the following to site-config.jam.</para>
|
||||
to declare the targets in site-config.jam:</para>
|
||||
<programlisting>
|
||||
import project ;
|
||||
project.initialize $(__name__) ;
|
||||
project site-config ;
|
||||
lib zlib : : <name>z ;
|
||||
</programlisting>
|
||||
|
||||
<para>The second line allows this module to act as project. The
|
||||
third line gives id to this project — it really has no location
|
||||
and cannot be used otherwise. The fourth line just declares a
|
||||
target. Now, one can write:
|
||||
<para>Recall that both <filename>site-config.jam</filename> and
|
||||
<filename>user-config.jam</filename> are projects, and everything
|
||||
you can do in a Jamfile you can do in those files. So, you declare
|
||||
a project id and a target. Now, one can write:
|
||||
<programlisting>
|
||||
exe hello : hello.cpp /site-config//zlib ;
|
||||
</programlisting>
|
||||
|
||||
@@ -316,7 +316,8 @@ lib tools : [ glob *.cpp : file_to_exclude.cpp bad*.cpp ] ;
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<varlistentry id="bbv2.reference.glob-tree">
|
||||
<indexterm><primary>glob-tree</primary></indexterm>
|
||||
<term><literal>glob-tree</literal></term>
|
||||
|
||||
<listitem><para>The <code>glob-tree</code> is similar to the
|
||||
@@ -947,11 +948,20 @@ using intel-win : &toolset_ops; ;</programlisting>
|
||||
<para>The module is initialized using the following
|
||||
syntax:</para>
|
||||
<programlisting>
|
||||
using acc ;</programlisting>
|
||||
using acc : &toolset_ops; ;</programlisting>
|
||||
|
||||
<para>There are no configuration options. The
|
||||
compiler will always be invoked as <command>aCC</command> and should
|
||||
be in <envar>PATH</envar>.</para>
|
||||
&using_repeation;
|
||||
|
||||
|
||||
<para>
|
||||
If the command is not specified, the <command>aCC</command>
|
||||
binary will be searched in <envar>PATH</envar>.</para>
|
||||
|
||||
&option_list_intro;
|
||||
<variablelist>
|
||||
<xi:include href="fragments.xml#xpointer(id('common_options')/*)"
|
||||
parse="xml"/>
|
||||
</variablelist>
|
||||
|
||||
</section>
|
||||
|
||||
|
||||
@@ -26,5 +26,7 @@
|
||||
</appendix>
|
||||
|
||||
<xi:include href="v1_vs_v2.xml"/>
|
||||
|
||||
<index/>
|
||||
|
||||
</book>
|
||||
|
||||
@@ -18,8 +18,7 @@
|
||||
<section id="bbv2.tasks.programs">
|
||||
<title>Programs</title>
|
||||
|
||||
<indexterm><primary>Builtin
|
||||
rules</primary><secondary>exe</secondary></indexterm>
|
||||
<indexterm><primary>exe</primary></indexterm>
|
||||
<para>Programs are created using the <code>exe</code> rule, which
|
||||
follows the <link linkend="bbv2.main-target-rule-syntax">common
|
||||
syntax</link>. For example:
|
||||
@@ -302,6 +301,7 @@ install dist : hello
|
||||
|
||||
<bridgehead>Preserving Directory Hierarchy</bridgehead>
|
||||
|
||||
<indexterm><primary>install-source-root</primary></indexterm>
|
||||
<para>By default, the <code>install</code> rules will stip paths from
|
||||
it's sources. So, if sources include <filename>a/b/c.hpp</filename>,
|
||||
the <filename>a/b</filename> part will be ignored. To make the
|
||||
@@ -319,6 +319,10 @@ install headers
|
||||
|
||||
the a file named <filename>/tmp/b/c.h</filename> will be created.
|
||||
</para>
|
||||
|
||||
<para>The <link linkend="bbv2.reference.glob-tree">glob-tree</link> rule
|
||||
can be used to find all files below a given directory, making
|
||||
it easy to install entire directory tree.</para>
|
||||
|
||||
<bridgehead>Installing into Several Directories</bridgehead>
|
||||
|
||||
|
||||
@@ -429,9 +429,9 @@ The <filename>/library-example/foo//bar</filename> syntax is used
|
||||
<para>If you want all applications in some project to link
|
||||
to a certain library, you can avoid having to specify it directly the sources of every
|
||||
target by using the
|
||||
<varname><source></varname> property. For example, if <filename>/boost/filesystem//fs</filename>
|
||||
<varname><library></varname> property. For example, if <filename>/boost/filesystem//fs</filename>
|
||||
should be linked to all applications in your project, you can add
|
||||
<code><source>/boost/filesystem//fs</code> to the project's requirements, like this:</para>
|
||||
<code><library>/boost/filesystem//fs</code> to the project's requirements, like this:</para>
|
||||
|
||||
<programlisting>
|
||||
project
|
||||
|
||||
@@ -58,7 +58,8 @@ class soap-generator : generator
|
||||
t2 = [ new file-target $(name)_server : CPP : $(project)
|
||||
: $(a) ] ;
|
||||
}
|
||||
return $(t) $(t2) ;
|
||||
return [ virtual-target.register $(t) ]
|
||||
[ virtual-target.register $(t2) ] ;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,43 @@
|
||||
# Copyright 2003, 2005 Douglas Gregor
|
||||
# Copyright 2004 John Maddock
|
||||
# Copyright 2002, 2003, 2004 Vladimir Prus
|
||||
# Copyright 2002, 2003, 2004, 2007 Vladimir Prus
|
||||
# Distributed under the Boost Software License, Version 1.0.
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
# This file is used to configure your Boost.Build installation. Please read
|
||||
# the user manual to find out where to put it.
|
||||
# This file is used to configure your Boost.Build installation.
|
||||
# You can modify this file in place, or you can place it it
|
||||
# permanent location so that it's not overwritten should you
|
||||
# get new version of Boost.Build. See:
|
||||
#
|
||||
# http://boost.org/boost-build2/doc/html/bbv2/reference.html#bbv2.reference.init
|
||||
#
|
||||
# for documentation about permanent location.
|
||||
|
||||
# This file specifies which toolsets (C++ compilers), libraries,
|
||||
# and other tools are available. Often, you should be able to
|
||||
# just uncomment existing example lines and adjust them to taste.
|
||||
# The complete list of supported tools, and configuration instructions
|
||||
# can be found at:
|
||||
#
|
||||
# http://boost.org/boost-build2/doc/html/bbv2/reference/tools.html
|
||||
#
|
||||
|
||||
# This file uses Jam language syntax to describe available tools.
|
||||
# Mostly, there are 'using' lines, that contain the name of the used
|
||||
# tools, and parameters to pass to those tools -- where paremeters
|
||||
# are separated by semicolons.
|
||||
# Important syntax notes:
|
||||
#
|
||||
# - Both ':' and ';' must be separated from other tokens by whitespace
|
||||
# - The '\' symbol is quote character, so when specifying Windows paths
|
||||
# it's recommended to use '/' instead, or use '\\'.
|
||||
#
|
||||
# More details about syntax can be found at:
|
||||
#
|
||||
# http://boost.org/boost-build2/doc/html/bbv2/advanced.html#bbv2.advanced.jam_language
|
||||
#
|
||||
|
||||
# Toolset declarations are most important in this file. They tell Boost.Build
|
||||
# what compilers are available and where to look for them. The first toolset
|
||||
# will become "default" one.
|
||||
# Some important libraries can also be configured.
|
||||
# Uncomment relevant parts to suite your local configuration and preferences.
|
||||
|
||||
import toolset : using ;
|
||||
|
||||
# GCC configuration
|
||||
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
Copyright 2004, 2006 Vladimir Prus
|
||||
Copyright 2004-2007 Vladimir Prus
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
Milestone 12 (in development)
|
||||
Milestone 13 (in development)
|
||||
|
||||
Changes in this release:
|
||||
|
||||
The following bugs were fixed:
|
||||
|
||||
- gcc suport did not work on HP-UX systems
|
||||
|
||||
Milestone 12 (Oct 1, 2007)
|
||||
|
||||
Changes in this release:
|
||||
|
||||
- The Pathscale, PGI and mipspro compilers are now supported.
|
||||
- Support for autoconfiguration of toolset based on command-line
|
||||
toolset=xxxx or --toolset=xxxx options, and for default toolset
|
||||
toolset=xxxx request, and for default toolset
|
||||
configuration as a fallback.
|
||||
- Support for precompiled headers for gcc toolset,
|
||||
and improvements for msvc.
|
||||
@@ -22,21 +31,38 @@ Changes in this release:
|
||||
- Toolsets can now implicitly add requirements to
|
||||
all targets.
|
||||
- New 'generate' rule.
|
||||
- The executables produced by the 'run' rule are automatically
|
||||
removed after run.
|
||||
- The gcc toolset uses the version obtained by running
|
||||
the compiler, if no explicit one is provided.
|
||||
- The sun toolset now supports the 'address-model' feature,
|
||||
and uses -KPIC for shared libraries.
|
||||
- Free features on command line affect all targets, not
|
||||
just 'directly requested' ones.
|
||||
|
||||
|
||||
Documentation changes:
|
||||
|
||||
- Installation instructions for Linux distributors.
|
||||
- Configuration options for all supported C++ compilers
|
||||
are now documented.
|
||||
|
||||
The following bugs were fixed:
|
||||
|
||||
- The 'cflags' and 'linkflags' features not working for Darwin.
|
||||
- The intel toolset not working on Windows.
|
||||
- The 'cflags' and 'linkflags' now work on Darwin.o
|
||||
- The intel toolset now works on Windows.
|
||||
- Fix library search options for CodeWarriour toolset.
|
||||
- The <install-source-root> could cause duplicate
|
||||
mkdir commands.
|
||||
- Numerious fixes in Boost autolink support
|
||||
- Numerious fixes in Boost.Python support.
|
||||
- Indirect properties not evaluates in usage requirements.
|
||||
- Indirect properties not evaluated in usage requirements.
|
||||
- Generator that returns a property set but not target is
|
||||
considered successful.
|
||||
- On Darwin, when several compiler versions
|
||||
are configured, -fcoalesce-templates is applied only to
|
||||
versions that need it.
|
||||
|
||||
|
||||
Milestone 11 (Jule 20, 2006)
|
||||
|
||||
|
||||
@@ -14,18 +14,22 @@ Distributed under the Boost Software License, Version 1.0.
|
||||
Make sure that "bjam --version" output is correct. Update version string if
|
||||
needed. Update bjam version and the version check is necessary.
|
||||
Check the download locations in "index.html". Check that "last modified"
|
||||
strings in docs are correct.
|
||||
string in index.html is correct.
|
||||
|
||||
1. Make sure you don't have any local modification, and tag the CVS tree with
|
||||
Milestone_X tag. Be sure to tag both Boost.Build and Boost.Jam sources.
|
||||
1. Make sure you don't have any local modification, and create SVN directory
|
||||
|
||||
https://svn.boost.org/svn/boost/branches/build/Milestone_X
|
||||
|
||||
Then, copy:
|
||||
|
||||
https://svn.boost.org/svn/boost/trunk/tools/build
|
||||
https://svn.boost.org/svn/boost/trunk/tools/jam
|
||||
|
||||
to that directory.
|
||||
|
||||
2. Run
|
||||
|
||||
cvs -d :ext:<your_user_name>@boost.cvs.sourceforge.net:/cvsroot/boost co -r
|
||||
Milestone_X -P -d boost-build boost/tools
|
||||
|
||||
Note: it turns out that anonymous CVS access uses some backup server, which
|
||||
is not up-to-date.
|
||||
svn co https://svn.boost.org/svn/boost/branches/build/Milestone_X boost-build
|
||||
|
||||
3. Go to "boost-build/build/v2" directory.
|
||||
|
||||
|
||||
2
scripts/nightly.sh
Normal file → Executable file
2
scripts/nightly.sh
Normal file → Executable file
@@ -18,7 +18,7 @@ export LANG=C
|
||||
cd /tmp
|
||||
rm -rf boost-build
|
||||
echo "Checking out sources"
|
||||
cvs -d :ext:vladimir_prus@boost.cvs.sourceforge.net:/cvsroot/boost co -P -d boost-build boost/tools > /tmp/boost_build_checkout_log
|
||||
svn co http://svn.boost.org/svn/boost/trunk/tools boost-build > /tmp/boost_build_checkout_log
|
||||
mv /tmp/boost_build_checkout_log boost-build/checkout-log
|
||||
cd boost-build/build/v2
|
||||
echo "Building packages and uploading docs"
|
||||
|
||||
20
scripts/roll.sh
Normal file → Executable file
20
scripts/roll.sh
Normal file → Executable file
@@ -7,28 +7,33 @@
|
||||
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
set -e
|
||||
# Do some renames/rearrangments
|
||||
|
||||
# Do some renames/rearrangments
|
||||
cp -r ../v2 ../boost-build
|
||||
# Grab jam_src
|
||||
cp -r ../../jam/src ../boost-build/jam_src
|
||||
cd ../boost-build
|
||||
|
||||
# Capture the version
|
||||
revision=`svnversion ..`
|
||||
echo "SVN Revision $revision" >> timestamp.txt
|
||||
date >> timestamp.txt
|
||||
|
||||
# This one is not fully finished
|
||||
rm -rf example/versioned
|
||||
|
||||
# Remove unnecessary top-level files
|
||||
find . -maxdepth 1 -type f | egrep -v "roll.sh|bootstrap.jam|build-system.jam|boost_build_v2.html|boost.png|index.html|hacking.txt|site-config.jam|user-config.jam" | xargs rm -f
|
||||
find . -maxdepth 1 -type f | egrep -v "timestamp.txt|roll.sh|bootstrap.jam|build-system.jam|boost_build_v2.html|boost_build.png|index.html|hacking.txt|site-config.jam|user-config.jam" | xargs rm -f
|
||||
|
||||
# Prepare some more files.
|
||||
echo -e "boost-build kernel ;\n" > boost-build.jam
|
||||
|
||||
# Build the documentation
|
||||
touch doc/project-root.jam
|
||||
export BOOST_BUILD_PATH=/home/ghost/Work/boost-rc/tools/build/v2
|
||||
export BOOST_BUILD_PATH=`pwd`
|
||||
cd doc
|
||||
/home/ghost/Work/boost-rc/tools/jam/src/bin.linuxx86/bjam --v2
|
||||
/home/ghost/Work/boost-rc/tools/jam/src/bin.linuxx86/bjam --v2 pdf
|
||||
/home/ghost/Work/Boost/boost-svn/tools/jam/src/bin.linuxx86/bjam --v2
|
||||
/home/ghost/Work/Boost/boost-svn/tools/jam/src/bin.linuxx86/bjam --v2 pdf
|
||||
cp `find bin -name "*.pdf"` ../..
|
||||
mv ../../standalone.pdf ../../userman.pdf
|
||||
rm -rf bin
|
||||
@@ -43,15 +48,14 @@ perl -pi -e 's%../../../doc/html/bbv2.html%doc/html/index.html%' index.html
|
||||
perl -pi -e 's%../../../doc/html/bbv2.installation.html%doc/html/bbv2.installation.html%' index.html
|
||||
|
||||
# Make packages
|
||||
find . -name CVS | xargs rm -rf
|
||||
find . -name ".svn" | xargs rm -rf
|
||||
rm roll.sh
|
||||
chmod a+x jam_src/build.bat
|
||||
date >> timestamp.txt
|
||||
cd .. && zip -r boost-build.zip boost-build && tar --bzip2 -cf boost-build.tar.bz2 boost-build
|
||||
cd boost-build
|
||||
|
||||
chmod -R u+w *
|
||||
# Upload docs to sourceforge
|
||||
perl -pi -e 's%<!-- sf logo -->%<a href="http://sourceforge.net"><img src="http://sourceforge.net/sflogo.php?group_id=7586&type=1" width="88" height="31" border="0" alt="SourceForge.net Logo" align="right"/></a>%' index.html doc/*.html
|
||||
scp -r doc example *.html hacking.txt vladimir_prus@shell.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2
|
||||
scp -r doc example boost_build.png *.html hacking.txt vladimir_prus@shell.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2
|
||||
scp ../userman.pdf vladimir_prus@shell.sourceforge.net:/home/groups/b/bo/boost/htdocs/boost-build2/doc
|
||||
|
||||
@@ -41,6 +41,15 @@ rule location ( )
|
||||
return $(r:P) ;
|
||||
}
|
||||
|
||||
# Returns the property set with the
|
||||
# free features from the currently processed
|
||||
# build request.
|
||||
rule command-line-free-features ( )
|
||||
{
|
||||
return $(.command-line-free-features) ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
# Check if we can load 'test-config.jam'. If we can, load it and
|
||||
# ignore user configs.
|
||||
@@ -126,6 +135,8 @@ module user-config
|
||||
|
||||
local user-config-path = [ MATCH ^--user-config=(.*) : $(argv) ] ;
|
||||
|
||||
user-config-path ?= [ os.environ BOOST_BUILD_USER_CONFIG ] ;
|
||||
|
||||
if $(user-config-path)
|
||||
{
|
||||
if $(debug-config)
|
||||
@@ -397,6 +408,7 @@ local results-of-main-targets ;
|
||||
|
||||
for local p in $(expanded)
|
||||
{
|
||||
.command-line-free-features = [ property-set.create [ $(p).free ] ] ;
|
||||
for local t in $(targets)
|
||||
{
|
||||
local g = [ $(t).generate $(p) ] ;
|
||||
|
||||
@@ -647,7 +647,10 @@ rule get-values ( feature : properties * )
|
||||
{
|
||||
if $(p:G) = $(feature)
|
||||
{
|
||||
result += $(p:G=) ;
|
||||
#~ Use MATCH instead if :G= to get the value, in order to preserve
|
||||
#~ the value intact instead of having bjam treat it as a decompossible
|
||||
#~ path.
|
||||
result += [ MATCH ">(.*)" : $(p) ] ;
|
||||
}
|
||||
}
|
||||
return $(result) ;
|
||||
|
||||
@@ -14,7 +14,7 @@ import feature ;
|
||||
import errors ;
|
||||
import type ;
|
||||
import "class" : new ;
|
||||
import generators : generator ;
|
||||
import generators ;
|
||||
import property ;
|
||||
import virtual-target ;
|
||||
import numbers ;
|
||||
@@ -25,17 +25,23 @@ import property-set ;
|
||||
# Base generator for creating targets that are modifications of existing
|
||||
# targets.
|
||||
#
|
||||
rule modifier (
|
||||
id
|
||||
composing ?
|
||||
: source-types *
|
||||
: target-types-and-names +
|
||||
: requirements *
|
||||
)
|
||||
class modifier : generator
|
||||
{
|
||||
generator.__init__ $(id) $(composing) : $(source-types) : $(target-types-and-names) : $(requirements) ;
|
||||
rule __init__ (
|
||||
id
|
||||
composing ?
|
||||
: source-types *
|
||||
: target-types-and-names +
|
||||
: requirements *
|
||||
)
|
||||
{
|
||||
generator.__init__ $(id) $(composing)
|
||||
: $(source-types)
|
||||
: $(target-types-and-names)
|
||||
: $(requirements) ;
|
||||
|
||||
self.targets-in-progress = ;
|
||||
self.targets-in-progress = ;
|
||||
}
|
||||
|
||||
# Wraps the generation of the target to call before and after rules to
|
||||
# affect the real target.
|
||||
@@ -47,16 +53,21 @@ rule modifier (
|
||||
if ! $(current-target) in $(self.targets-in-progress)
|
||||
{
|
||||
# Before modifications...
|
||||
local project_ = [ modify-project-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local name_ = [ modify-name-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local property-set_ = [ modify-properties-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local sources_ = [ modify-sources-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local multiple_ = [ modify-multiple-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local project_ =
|
||||
[ modify-project-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local name_ =
|
||||
[ modify-name-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local property-set_ =
|
||||
[ modify-properties-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local sources_ =
|
||||
[ modify-sources-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
local multiple_ =
|
||||
[ modify-multiple-before
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
project = $(project_) ;
|
||||
name = $(name_) ;
|
||||
property-set = $(property-set_) ;
|
||||
@@ -64,16 +75,23 @@ rule modifier (
|
||||
multiple = $(multiple_) ;
|
||||
|
||||
# Generate the real target...
|
||||
local target-type-p = [ property.select <main-target-type> : [ $(property-set).raw ] ] ;
|
||||
local target-type-p =
|
||||
[ property.select <main-target-type> : [ $(property-set).raw ] ] ;
|
||||
self.targets-in-progress += $(current-target) ;
|
||||
result =
|
||||
[ generators.construct $(project) $(name) : $(target-type-p:G=) $(multiple) :
|
||||
$(property-set) : $(sources) ] ;
|
||||
[ generators.construct $(project) $(name)
|
||||
: $(target-type-p:G=) $(multiple)
|
||||
: $(property-set)
|
||||
: $(sources) ] ;
|
||||
self.targets-in-progress = $(self.targets-in-progress[1--2]) ;
|
||||
|
||||
# After modifications...
|
||||
result = [ modify-target-after $(result) :
|
||||
$(project) $(name) : $(property-set) : $(sources) : $(multiple) ] ;
|
||||
result =
|
||||
[ modify-target-after $(result)
|
||||
: $(project) $(name)
|
||||
: $(property-set)
|
||||
: $(sources)
|
||||
: $(multiple) ] ;
|
||||
}
|
||||
return $(result) ;
|
||||
}
|
||||
@@ -135,17 +153,19 @@ rule modifier (
|
||||
return $(result) ;
|
||||
}
|
||||
}
|
||||
class modifier : generator ;
|
||||
|
||||
# A modifier that changes the name of a target, after it's generated, given
|
||||
# a regular expression to slpit the name, and a set of token to insert
|
||||
# between the split tokens of the name. This also exposes the target for other
|
||||
# uses with a symlink to the original name (optionally).
|
||||
#
|
||||
rule name-modifier ( )
|
||||
class name-modifier : modifier
|
||||
{
|
||||
# Apply ourselves to EXE targets, for now.
|
||||
modifier.__init__ name.modifier : : EXE LIB : <name-modify>yes ;
|
||||
rule __init__ ( )
|
||||
{
|
||||
# Apply ourselves to EXE targets, for now.
|
||||
modifier.__init__ name.modifier : : EXE LIB : <name-modify>yes ;
|
||||
}
|
||||
|
||||
# Modifies the name, by cloning the target with the new name.
|
||||
#
|
||||
@@ -203,7 +223,6 @@ rule name-modifier ( )
|
||||
return <name-modify>yes ;
|
||||
}
|
||||
}
|
||||
class name-modifier : modifier ;
|
||||
feature.feature name-modifier : : free ;
|
||||
feature.feature name-modify : no yes : incidental optional ;
|
||||
generators.register [ new name-modifier ] ;
|
||||
|
||||
@@ -726,7 +726,7 @@ rule use ( id : location )
|
||||
&& $($(id).jamfile-module) != $(project-module)
|
||||
{
|
||||
errors.user-error
|
||||
"Attempt to redeclare already existing project id" ;
|
||||
"Attempt to redeclare already existing project id '$(id)'" ;
|
||||
}
|
||||
$(id).jamfile-module = $(project-module) ;
|
||||
}
|
||||
@@ -882,7 +882,12 @@ module project-rules
|
||||
|
||||
if $(global-build-dir)
|
||||
{
|
||||
if [ $(attributes).get location ] = [ $(attributes).get project-root ]
|
||||
local location = [ $(attributes).get location ] ;
|
||||
# Project with empty location is 'standalone' project, like
|
||||
# user-config, or qt. It has no build dir.
|
||||
# If we try to set build dir for user-config, we'll then
|
||||
# try to inherit it, with either weird, or wrong consequences.
|
||||
if $(location) && $(location) = [ $(attributes).get project-root ]
|
||||
{
|
||||
# This is Jamroot.
|
||||
if $(id)
|
||||
|
||||
@@ -455,19 +455,29 @@ rule translate-indirect ( specification * : context-module )
|
||||
local m = [ MATCH ^@(.+) : $(p:G=) ] ;
|
||||
if $(m)
|
||||
{
|
||||
if ! [ MATCH ".*([.]).*" : $(m) ]
|
||||
local v ;
|
||||
if [ MATCH "^([^%]*)%([^%]+)$" : $(m) ]
|
||||
{
|
||||
# This is unqualified rule name. The user might want
|
||||
# to set flags on this rule name, and toolset.flag
|
||||
# auto-qualifies the rule name. Need to do the same
|
||||
# here so set flag setting work.
|
||||
# We can arrange for toolset.flag to *not* auto-qualify
|
||||
# the argument, but then two rules defined in two Jamfiles
|
||||
# will conflict.
|
||||
m = $(context-module).$(m) ;
|
||||
# Rule is already in indirect format
|
||||
v = $(m) ;
|
||||
}
|
||||
|
||||
local v = [ indirect.make $(m) : $(context-module) ] ;
|
||||
else
|
||||
{
|
||||
if ! [ MATCH ".*([.]).*" : $(m) ]
|
||||
{
|
||||
# This is unqualified rule name. The user might want
|
||||
# to set flags on this rule name, and toolset.flag
|
||||
# auto-qualifies the rule name. Need to do the same
|
||||
# here so set flag setting work.
|
||||
# We can arrange for toolset.flag to *not* auto-qualify
|
||||
# the argument, but then two rules defined in two Jamfiles
|
||||
# will conflict.
|
||||
m = $(context-module).$(m) ;
|
||||
}
|
||||
|
||||
v = [ indirect.make $(m) : $(context-module) ] ;
|
||||
}
|
||||
|
||||
v = @$(v) ;
|
||||
result += $(v:G=$(p:G)) ;
|
||||
}
|
||||
|
||||
@@ -506,21 +506,7 @@ class project-target : abstract-target
|
||||
[ RULENAMES project-rules ] ] ;
|
||||
IMPORT $(parent-module) : $(user-rules) : $(this-module) : $(user-rules) ;
|
||||
EXPORT $(this-module) : $(user-rules) ;
|
||||
}
|
||||
|
||||
|
||||
# Intern the constants from this project into the specified module.
|
||||
#
|
||||
rule intern-constants (
|
||||
target-module # The module to intern into.
|
||||
)
|
||||
{
|
||||
for local c in $(self.constants)
|
||||
{
|
||||
modules.poke $(target-module) : $(c) : $(self.constant.$(c)) ;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -835,13 +821,6 @@ class file-reference : abstract-target
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if "--quiet" in [ modules.peek : ARGV ]
|
||||
{
|
||||
.quiet = true ;
|
||||
}
|
||||
|
||||
|
||||
# Given a target-reference, made in context of 'project',
|
||||
# returns the abstract-target instance that is referred to, as well
|
||||
# as properties explicitly specified for this reference.
|
||||
@@ -1057,6 +1036,7 @@ class basic-target : abstract-target
|
||||
import set sequence errors ;
|
||||
import "class" : new ;
|
||||
import property feature ;
|
||||
import build-system ;
|
||||
|
||||
rule __init__ ( name : project
|
||||
: sources * : requirements * :
|
||||
@@ -1185,12 +1165,21 @@ class basic-target : abstract-target
|
||||
local fn = [ full-name ] ;
|
||||
ECHO [ targets.indent ] "Building target '$(fn)'" ;
|
||||
targets.increase-indent ;
|
||||
ECHO [ targets.indent ] "Build request: " [ $(property-set).raw ] ;
|
||||
ECHO [ targets.indent ] "Build request: " [ $(property-set).raw ] ;
|
||||
local cf = [ build-system.command-line-free-features ] ;
|
||||
ECHO [ targets.indent ] "Command line free features: "
|
||||
[ $(cf).raw ] ;
|
||||
ECHO [ targets.indent ] "Target requirements: " [ $(self.requirements).raw ] ;
|
||||
}
|
||||
|
||||
if ! $(self.generated.$(property-set))
|
||||
{
|
||||
# Apply free features form the command line. If user
|
||||
# said
|
||||
# define=FOO
|
||||
# he most likely want this define to be set for all compiles.
|
||||
property-set = [ $(property-set).refine
|
||||
[ build-system.command-line-free-features ] ] ;
|
||||
local rproperties = [ targets.common-properties $(property-set)
|
||||
$(self.requirements) ] ;
|
||||
|
||||
@@ -1268,6 +1257,21 @@ class basic-target : abstract-target
|
||||
}
|
||||
else
|
||||
{
|
||||
if $(rproperties[1]) = "@error"
|
||||
{
|
||||
ECHO [ targets.indent ]
|
||||
"Skipping build of: " [ full-name ] " cannot compute common properties" ;
|
||||
}
|
||||
else if [ $(rproperties).get <build> ] = no
|
||||
{
|
||||
ECHO [ targets.indent ]
|
||||
"Skipping build of: " [ full-name ] " <build>no in common properties" ;
|
||||
}
|
||||
else
|
||||
{
|
||||
ECHO [ targets.indent ] "Skipping build of: " [ full-name ] " unknown reason" ;
|
||||
}
|
||||
|
||||
# We're here either because there's error computing
|
||||
# properties, or there's <build>no in properties.
|
||||
# In the latter case we don't want any diagnostic.
|
||||
|
||||
@@ -18,6 +18,15 @@ import sequence ;
|
||||
|
||||
.flag-no = 1 ;
|
||||
|
||||
.ignore-requirements = ;
|
||||
|
||||
# This is used only for testing, to make sure
|
||||
# we don't get random extra elements in paths.
|
||||
if --ignore-toolset-requirements in [ modules.peek : ARGV ]
|
||||
{
|
||||
.ignore-requirements = 1 ;
|
||||
}
|
||||
|
||||
# Initializes an additional toolset-like module.
|
||||
# First load 'toolset-module' and then calls its 'init'
|
||||
# rule with trailing arguments
|
||||
@@ -351,15 +360,6 @@ rule set-target-variables ( rule-or-module targets + : property-set )
|
||||
}
|
||||
}
|
||||
|
||||
.toolsets += $(toolset) ;
|
||||
|
||||
# Registers a new toolset
|
||||
rule register ( toolset )
|
||||
{
|
||||
feature.extend toolset : $(toolset) ;
|
||||
.toolsets += $(toolset) ;
|
||||
}
|
||||
|
||||
# Make toolset 'toolset', defined in a module of the same name,
|
||||
# inherit from 'base'
|
||||
# 1. The 'init' rule from 'base' is imported into 'toolset' with full
|
||||
@@ -480,7 +480,10 @@ rule requirements ( )
|
||||
# indirect conditional.
|
||||
rule add-requirements ( requirements * )
|
||||
{
|
||||
.requirements += $(requirements) ;
|
||||
if ! $(.ignore-requirements)
|
||||
{
|
||||
.requirements += $(requirements) ;
|
||||
}
|
||||
}
|
||||
|
||||
local rule __test__ ( )
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
rule boost-build ( )
|
||||
{
|
||||
return "V2 (Milestone 11)" ;
|
||||
return "V2 (Milestone 12)" ;
|
||||
}
|
||||
rule jam ( )
|
||||
{
|
||||
|
||||
@@ -79,7 +79,7 @@ rule boost-build ( dir ? )
|
||||
# Add the given directory to the path so we can find the build
|
||||
# system. If dir is empty, has no effect.
|
||||
#
|
||||
BOOST_BUILD_PATH = $(BOOST_BUILD_PATH) $(dir:R=$(.boost-build-file:D)) ;
|
||||
BOOST_BUILD_PATH = $(dir:R=$(.boost-build-file:D)) $(BOOST_BUILD_PATH) ;
|
||||
|
||||
# We might have just modified the *global* value of BOOST_BUILD_PATH.
|
||||
# The code that loads the rest of Boost.Build, in particular the
|
||||
|
||||
623
src/engine/boehm_gc/AmigaOS.c
Normal file
623
src/engine/boehm_gc/AmigaOS.c
Normal file
@@ -0,0 +1,623 @@
|
||||
|
||||
|
||||
/******************************************************************
|
||||
|
||||
AmigaOS-spesific routines for GC.
|
||||
This file is normally included from os_dep.c
|
||||
|
||||
******************************************************************/
|
||||
|
||||
|
||||
#if !defined(GC_AMIGA_DEF) && !defined(GC_AMIGA_SB) && !defined(GC_AMIGA_DS) && !defined(GC_AMIGA_AM)
|
||||
# include "gc_priv.h"
|
||||
# include <stdio.h>
|
||||
# include <signal.h>
|
||||
# define GC_AMIGA_DEF
|
||||
# define GC_AMIGA_SB
|
||||
# define GC_AMIGA_DS
|
||||
# define GC_AMIGA_AM
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef GC_AMIGA_DEF
|
||||
|
||||
# ifndef __GNUC__
|
||||
# include <exec/exec.h>
|
||||
# endif
|
||||
# include <proto/exec.h>
|
||||
# include <proto/dos.h>
|
||||
# include <dos/dosextens.h>
|
||||
# include <workbench/startup.h>
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef GC_AMIGA_SB
|
||||
|
||||
/******************************************************************
|
||||
Find the base of the stack.
|
||||
******************************************************************/
|
||||
|
||||
ptr_t GC_get_main_stack_base()
|
||||
{
|
||||
struct Process *proc = (struct Process*)SysBase->ThisTask;
|
||||
|
||||
/* Reference: Amiga Guru Book Pages: 42,567,574 */
|
||||
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS
|
||||
&& proc->pr_CLI != NULL) {
|
||||
/* first ULONG is StackSize */
|
||||
/*longPtr = proc->pr_ReturnAddr;
|
||||
size = longPtr[0];*/
|
||||
|
||||
return (char *)proc->pr_ReturnAddr + sizeof(ULONG);
|
||||
} else {
|
||||
return (char *)proc->pr_Task.tc_SPUpper;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0 /* old version */
|
||||
ptr_t GC_get_stack_base()
|
||||
{
|
||||
extern struct WBStartup *_WBenchMsg;
|
||||
extern long __base;
|
||||
extern long __stack;
|
||||
struct Task *task;
|
||||
struct Process *proc;
|
||||
struct CommandLineInterface *cli;
|
||||
long size;
|
||||
|
||||
if ((task = FindTask(0)) == 0) {
|
||||
GC_err_puts("Cannot find own task structure\n");
|
||||
ABORT("task missing");
|
||||
}
|
||||
proc = (struct Process *)task;
|
||||
cli = BADDR(proc->pr_CLI);
|
||||
|
||||
if (_WBenchMsg != 0 || cli == 0) {
|
||||
size = (char *)task->tc_SPUpper - (char *)task->tc_SPLower;
|
||||
} else {
|
||||
size = cli->cli_DefaultStack * 4;
|
||||
}
|
||||
return (ptr_t)(__base + GC_max(size, __stack));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef GC_AMIGA_DS
|
||||
/******************************************************************
|
||||
Register data segments.
|
||||
******************************************************************/
|
||||
|
||||
void GC_register_data_segments()
|
||||
{
|
||||
struct Process *proc;
|
||||
struct CommandLineInterface *cli;
|
||||
BPTR myseglist;
|
||||
ULONG *data;
|
||||
|
||||
int num;
|
||||
|
||||
|
||||
# ifdef __GNUC__
|
||||
ULONG dataSegSize;
|
||||
GC_bool found_segment = FALSE;
|
||||
extern char __data_size[];
|
||||
|
||||
dataSegSize=__data_size+8;
|
||||
/* Can`t find the Location of __data_size, because
|
||||
it`s possible that is it, inside the segment. */
|
||||
|
||||
# endif
|
||||
|
||||
proc= (struct Process*)SysBase->ThisTask;
|
||||
|
||||
/* Reference: Amiga Guru Book Pages: 538ff,565,573
|
||||
and XOper.asm */
|
||||
if (proc->pr_Task.tc_Node.ln_Type==NT_PROCESS) {
|
||||
if (proc->pr_CLI == NULL) {
|
||||
myseglist = proc->pr_SegList;
|
||||
} else {
|
||||
/* ProcLoaded 'Loaded as a command: '*/
|
||||
cli = BADDR(proc->pr_CLI);
|
||||
myseglist = cli->cli_Module;
|
||||
}
|
||||
} else {
|
||||
ABORT("Not a Process.");
|
||||
}
|
||||
|
||||
if (myseglist == NULL) {
|
||||
ABORT("Arrrgh.. can't find segments, aborting");
|
||||
}
|
||||
|
||||
/* xoper hunks Shell Process */
|
||||
|
||||
num=0;
|
||||
for (data = (ULONG *)BADDR(myseglist); data != NULL;
|
||||
data = (ULONG *)BADDR(data[0])) {
|
||||
if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
|
||||
((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
|
||||
# ifdef __GNUC__
|
||||
if (dataSegSize == data[-1]) {
|
||||
found_segment = TRUE;
|
||||
}
|
||||
# endif
|
||||
GC_add_roots_inner((char *)&data[1],
|
||||
((char *)&data[1]) + data[-1], FALSE);
|
||||
}
|
||||
++num;
|
||||
} /* for */
|
||||
# ifdef __GNUC__
|
||||
if (!found_segment) {
|
||||
ABORT("Can`t find correct Segments.\nSolution: Use an newer version of ixemul.library");
|
||||
}
|
||||
# endif
|
||||
}
|
||||
|
||||
#if 0 /* old version */
|
||||
void GC_register_data_segments()
|
||||
{
|
||||
extern struct WBStartup *_WBenchMsg;
|
||||
struct Process *proc;
|
||||
struct CommandLineInterface *cli;
|
||||
BPTR myseglist;
|
||||
ULONG *data;
|
||||
|
||||
if ( _WBenchMsg != 0 ) {
|
||||
if ((myseglist = _WBenchMsg->sm_Segment) == 0) {
|
||||
GC_err_puts("No seglist from workbench\n");
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
if ((proc = (struct Process *)FindTask(0)) == 0) {
|
||||
GC_err_puts("Cannot find process structure\n");
|
||||
return;
|
||||
}
|
||||
if ((cli = BADDR(proc->pr_CLI)) == 0) {
|
||||
GC_err_puts("No CLI\n");
|
||||
return;
|
||||
}
|
||||
if ((myseglist = cli->cli_Module) == 0) {
|
||||
GC_err_puts("No seglist from CLI\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
for (data = (ULONG *)BADDR(myseglist); data != 0;
|
||||
data = (ULONG *)BADDR(data[0])) {
|
||||
# ifdef AMIGA_SKIP_SEG
|
||||
if (((ULONG) GC_register_data_segments < (ULONG) &data[1]) ||
|
||||
((ULONG) GC_register_data_segments > (ULONG) &data[1] + data[-1])) {
|
||||
# else
|
||||
{
|
||||
# endif /* AMIGA_SKIP_SEG */
|
||||
GC_add_roots_inner((char *)&data[1],
|
||||
((char *)&data[1]) + data[-1], FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* old version */
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#ifdef GC_AMIGA_AM
|
||||
|
||||
#ifndef GC_AMIGA_FASTALLOC
|
||||
|
||||
void *GC_amiga_allocwrapper(size_t size,void *(*AllocFunction)(size_t size2)){
|
||||
return (*AllocFunction)(size);
|
||||
}
|
||||
|
||||
void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
|
||||
=GC_amiga_allocwrapper;
|
||||
|
||||
#else
|
||||
|
||||
|
||||
|
||||
|
||||
void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2));
|
||||
|
||||
void *(*GC_amiga_allocwrapper_do)(size_t size,void *(*AllocFunction)(size_t size2))
|
||||
=GC_amiga_allocwrapper_firsttime;
|
||||
|
||||
|
||||
/******************************************************************
|
||||
Amiga-spesific routines to obtain memory, and force GC to give
|
||||
back fast-mem whenever possible.
|
||||
These hacks makes gc-programs go many times faster when
|
||||
the amiga is low on memory, and are therefore strictly necesarry.
|
||||
|
||||
-Kjetil S. Matheussen, 2000.
|
||||
******************************************************************/
|
||||
|
||||
|
||||
|
||||
/* List-header for all allocated memory. */
|
||||
|
||||
struct GC_Amiga_AllocedMemoryHeader{
|
||||
ULONG size;
|
||||
struct GC_Amiga_AllocedMemoryHeader *next;
|
||||
};
|
||||
struct GC_Amiga_AllocedMemoryHeader *GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(int)~(NULL);
|
||||
|
||||
|
||||
|
||||
/* Type of memory. Once in the execution of a program, this might change to MEMF_ANY|MEMF_CLEAR */
|
||||
|
||||
ULONG GC_AMIGA_MEMF = MEMF_FAST | MEMF_CLEAR;
|
||||
|
||||
|
||||
/* Prevents GC_amiga_get_mem from allocating memory if this one is TRUE. */
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
BOOL GC_amiga_dontalloc=FALSE;
|
||||
#endif
|
||||
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
int succ=0,succ2=0;
|
||||
int nsucc=0,nsucc2=0;
|
||||
int nullretries=0;
|
||||
int numcollects=0;
|
||||
int chipa=0;
|
||||
int allochip=0;
|
||||
int allocfast=0;
|
||||
int cur0=0;
|
||||
int cur1=0;
|
||||
int cur10=0;
|
||||
int cur50=0;
|
||||
int cur150=0;
|
||||
int cur151=0;
|
||||
int ncur0=0;
|
||||
int ncur1=0;
|
||||
int ncur10=0;
|
||||
int ncur50=0;
|
||||
int ncur150=0;
|
||||
int ncur151=0;
|
||||
#endif
|
||||
|
||||
/* Free everything at program-end. */
|
||||
|
||||
void GC_amiga_free_all_mem(void){
|
||||
struct GC_Amiga_AllocedMemoryHeader *gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(GC_AMIGAMEM));
|
||||
struct GC_Amiga_AllocedMemoryHeader *temp;
|
||||
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
printf("\n\n"
|
||||
"%d bytes of chip-mem, and %d bytes of fast-mem where allocated from the OS.\n",
|
||||
allochip,allocfast
|
||||
);
|
||||
printf(
|
||||
"%d bytes of chip-mem were returned from the GC_AMIGA_FASTALLOC supported allocating functions.\n",
|
||||
chipa
|
||||
);
|
||||
printf("\n");
|
||||
printf("GC_gcollect was called %d times to avoid returning NULL or start allocating with the MEMF_ANY flag.\n",numcollects);
|
||||
printf("%d of them was a success. (the others had to use allocation from the OS.)\n",nullretries);
|
||||
printf("\n");
|
||||
printf("Succeded forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",succ,succ2);
|
||||
printf("Failed forcing %d gc-allocations (%d bytes) of chip-mem to be fast-mem.\n",nsucc,nsucc2);
|
||||
printf("\n");
|
||||
printf(
|
||||
"Number of retries before succeding a chip->fast force:\n"
|
||||
"0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
|
||||
cur0,cur1,cur10,cur50,cur150,cur151
|
||||
);
|
||||
printf(
|
||||
"Number of retries before giving up a chip->fast force:\n"
|
||||
"0: %d, 1: %d, 2-9: %d, 10-49: %d, 50-149: %d, >150: %d\n",
|
||||
ncur0,ncur1,ncur10,ncur50,ncur150,ncur151
|
||||
);
|
||||
#endif
|
||||
|
||||
while(gc_am!=NULL){
|
||||
temp=gc_am->next;
|
||||
FreeMem(gc_am,gc_am->size);
|
||||
gc_am=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(temp));
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
|
||||
/* All memory with address lower than this one is chip-mem. */
|
||||
|
||||
char *chipmax;
|
||||
|
||||
|
||||
/*
|
||||
* Allways set to the last size of memory tried to be allocated.
|
||||
* Needed to ensure allocation when the size is bigger than 100000.
|
||||
*
|
||||
*/
|
||||
size_t latestsize;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* The actual function that is called with the GET_MEM macro.
|
||||
*
|
||||
*/
|
||||
|
||||
void *GC_amiga_get_mem(size_t size){
|
||||
struct GC_Amiga_AllocedMemoryHeader *gc_am;
|
||||
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
if(GC_amiga_dontalloc==TRUE){
|
||||
// printf("rejected, size: %d, latestsize: %d\n",size,latestsize);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// We really don't want to use chip-mem, but if we must, then as little as possible.
|
||||
if(GC_AMIGA_MEMF==(MEMF_ANY|MEMF_CLEAR) && size>100000 && latestsize<50000) return NULL;
|
||||
#endif
|
||||
|
||||
gc_am=AllocMem((ULONG)(size + sizeof(struct GC_Amiga_AllocedMemoryHeader)),GC_AMIGA_MEMF);
|
||||
if(gc_am==NULL) return NULL;
|
||||
|
||||
gc_am->next=GC_AMIGAMEM;
|
||||
gc_am->size=size + sizeof(struct GC_Amiga_AllocedMemoryHeader);
|
||||
GC_AMIGAMEM=(struct GC_Amiga_AllocedMemoryHeader *)(~(int)(gc_am));
|
||||
|
||||
// printf("Allocated %d (%d) bytes at address: %x. Latest: %d\n",size,tot,gc_am,latestsize);
|
||||
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
if((char *)gc_am<chipmax){
|
||||
allochip+=size;
|
||||
}else{
|
||||
allocfast+=size;
|
||||
}
|
||||
#endif
|
||||
|
||||
return gc_am+1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
|
||||
/* Tries very hard to force GC to find fast-mem to return. Done recursively
|
||||
* to hold the rejected memory-pointers reachable from the collector in an
|
||||
* easy way.
|
||||
*
|
||||
*/
|
||||
#ifdef GC_AMIGA_RETRY
|
||||
void *GC_amiga_rec_alloc(size_t size,void *(*AllocFunction)(size_t size2),const int rec){
|
||||
void *ret;
|
||||
|
||||
ret=(*AllocFunction)(size);
|
||||
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
if((char *)ret>chipmax || ret==NULL){
|
||||
if(ret==NULL){
|
||||
nsucc++;
|
||||
nsucc2+=size;
|
||||
if(rec==0) ncur0++;
|
||||
if(rec==1) ncur1++;
|
||||
if(rec>1 && rec<10) ncur10++;
|
||||
if(rec>=10 && rec<50) ncur50++;
|
||||
if(rec>=50 && rec<150) ncur150++;
|
||||
if(rec>=150) ncur151++;
|
||||
}else{
|
||||
succ++;
|
||||
succ2+=size;
|
||||
if(rec==0) cur0++;
|
||||
if(rec==1) cur1++;
|
||||
if(rec>1 && rec<10) cur10++;
|
||||
if(rec>=10 && rec<50) cur50++;
|
||||
if(rec>=50 && rec<150) cur150++;
|
||||
if(rec>=150) cur151++;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (((char *)ret)<=chipmax && ret!=NULL && (rec<(size>500000?9:size/5000))){
|
||||
ret=GC_amiga_rec_alloc(size,AllocFunction,rec+1);
|
||||
// GC_free(ret2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/* The allocating-functions defined inside the amiga-blocks in gc.h is called
|
||||
* via these functions.
|
||||
*/
|
||||
|
||||
|
||||
void *GC_amiga_allocwrapper_any(size_t size,void *(*AllocFunction)(size_t size2)){
|
||||
void *ret,*ret2;
|
||||
|
||||
GC_amiga_dontalloc=TRUE; // Pretty tough thing to do, but its indeed necesarry.
|
||||
latestsize=size;
|
||||
|
||||
ret=(*AllocFunction)(size);
|
||||
|
||||
if(((char *)ret) <= chipmax){
|
||||
if(ret==NULL){
|
||||
//Give GC access to allocate memory.
|
||||
#ifdef GC_AMIGA_GC
|
||||
if(!GC_dont_gc){
|
||||
GC_gcollect();
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
numcollects++;
|
||||
#endif
|
||||
ret=(*AllocFunction)(size);
|
||||
}
|
||||
#endif
|
||||
if(ret==NULL){
|
||||
GC_amiga_dontalloc=FALSE;
|
||||
ret=(*AllocFunction)(size);
|
||||
if(ret==NULL){
|
||||
WARN("Out of Memory! Returning NIL!\n", 0);
|
||||
}
|
||||
}
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
else{
|
||||
nullretries++;
|
||||
}
|
||||
if(ret!=NULL && (char *)ret<=chipmax) chipa+=size;
|
||||
#endif
|
||||
}
|
||||
#ifdef GC_AMIGA_RETRY
|
||||
else{
|
||||
/* We got chip-mem. Better try again and again and again etc., we might get fast-mem sooner or later... */
|
||||
/* Using gctest to check the effectiviness of doing this, does seldom give a very good result. */
|
||||
/* However, real programs doesn't normally rapidly allocate and deallocate. */
|
||||
// printf("trying to force... %d bytes... ",size);
|
||||
if(
|
||||
AllocFunction!=GC_malloc_uncollectable
|
||||
#ifdef ATOMIC_UNCOLLECTABLE
|
||||
&& AllocFunction!=GC_malloc_atomic_uncollectable
|
||||
#endif
|
||||
){
|
||||
ret2=GC_amiga_rec_alloc(size,AllocFunction,0);
|
||||
}else{
|
||||
ret2=(*AllocFunction)(size);
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
if((char *)ret2<chipmax || ret2==NULL){
|
||||
nsucc++;
|
||||
nsucc2+=size;
|
||||
ncur0++;
|
||||
}else{
|
||||
succ++;
|
||||
succ2+=size;
|
||||
cur0++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(((char *)ret2)>chipmax){
|
||||
// printf("Succeeded.\n");
|
||||
GC_free(ret);
|
||||
ret=ret2;
|
||||
}else{
|
||||
GC_free(ret2);
|
||||
// printf("But did not succeed.\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
GC_amiga_dontalloc=FALSE;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void (*GC_amiga_toany)(void)=NULL;
|
||||
|
||||
void GC_amiga_set_toany(void (*func)(void)){
|
||||
GC_amiga_toany=func;
|
||||
}
|
||||
|
||||
#endif // !GC_AMIGA_ONLYFAST
|
||||
|
||||
|
||||
void *GC_amiga_allocwrapper_fast(size_t size,void *(*AllocFunction)(size_t size2)){
|
||||
void *ret;
|
||||
|
||||
ret=(*AllocFunction)(size);
|
||||
|
||||
if(ret==NULL){
|
||||
// Enable chip-mem allocation.
|
||||
// printf("ret==NULL\n");
|
||||
#ifdef GC_AMIGA_GC
|
||||
if(!GC_dont_gc){
|
||||
GC_gcollect();
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
numcollects++;
|
||||
#endif
|
||||
ret=(*AllocFunction)(size);
|
||||
}
|
||||
#endif
|
||||
if(ret==NULL){
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
|
||||
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
|
||||
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
|
||||
return GC_amiga_allocwrapper_any(size,AllocFunction);
|
||||
#endif
|
||||
}
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
else{
|
||||
nullretries++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *GC_amiga_allocwrapper_firsttime(size_t size,void *(*AllocFunction)(size_t size2)){
|
||||
atexit(&GC_amiga_free_all_mem);
|
||||
chipmax=(char *)SysBase->MaxLocMem; // For people still having SysBase in chip-mem, this might speed up a bit.
|
||||
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_fast;
|
||||
return GC_amiga_allocwrapper_fast(size,AllocFunction);
|
||||
}
|
||||
|
||||
|
||||
#endif //GC_AMIGA_FASTALLOC
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* The wrapped realloc function.
|
||||
*
|
||||
*/
|
||||
void *GC_amiga_realloc(void *old_object,size_t new_size_in_bytes){
|
||||
#ifndef GC_AMIGA_FASTALLOC
|
||||
return GC_realloc(old_object,new_size_in_bytes);
|
||||
#else
|
||||
void *ret;
|
||||
latestsize=new_size_in_bytes;
|
||||
ret=GC_realloc(old_object,new_size_in_bytes);
|
||||
if(ret==NULL && GC_AMIGA_MEMF==(MEMF_FAST | MEMF_CLEAR)){
|
||||
/* Out of fast-mem. */
|
||||
#ifdef GC_AMIGA_GC
|
||||
if(!GC_dont_gc){
|
||||
GC_gcollect();
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
numcollects++;
|
||||
#endif
|
||||
ret=GC_realloc(old_object,new_size_in_bytes);
|
||||
}
|
||||
#endif
|
||||
if(ret==NULL){
|
||||
#ifndef GC_AMIGA_ONLYFAST
|
||||
GC_AMIGA_MEMF=MEMF_ANY | MEMF_CLEAR;
|
||||
if(GC_amiga_toany!=NULL) (*GC_amiga_toany)();
|
||||
GC_amiga_allocwrapper_do=GC_amiga_allocwrapper_any;
|
||||
ret=GC_realloc(old_object,new_size_in_bytes);
|
||||
#endif
|
||||
}
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
else{
|
||||
nullretries++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if(ret==NULL){
|
||||
WARN("Out of Memory! Returning NIL!\n", 0);
|
||||
}
|
||||
#ifdef GC_AMIGA_PRINTSTATS
|
||||
if(((char *)ret)<chipmax && ret!=NULL){
|
||||
chipa+=new_size_in_bytes;
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif //GC_AMIGA_AM
|
||||
|
||||
|
||||
87
src/engine/boehm_gc/BCC_MAKEFILE
Normal file
87
src/engine/boehm_gc/BCC_MAKEFILE
Normal file
@@ -0,0 +1,87 @@
|
||||
# Makefile for Borland C++ 5.5 on NT
|
||||
# If you have the Borland assembler, remove "-DUSE_GENERIC"
|
||||
#
|
||||
bc= c:\Borland\BCC55
|
||||
bcbin= $(bc)\bin
|
||||
bclib= $(bc)\lib
|
||||
bcinclude= $(bc)\include
|
||||
|
||||
gcinclude1 = $(bc)\gc6.2\include
|
||||
gcinclude2 = $(bc)\gc6.2\cord
|
||||
|
||||
cc= $(bcbin)\bcc32
|
||||
rc= $(bcbin)\brc32
|
||||
lib= $(bcbin)\tlib
|
||||
link= $(bcbin)\ilink32
|
||||
cflags= -O2 -R -v- -vi -H -H=gc.csm -I$(bcinclude);$(gcinclude1);$(gcinclude2) -L$(bclib) \
|
||||
-w-pro -w-aus -w-par -w-ccc -w-rch -a4 -D__STDC__=0
|
||||
defines= -DALL_INTERIOR_POINTERS -DUSE_GENERIC -DNO_GETENV -DJAVA_FINALIZATION -DGC_OPERATOR_NEW_ARRAY
|
||||
|
||||
.c.obj:
|
||||
$(cc) @&&|
|
||||
$(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.c
|
||||
|
|
||||
|
||||
.cpp.obj:
|
||||
$(cc) @&&|
|
||||
$(cdebug) $(cflags) $(cvars) $(defines) -o$* -c $*.cpp
|
||||
|
|
||||
|
||||
.rc.res:
|
||||
$(rc) -i$(bcinclude) -r -fo$* $*.rc
|
||||
|
||||
XXXOBJS= XXXalloc.obj XXXreclaim.obj XXXallchblk.obj XXXmisc.obj \
|
||||
XXXmach_dep.obj XXXos_dep.obj XXXmark_rts.obj XXXheaders.obj XXXmark.obj \
|
||||
XXXobj_map.obj XXXblacklst.obj XXXfinalize.obj XXXnew_hblk.obj \
|
||||
XXXdbg_mlc.obj XXXmalloc.obj XXXstubborn.obj XXXdyn_load.obj \
|
||||
XXXtypd_mlc.obj XXXptr_chck.obj XXXgc_cpp.obj XXXmallocx.obj
|
||||
|
||||
OBJS= $(XXXOBJS:XXX=)
|
||||
|
||||
all: gctest.exe cord\de.exe test_cpp.exe
|
||||
|
||||
$(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h MAKEFILE
|
||||
|
||||
gc.lib: $(OBJS)
|
||||
del gc.lib
|
||||
$(lib) $* @&&|
|
||||
$(XXXOBJS:XXX=+)
|
||||
|
|
||||
|
||||
gctest.exe: tests\test.obj gc.lib
|
||||
$(cc) @&&|
|
||||
$(cflags) -W -e$* tests\test.obj gc.lib
|
||||
|
|
||||
|
||||
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h \
|
||||
cord\de_cmds.h
|
||||
|
||||
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj \
|
||||
cord\de_win.res gc.lib
|
||||
$(cc) @&&|
|
||||
$(cflags) -W -e$* cord\cordbscs.obj cord\cordxtra.obj \
|
||||
cord\de.obj cord\de_win.obj gc.lib
|
||||
|
|
||||
$(rc) cord\de_win.res cord\de.exe
|
||||
|
||||
gc_cpp.obj: include\gc_cpp.h include\gc.h
|
||||
|
||||
gc_cpp.cpp: gc_cpp.cc
|
||||
copy gc_cpp.cc gc_cpp.cpp
|
||||
|
||||
test_cpp.cpp: tests\test_cpp.cc
|
||||
copy tests\test_cpp.cc test_cpp.cpp
|
||||
|
||||
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
|
||||
$(cc) @&&|
|
||||
$(cflags) -W -e$* test_cpp.obj gc.lib
|
||||
|
|
||||
|
||||
scratch:
|
||||
-del *.obj *.res *.exe *.csm cord\*.obj cord\*.res cord\*.exe cord\*.csm
|
||||
|
||||
clean:
|
||||
del gc.lib
|
||||
del *.obj
|
||||
del tests\test.obj
|
||||
|
||||
363
src/engine/boehm_gc/ChangeLog
Normal file
363
src/engine/boehm_gc/ChangeLog
Normal file
@@ -0,0 +1,363 @@
|
||||
2007-07-02 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* gc_config_macros.h: Also check for IA64 when setting
|
||||
GC_HPUX_THREADS.
|
||||
* mallocx.c: Change my_bytes_allocd to signed_word.
|
||||
* include/pthread_redirects.h: Remove obsolete Solaris threads
|
||||
(as opposed to pthreads) support.
|
||||
|
||||
2007-07-02 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* mach_dep.c (GC_with_callee_saves_pushed): Don't use getcontext()
|
||||
on ARM/Linux. Check getcontext() return value.
|
||||
|
||||
2007-06-29 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* backgraph.c (per_object_func): Make argument types consistent.
|
||||
(GC_traverse_back_graph): Mark GC_deepest_obj.
|
||||
|
||||
2007-06-29 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* finalize.c (GC_finalize): Change dl_size and fo_size to size_t.
|
||||
* os_dep.c (GC_win32_get_mem): Add GC_mem_top_down option.
|
||||
|
||||
2007-06-28 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* doc/README.win32, doc/README, README.QUICK: Fix some of the worst
|
||||
anachronisms.
|
||||
* dyn_load.c: Partially support cygwin, but don't enable it yet.
|
||||
|
||||
2007-06-28 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* Makefile.am: Use -no-undefined for libgc.
|
||||
* Makefile.in: Regenerate.
|
||||
* Makefile.direct: Document USE_PROC_FOR_LIBRARIES.
|
||||
* dyn_load.c (GC_register_map_entries): Rename prot_buf to prot
|
||||
consistently.
|
||||
* misc.c: Fix some WARN calls. Move GC_is_initialized setting and
|
||||
GC_thr_init() call.
|
||||
* os_dep.c: Consistently use WARN where appropriate.
|
||||
* thread_local_alloc.c: Revert change to GC_WIN32_THREADS test. Instead
|
||||
remove inappropriate pthread.h include.
|
||||
* doc/README.linux: Remove some anachronisms.
|
||||
|
||||
2007-06-23 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* alloc.c: Also use GC_check_tls on non-Linux systems.
|
||||
* mallocx.c (GC_reclaim_generic): Remove bogus declaration.
|
||||
* include/private/gc_priv.h (GC_reclaim_generic): Declare correctly
|
||||
with prototype.
|
||||
|
||||
2007-06-19 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* alloc.c (GC_adj_bytes_allocd): Avoid (long) casts, fix comment.
|
||||
(GC_print_heap_sects): Use size_t instead of unsigned long.
|
||||
* thread_local_alloc.c (GC_lookup_thread): Define in the correct
|
||||
context.
|
||||
* win32_threads.c, include/gc_config_macros.h: The last of Romano
|
||||
Paolo Tenca's patch. Move stdint.h include to gc_config_macros.h.
|
||||
* include/gc_inline.h: Avoid gc_priv.h dependencies.
|
||||
* tests/test.c (check_heap_stats): Replace unsigned long with size_t.
|
||||
|
||||
2007-06-12 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* aclocal.m4: Regenerate to update date.
|
||||
|
||||
2007-06-10 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* NT_X64_STATIC_THREADS_MAKEFILE: Replace obsolete -debugtype:cv.
|
||||
* mark_rts.c (GC_push_roots): Fix kind type.
|
||||
|
||||
2007-06-06 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* doc/README.win64: New file.
|
||||
* doc/doc.am, Makefile.direct: Add README.win64.
|
||||
* Makefile.in: Regenerate.
|
||||
|
||||
2007-06-06 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* Makefile.am, Makefile.direct: Add NT_X64_STATIC_THREADS_MAKEFILE.
|
||||
* Makefile.in: Regenerate.
|
||||
* NT_X64_STATIC_THREADS_MAKEFILE: Fix warning flags.
|
||||
* allochblk.c, alloc.c, blacklst.c, dbg_malc.c, dyn_load.c,
|
||||
finalize.c, headers.c, mach_dep.c, malloc.c, mark.c, misc.c,
|
||||
obj_map.c, os_dep.c, ptr_chck.c, reclaim.c, typd_mlc.c,
|
||||
win32_threads.c, cord/de_win.c, include/gc_mark.h,
|
||||
include/private/gc_hdrs.h, include/private/gc_pmark.h,
|
||||
include/private/gc_priv.h, tests/test_cpp.cc:
|
||||
Replace old style function declarations. Clean up integral types.
|
||||
Remove register declarations. The change in malloc.c and the
|
||||
"int descr" declaration in mark.c are the most likely to have
|
||||
been real bugs outside of win64.
|
||||
* msvc_dbg.c: Disable on win64.
|
||||
* win32_threads.c: Add AMD64 support.
|
||||
* include/gc.h: no backtrace on AMD64 for now.
|
||||
|
||||
2007-06-06 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* msvc_dbg.c(GetModuleBase): Replace strcat with strcat_s.
|
||||
|
||||
2007-06-06 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* include/gc.h: (GC_word, GC_signed_word): Fix win64 definitions.
|
||||
Don't include windows.h in an extern "C" context.
|
||||
* include/private/gcconfig.h: Fix win64/X86_64 configuration.
|
||||
* tests/test.c: Eliminate more old style function definitions.
|
||||
Cleanup pointer and integer casts for win64.
|
||||
* tests/test_cpp.cc: Don't include gc_priv.h.
|
||||
* NT_STATIC_THREADS_MAKEFILE: Restrict suffixes for VC++ 2005.
|
||||
* NT_X64_STATIC_THREADS_MAKEFILE: New.
|
||||
|
||||
2007-06-06 Hans Boehm <Hans.Boehm@hp.com> (Really mostly Romano Paolo Tenca)
|
||||
|
||||
* win32_threads.c: Separate out DEBUG_WIN32_PTHREADS_STACK. Ignore
|
||||
FINISHED threads for suspension. (GC_pthread_join): Add
|
||||
pthread_self() cast. (GC_pthread_start_inner): Execute cleanup
|
||||
handler when popping it.
|
||||
* include/private/gc_locks.h: Inline THREAD_EQUAL for
|
||||
GC_WIN32_PTHREADS. Define USE_PTHREAD_LOCKS only if we have
|
||||
pthreads.
|
||||
|
||||
2007-05-23 Hans Boehm <Hans.Boehm@hp.com> (Really mostly Romano Paolo Tenca)
|
||||
|
||||
* gc_dlopen.c, thread_local_alloc.c, threadlibs.c, win32_threads.c,
|
||||
tests/test.c: Accomodate GC_WIN32_PTHREADS.
|
||||
* include/gc.h: Don't include windows.h for GC_WIN32_PTHREADS.
|
||||
* include/gc_config_macros.h: Define both PTHREADS and
|
||||
GC_WIN32_THREADS.
|
||||
* include/private/gc_locks.h: Nonstandard definitions of
|
||||
NUMERIC_THREAD_ID for GC_WIN32_PTHREADS.
|
||||
* doc/README.win32, Makefile.direct: Include documentation
|
||||
for GC_WIN32_PTHREADS.
|
||||
* Makefile.direct: Remove some anachronisms in the documentation.
|
||||
|
||||
2007-05-23 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* Makefile.am: Move includes to bottom. Add better library
|
||||
dependencies. Increment library version. Remove "SUBDIRS += .".
|
||||
* cord/cord.am, tests/tests.am: Add better library dependencies.
|
||||
Remove now unnecessary dependencies.
|
||||
* Makefile.in: Regenerate.
|
||||
* include/gc.h (GC_begin_thread_ex, GC_endthreadex, GC_ExitThread):
|
||||
Move to define on all Windows platforms. (_beginthread): define
|
||||
to generate error if used.
|
||||
|
||||
2007-05-22 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* include/private/gc_locks.h: Format to 80 columns.
|
||||
|
||||
2007-05-22 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* malloc.c(GC_free): Ignore bad frees on MSWIN32 with REDIRECT_MALLOC.
|
||||
* NT_MAKEFILE: msvc_dbg.h is in include/private. Don't use cvars
|
||||
rc.
|
||||
* misc.c (WIN32 GC_write): Define GC_need_to_lock in single-threaded
|
||||
case.
|
||||
* win32_threads.c: Test for __MINGW32__ in addition to _MINGW_VER.
|
||||
(GC_CreateThread, GC_beginthreadex): Deallocate args even if we fail.
|
||||
* include/gc.h: Add GC_reachable_here(). (GC_WinMain): Add GC_API.
|
||||
(GC_beginthreadex, GC_endthreadex, GC_ExitThread): Declare.
|
||||
* tests/test.c: Add GC_reachable_here() call.
|
||||
|
||||
2007-05-21 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* alloc.c (GC_try_to_collect): Call GC_init if necessary.
|
||||
* tests/thread_leak_test.c: Don't unconditionally define
|
||||
GC_LINUX_THREADS.
|
||||
|
||||
2007-05-21 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* Makefile.am: Remove extra_ldflags_libgc definition.
|
||||
* Makefile.in: Regenerate.
|
||||
|
||||
2007-05-17 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* include/private/gc_priv.h: Define AO_REQUIRE_CAS.
|
||||
|
||||
2007-05-16 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* finalize.c (GC_unreachable_finalize_mark_proc): Don't return void
|
||||
value.
|
||||
|
||||
2007-05-15 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* configure.ac, version.h, doc/README: Change version to 7.0alpha10.
|
||||
* configure: Regenerate.
|
||||
|
||||
[7.0alpha9 release]
|
||||
|
||||
2007-05-15 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* configure.ac, version.h, doc/README: Change version to 7.0alpha9.
|
||||
* configure: Regenerate.
|
||||
|
||||
2007-05-15 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* Makefile.am: Include NT_STSTIC_THREADS_MAKEFILE in dist.
|
||||
* Makefile.in: Regenerate.
|
||||
* include/private/gc_locks.h: GC_compare_and_exchange, GC_atomic_add:
|
||||
remove. NUMERIC_THREAD_ID, THREAD_EQUAL: New. GC_lock_holder: now
|
||||
unsigned long. I_DONT_HOLD_LOCK, I_HOLD_LOCK: Update.
|
||||
* pthread_stop_world.c, pthread_support.c, win32_threads.c: Use
|
||||
NUMERIC_THREAD_ID, THREAD_EQUAL.
|
||||
* include/private/gcconfig.h: GENERIC_COMPARE_AND_SWAP: Remove.
|
||||
* include/private/thread_local_alloc.h: Don't USE_COMPILER_TLS on
|
||||
ARM.
|
||||
|
||||
2007-05-11 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* dbg_mlc.c, include/gc.h, finalize.c: Merge Alexandre Oliva's
|
||||
GC_debug_register_finalizer_unreachable() patch from gcc tree.
|
||||
* thread_local_alloc.c (GC_malloc, GC_malloc_atomic): Add assertions
|
||||
to check GC has been initialized.
|
||||
|
||||
2007-05-10 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* include/gc_cpp.h: Documentation updates.
|
||||
* include/gc_config_macros.h: Don't check for __ppc__ to set
|
||||
DARWIN_THREADS.
|
||||
* Makefile.am: Include configure_atomic_ops.sh in dist.
|
||||
* Makefile.in: Regenerate.
|
||||
|
||||
2007-05-08 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* Makefile.am: Dont distribute copied atomic_ops files. Include
|
||||
libatomic_ops with "make dist".
|
||||
* Makefile.in: Regenerate.
|
||||
* configure: Regenerate.
|
||||
* configure.ac: Enable THREAD_LOCAL_ALLOC for Cygwin with threads.
|
||||
* win32_threads.c: Report error for Cygwin + GC_DLL.
|
||||
|
||||
2007-05-08 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* Makefile.direct: Update THREAD_LOCAL_ALLOC documentation.
|
||||
* cord/de_win.c: Rename and move AboutBox. Call GC_INIT. Remove
|
||||
MakeProcInstance anachronism.
|
||||
* doc/README.macros: Officially remove elif prohibition.
|
||||
Remove documentation for defunct SRC_M3 support.
|
||||
* include/gc.h: Remove more SRC_M3 references.
|
||||
* include/private/gcconfig.h: Remove still more SRC_M3 references.
|
||||
GC_SOLARIS_THREADS no longer needs to be checked separately.
|
||||
|
||||
2007-05-08 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* thread_local_alloc.c, include/private/thread_local_alloc.h:
|
||||
Spell __declspec correctly.
|
||||
* NT_STATIC_THREADS_MAKEFILE: Enable thread-local allocation.
|
||||
|
||||
2007-05-07 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* doc/README.win32: Adjust GC_win32_dll_threads rules again.
|
||||
|
||||
2007-05-07 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* mark.c (GC_mark_some wrapper): Restructure for readability, handle
|
||||
GC_started_thread_while_stopped.
|
||||
* misc.c (Win32 GC_write): Lock GC_write_cs only if needed.
|
||||
* win32_threads.c: (client_has_run): remove,
|
||||
GC_started_thread_while_stopped, GC_attached_thread: add.
|
||||
(GC_push_all_stacks): Add verbose output.
|
||||
(DllMain): Avoid initializing collector or the like.
|
||||
Never update both thread tables.
|
||||
* doc/README.win32: Adjust GC_win32_dll_threads rules.
|
||||
|
||||
2007-05-07 Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* pthread_stop_world.c (GC_push_all_stacks): Print thread count with
|
||||
GC_PRINT_VERBOSE_STATS.
|
||||
|
||||
2007-05-01 Hans Boehm <Hans.Boehm@hp.com>
|
||||
(and Manuel Serrano, Craig McDaniel)
|
||||
|
||||
* configure.ac: Comment out redundant
|
||||
AC_DEFINE(NO_EXECUTE_PERMISSION).
|
||||
* configure: Regenerate.
|
||||
* sparc_mach_dep.S: Remove single quote in comment.
|
||||
* include/private/gcconfig.h: Fix DATAEND for NONSTOP.
|
||||
* win32_threads.c: Include stdint.h for Mingw. Add GC_API for DllMain.
|
||||
(GC_use_DllMain): Fix assertion.
|
||||
|
||||
2007-02-14 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* configure.ac: Introduce extra_ldflags_libgc. Use it for Darwin.
|
||||
* configure: Regenerate.
|
||||
* Makefile.am (libgc_la_LDFLAGS): Use extra_ldflags_libgc.
|
||||
* Makefile.in: Regenerate.
|
||||
* include/private/gcconfig.h: Enable MPROTECT_VDB for all Darwin
|
||||
targets. Remove comments.
|
||||
Prepare ppc64 support for Darwin.
|
||||
|
||||
2007-01-29 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* darwin_stop_world.c: Clean up and reformat code.
|
||||
|
||||
2007-01-28 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* darwin_stop_world.c (GC_push_all_stacks): Fix compiler warnings.
|
||||
Make i unsigned.
|
||||
(GC_stop_world): Likewise. Remove unused GC_thread p.
|
||||
(GC_start_world): Likewise.
|
||||
|
||||
* os_dep.c: Define GC_darwin_register_mach_handler_thread extern.
|
||||
Remove double SIG_HNDLR_PTR definition.
|
||||
(GC_forward_exception): Fix compiler warnings, make i unsigned.
|
||||
Initialize thread_state to NULL.
|
||||
(catch_exception_raise): Fix compiler warnings, make i unsigned.
|
||||
|
||||
2007-01-25 Petr Salinger and Hans Boehm <Hans.Boehm@hp.com>
|
||||
|
||||
* include/private/gc_priv.h (NEED_FIND_LIMIT, FREEBSD variant):
|
||||
also define for X86_64.
|
||||
* configure.ac: Move generic gnu (Hurd) case to below kfreebsd case.
|
||||
* configure: Regenerate.
|
||||
* README.changes: Point to ChangeLog.
|
||||
|
||||
2007-01-25 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* darwin_stop_world.c: Move THREAD_FLD defines to ...
|
||||
* include/private/gc_priv.h: ... here.
|
||||
Fix THREAD_STATE definitions for ppc64.
|
||||
* os_dep.c (catch_exception_raise): Use THREAD_FLD for exc_state member
|
||||
access.
|
||||
|
||||
2007-01-18 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* os_dep.c (if defined(MPROTECT_VDB) && defined(DARWIN)): Clean up and
|
||||
reformat code.
|
||||
Correct email reference.
|
||||
|
||||
2007-01-11 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* configure.ac (i?86*-*-darwin*): Replaced HAS_I386_THREAD_STATE_* with
|
||||
HAS_X86_THREAD_STATE32_*.
|
||||
(x86_64-*-darwin*): Extended the above check for x86_64-*-darwin* with
|
||||
HAS_X86_THREAD_STATE64_*.
|
||||
Added value 1 in the above AC_DEFINE's. Important for the upcoming
|
||||
Leopard.
|
||||
* configure: Regenerated.
|
||||
* include/private/gcconfig.h: Modified X86_64 define for Darwin.
|
||||
Removed __x86_64__ check in POWERPC section. Added base definitions
|
||||
for the X86_64 Darwin port.
|
||||
* include/private/gc_priv.h: Added GC_MACH_HEADER and GC_MACH_SECTION
|
||||
to distinguish between 32 and 64-bit applications. Added definitions
|
||||
for X86_64 Darwin.
|
||||
* darwin_stop_world.c: Added HAS_X86_THREAD_STATE64___RAX. And
|
||||
replaced HAS_I386_THREAD_STATE___EAX with HAS_X86_THREAD_STATE32___EAX.
|
||||
(GC_push_all_stacks): Added code for X86_64 Darwin. Even for the
|
||||
!DARWIN_DONT_PARSE_STACK. Maybe obsolete.
|
||||
* dyn_load.c (GC_dyld_name_for_hdr): Use GC_MACH_HEADER.
|
||||
(GC_dyld_image_add): Use GC_MACH_HEADER and GC_MACH_SECTION.
|
||||
Distinguish between getsectbynamefromheader_64 and
|
||||
getsectbynamefromheader.
|
||||
* os_dep.c (catch_exception_raise): Introduce exception definition for
|
||||
X86_64 Darwin. Replaced old i386_EXCEPTION_STATE_* definition with
|
||||
x86_EXCEPTION_STATE32_*. Add X86_64 for exc_state.faultvaddr.
|
||||
|
||||
2007-01-09 Andreas Tobler <a.tobler@schweiz.org>
|
||||
|
||||
* libtool.m4: Update to version from libtool-1.5.22.
|
||||
* ltmain.sh: Likewise.
|
||||
* ChangeLog: Created.
|
||||
|
||||
See doc/README.changes for earlier changes.
|
||||
|
||||
140
src/engine/boehm_gc/EMX_MAKEFILE
Normal file
140
src/engine/boehm_gc/EMX_MAKEFILE
Normal file
@@ -0,0 +1,140 @@
|
||||
#
|
||||
# OS/2 specific Makefile for the EMX environment
|
||||
#
|
||||
# You need GNU Make 3.71, gcc 2.5.7, emx 0.8h and GNU fileutils 3.9
|
||||
# or similar tools. C++ interface and de.exe weren't tested.
|
||||
#
|
||||
# Rename this file "Makefile".
|
||||
#
|
||||
|
||||
# Primary targets:
|
||||
# gc.a - builds basic library
|
||||
# c++ - adds C++ interface to library and include directory
|
||||
# cords - adds cords (heavyweight strings) to library and include directory
|
||||
# test - prints porting information, then builds basic version of gc.a, and runs
|
||||
# some tests of collector and cords. Does not add cords or c++ interface to gc.a
|
||||
# cord/de.exe - builds dumb editor based on cords.
|
||||
CC= gcc
|
||||
CXX=g++
|
||||
# Needed only for "make c++", which adds the c++ interface
|
||||
|
||||
CFLAGS= -O -DALL_INTERIOR_POINTERS
|
||||
# Setjmp_test may yield overly optimistic results when compiled
|
||||
# without optimization.
|
||||
# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
|
||||
# altered stubborn objects, at substantial performance cost.
|
||||
# -DFIND_LEAK causes the collector to assume that all inaccessible
|
||||
# objects should have been explicitly deallocated, and reports exceptions
|
||||
# -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
|
||||
# (Clients should also define SOLARIS_THREADS and then include
|
||||
# gc.h before performing thr_ or GC_ operations.)
|
||||
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
|
||||
# of objects to be recognized. (See gc_private.h for consequences.)
|
||||
# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
|
||||
# usually causing it to use less space in such situations.
|
||||
# Incremental collection no longer works in this case.
|
||||
# -DDONT_ADD_BYTE_AT_END is meaningful only with
|
||||
# -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
|
||||
# causes all objects to be padded so that pointers just past the end of
|
||||
# an object can be recognized. This can be expensive. (The padding
|
||||
# is normally more than one byte due to alignment constraints.)
|
||||
# -DDONT_ADD_BYTE_AT_END disables the padding.
|
||||
|
||||
AR= ar
|
||||
RANLIB= ar s
|
||||
|
||||
# Redefining srcdir allows object code for the nonPCR version of the collector
|
||||
# to be generated in different directories
|
||||
srcdir = .
|
||||
VPATH = $(srcdir)
|
||||
|
||||
OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o mallocx.o
|
||||
|
||||
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
|
||||
|
||||
CORD_INCLUDE_FILES= $(srcdir)/gc.h $(srcdir)/cord/cord.h $(srcdir)/cord/ec.h \
|
||||
$(srcdir)/cord/cord_pos.h
|
||||
|
||||
# Libraries needed for curses applications. Only needed for de.
|
||||
CURSES= -lcurses -ltermlib
|
||||
|
||||
# The following is irrelevant on most systems. But a few
|
||||
# versions of make otherwise fork the shell specified in
|
||||
# the SHELL environment variable.
|
||||
SHELL= bash
|
||||
|
||||
SPECIALCFLAGS =
|
||||
# Alternative flags to the C compiler for mach_dep.c.
|
||||
# Mach_dep.c often doesn't like optimization, and it's
|
||||
# not time-critical anyway.
|
||||
|
||||
all: gc.a gctest.exe
|
||||
|
||||
$(OBJS) test.o: $(srcdir)/gc_priv.h $(srcdir)/gc_hdrs.h $(srcdir)/gc.h \
|
||||
$(srcdir)/gcconfig.h $(srcdir)/gc_typed.h
|
||||
# The dependency on Makefile is needed. Changing
|
||||
# options affects the size of GC_arrays,
|
||||
# invalidating all .o files that rely on gc_priv.h
|
||||
|
||||
mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h $(srcdir)/include/private/gc_pmark.h
|
||||
|
||||
gc.a: $(OBJS)
|
||||
$(AR) ru gc.a $(OBJS)
|
||||
$(RANLIB) gc.a
|
||||
|
||||
cords: $(CORD_OBJS) cord/cordtest.exe
|
||||
$(AR) ru gc.a $(CORD_OBJS)
|
||||
$(RANLIB) gc.a
|
||||
cp $(srcdir)/cord/cord.h include/cord.h
|
||||
cp $(srcdir)/cord/ec.h include/ec.h
|
||||
cp $(srcdir)/cord/cord_pos.h include/cord_pos.h
|
||||
|
||||
gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/gc_cpp.h
|
||||
$(CXX) -c -O $(srcdir)/gc_cpp.cc
|
||||
|
||||
c++: gc_cpp.o $(srcdir)/gc_cpp.h
|
||||
$(AR) ru gc.a gc_cpp.o
|
||||
$(RANLIB) gc.a
|
||||
cp $(srcdir)/gc_cpp.h include/gc_cpp.h
|
||||
|
||||
mach_dep.o: $(srcdir)/mach_dep.c
|
||||
$(CC) -o mach_dep.o -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
|
||||
|
||||
mark_rts.o: $(srcdir)/mark_rts.c
|
||||
$(CC) -o mark_rts.o -c $(CFLAGS) $(srcdir)/mark_rts.c
|
||||
|
||||
cord/cordbscs.o: $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordbscs.c -o cord/cordbscs.o
|
||||
|
||||
cord/cordxtra.o: $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordxtra.c -o cord/cordxtra.o
|
||||
|
||||
cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c $(srcdir)/cord/cordprnt.c -o cord/cordprnt.o
|
||||
|
||||
cord/cordtest.exe: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
|
||||
$(CC) $(CFLAGS) -o cord/cordtest.exe $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
|
||||
|
||||
cord/de.exe: $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a
|
||||
$(CC) $(CFLAGS) -o cord/de.exe $(srcdir)/cord/de.c $(srcdir)/cord/cordbscs.o $(srcdir)/cord/cordxtra.o gc.a $(CURSES)
|
||||
|
||||
clean:
|
||||
rm -f gc.a tests/test.o gctest.exe output-local output-diff $(OBJS) \
|
||||
setjmp_test mon.out gmon.out a.out core \
|
||||
$(CORD_OBJS) cord/cordtest.exe cord/de.exe
|
||||
-rm -f *~
|
||||
|
||||
gctest.exe: tests/test.o gc.a
|
||||
$(CC) $(CFLAGS) -o gctest.exe tests/test.o gc.a
|
||||
|
||||
# If an optimized setjmp_test generates a segmentation fault,
|
||||
# odds are your compiler is broken. Gctest may still work.
|
||||
# Try compiling setjmp_t.c unoptimized.
|
||||
setjmp_test.exe: $(srcdir)/setjmp_t.c $(srcdir)/gc.h
|
||||
$(CC) $(CFLAGS) -o setjmp_test.exe $(srcdir)/setjmp_t.c
|
||||
|
||||
test: setjmp_test.exe gctest.exe
|
||||
./setjmp_test
|
||||
./gctest
|
||||
make cord/cordtest.exe
|
||||
cord/cordtest
|
||||
156
src/engine/boehm_gc/MacOS.c
Normal file
156
src/engine/boehm_gc/MacOS.c
Normal file
@@ -0,0 +1,156 @@
|
||||
/*
|
||||
MacOS.c
|
||||
|
||||
Some routines for the Macintosh OS port of the Hans-J. Boehm, Alan J. Demers
|
||||
garbage collector.
|
||||
|
||||
<Revision History>
|
||||
|
||||
11/22/94 pcb StripAddress the temporary memory handle for 24-bit mode.
|
||||
11/30/94 pcb Tracking all memory usage so we can deallocate it all at once.
|
||||
02/10/96 pcb Added routine to perform a final collection when
|
||||
unloading shared library.
|
||||
|
||||
by Patrick C. Beard.
|
||||
*/
|
||||
/* Boehm, February 15, 1996 2:55 pm PST */
|
||||
|
||||
#include <Resources.h>
|
||||
#include <Memory.h>
|
||||
#include <LowMem.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gc.h"
|
||||
#include "gc_priv.h"
|
||||
|
||||
// use 'CODE' resource 0 to get exact location of the beginning of global space.
|
||||
|
||||
typedef struct {
|
||||
unsigned long aboveA5;
|
||||
unsigned long belowA5;
|
||||
unsigned long JTSize;
|
||||
unsigned long JTOffset;
|
||||
} *CodeZeroPtr, **CodeZeroHandle;
|
||||
|
||||
void* GC_MacGetDataStart()
|
||||
{
|
||||
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
|
||||
if (code0) {
|
||||
long belowA5Size = (**code0).belowA5;
|
||||
ReleaseResource((Handle)code0);
|
||||
return (LMGetCurrentA5() - belowA5Size);
|
||||
}
|
||||
fprintf(stderr, "Couldn't load the jump table.");
|
||||
exit(-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* track the use of temporary memory so it can be freed all at once. */
|
||||
|
||||
typedef struct TemporaryMemoryBlock TemporaryMemoryBlock, **TemporaryMemoryHandle;
|
||||
|
||||
struct TemporaryMemoryBlock {
|
||||
TemporaryMemoryHandle nextBlock;
|
||||
char data[];
|
||||
};
|
||||
|
||||
static TemporaryMemoryHandle theTemporaryMemory = NULL;
|
||||
static Boolean firstTime = true;
|
||||
|
||||
void GC_MacFreeTemporaryMemory(void);
|
||||
|
||||
Ptr GC_MacTemporaryNewPtr(size_t size, Boolean clearMemory)
|
||||
{
|
||||
static Boolean firstTime = true;
|
||||
OSErr result;
|
||||
TemporaryMemoryHandle tempMemBlock;
|
||||
Ptr tempPtr = nil;
|
||||
|
||||
tempMemBlock = (TemporaryMemoryHandle)TempNewHandle(size + sizeof(TemporaryMemoryBlock), &result);
|
||||
if (tempMemBlock && result == noErr) {
|
||||
HLockHi((Handle)tempMemBlock);
|
||||
tempPtr = (**tempMemBlock).data;
|
||||
if (clearMemory) memset(tempPtr, 0, size);
|
||||
tempPtr = StripAddress(tempPtr);
|
||||
|
||||
// keep track of the allocated blocks.
|
||||
(**tempMemBlock).nextBlock = theTemporaryMemory;
|
||||
theTemporaryMemory = tempMemBlock;
|
||||
}
|
||||
|
||||
# if !defined(SHARED_LIBRARY_BUILD)
|
||||
// install an exit routine to clean up the memory used at the end.
|
||||
if (firstTime) {
|
||||
atexit(&GC_MacFreeTemporaryMemory);
|
||||
firstTime = false;
|
||||
}
|
||||
# endif
|
||||
|
||||
return tempPtr;
|
||||
}
|
||||
|
||||
extern word GC_fo_entries;
|
||||
|
||||
static void perform_final_collection()
|
||||
{
|
||||
unsigned i;
|
||||
word last_fo_entries = 0;
|
||||
|
||||
/* adjust the stack bottom, because CFM calls us from another stack
|
||||
location. */
|
||||
GC_stackbottom = (ptr_t)&i;
|
||||
|
||||
/* try to collect and finalize everything in sight */
|
||||
for (i = 0; i < 2 || GC_fo_entries < last_fo_entries; i++) {
|
||||
last_fo_entries = GC_fo_entries;
|
||||
GC_gcollect();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void GC_MacFreeTemporaryMemory()
|
||||
{
|
||||
# if defined(SHARED_LIBRARY_BUILD)
|
||||
/* if possible, collect all memory, and invoke all finalizers. */
|
||||
perform_final_collection();
|
||||
# endif
|
||||
|
||||
if (theTemporaryMemory != NULL) {
|
||||
long totalMemoryUsed = 0;
|
||||
TemporaryMemoryHandle tempMemBlock = theTemporaryMemory;
|
||||
while (tempMemBlock != NULL) {
|
||||
TemporaryMemoryHandle nextBlock = (**tempMemBlock).nextBlock;
|
||||
totalMemoryUsed += GetHandleSize((Handle)tempMemBlock);
|
||||
DisposeHandle((Handle)tempMemBlock);
|
||||
tempMemBlock = nextBlock;
|
||||
}
|
||||
theTemporaryMemory = NULL;
|
||||
|
||||
# if !defined(SHARED_LIBRARY_BUILD)
|
||||
if (GC_print_stats) {
|
||||
fprintf(stdout, "[total memory used: %ld bytes.]\n",
|
||||
totalMemoryUsed);
|
||||
fprintf(stdout, "[total collections: %ld.]\n", GC_gc_no);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
#if __option(far_data)
|
||||
|
||||
void* GC_MacGetDataEnd()
|
||||
{
|
||||
CodeZeroHandle code0 = (CodeZeroHandle)GetResource('CODE', 0);
|
||||
if (code0) {
|
||||
long aboveA5Size = (**code0).aboveA5;
|
||||
ReleaseResource((Handle)code0);
|
||||
return (LMGetCurrentA5() + aboveA5Size);
|
||||
}
|
||||
fprintf(stderr, "Couldn't load the jump table.");
|
||||
exit(-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __option(far_data) */
|
||||
886
src/engine/boehm_gc/MacProjects.sit.hqx
Normal file
886
src/engine/boehm_gc/MacProjects.sit.hqx
Normal file
@@ -0,0 +1,886 @@
|
||||
(This file must be converted with BinHex 4.0)
|
||||
|
||||
:$deKBe"bEfTPBh4c,R0TG!"6594%8dP8)3#3"&)e!!!"4UiT8dP8)3!(!!"50A*
|
||||
|
||||
-BA8#ZJ#3!aB"#3d0#'GM,MBi5bkjBf038%-ZZ3#3%)Zi!*!8"@`!N!6rN!4069"
|
||||
|
||||
568e$3`%!UbqAD+X`19S!!!Ba!!!,*J!!!F%!!!-PfTmj1`#3"PET)d31)LTH6H4
|
||||
|
||||
#*AqG5b5HI*)QjY$IIb00%ReTJSi6rG$jG(bZ,"Rc,9Umf[IRj)6FZ-j`GfGR)#!
|
||||
|
||||
m-#qLqB#cj'G%46qffB3q8AppLXKc+P&*il4FMJMq3N32r[U,(PlSNdrQm-J(4!p
|
||||
|
||||
jK)NHmKJSHY!,&chS$4)pk%8mL3I)B0'$AU6S3'q)k%%[5[5J&ffa#68)0ZM&#T!
|
||||
|
||||
!*fHC-2dFZ3i83[Vr[4Xh'+DNQrm'J)rrpqe%ST`,FeVi6b,*qHH")4eQc28NFMN
|
||||
|
||||
ZT*m,L"Y%-`pdAk6RLHDaeVV0a,,@P(4UUK66rUM'8bf91llS("lTh81)MBQ+4*q
|
||||
|
||||
rfHENEhD)Ke#3!09'M%bL[P1+G88fa$3e)5Gpf0kARpBf*6eIH*0`ZBHR%ii"PbN
|
||||
|
||||
+D&*)688M)Sm$Bm[cCdDjh2YIjmAc`(TVpi*Vka((A*&Yl@'LTSH1M*AMP#,2[A$
|
||||
|
||||
(FHA@S"dL4dER#3b!EfBYem(C9P5iGH"a-bb-AL(F"bb-AL,F6)%a9pJUL,(hf%B
|
||||
|
||||
TeQb["X5ib4DQXV!-fa6&mZf&3,(C&UDd-((SpeMBEIB`8Zc,BcZR3A5'X+jYj$'
|
||||
|
||||
6)6HVV+R[!`#3!`X!(E@*MFQ%R4d"))`m[3JM[c)bBS54Tj'M(AP+MK&f%VD5SdG
|
||||
|
||||
SANFB@3Rqc$Am83(+)`"G(D%A'9!bBQ6!b)b4Sq3SH8D1NDGNX$)bBi54!51--$*
|
||||
|
||||
Kj0L!M"KKK"dC--,)-h+-6#KKC-$)-F)NamL!!Z06#X!!b&%bBUHp8RcN'%%6!b,
|
||||
|
||||
i!!kV"`"DLHFaK*!!"Ym4K,,2i2X4c[,`c5!GIPf!ZcNi'8'VfJFpSfdpq+CY$8j
|
||||
|
||||
-V'f-DZr2[36#1(ael5hmfT@1cSU66D5pqDSA89pdTP-`Z[jj6T&!PmZBFZjal"&
|
||||
|
||||
5iG6#blE$+&kLh#QZ118&(0T1J(hZ,9)5MJ9ic*qPI!ac'RJ96QMZjSbkMq()Ui6
|
||||
|
||||
B+f,,#'N1icbM4N"aaBr1`3Z9U'8RY'XAiVXFKp#&k2D5Be%VCdh4%,+2QS'b"Q2
|
||||
|
||||
%0PNT4rE#%kTUFqYDM56bVjfe!p8MqmL)1VmjVkJY`U[*$&*L3AMSpB@LCQ*U&l%
|
||||
|
||||
T+3890rL,V9klFN*4@f0UTf8Z&&afN!"4GC6G8p3fN9$4+4[-@DAeK%lej"@eAAL
|
||||
|
||||
eU@&4[Tm28%mqqUkS(F+VDa#lB&'rlRAllRP&l460Qc,)MHR$jMh@$8Y4Xc'e`cd
|
||||
|
||||
ZE2AUUiH+fK96feb$epq&'RAQeLG&lCDjmP+"Kr8k9#qp'eI8RPf[6R$dS+$UcqI
|
||||
|
||||
ELYSV[*ETFL&j[@lr803qd9I2A#bi4Vei3*d[+@Urk*!!&abe0HTVm%44"i4A6JN
|
||||
|
||||
c(2I!kjRl6a9e813DK"A6p(LjRZZGaGH+1L5SiBT[(6ekd2*ILMSXU(l)#m3QMDB
|
||||
|
||||
V+QTG!r*NG#RQai#DNh4,l0&!Ie`dYi98Y1%1A$5hKP4,`d9cHdKP'LkD@q4hYC*
|
||||
|
||||
%dfdLeCCNN@i9UIBNLh5l5(8N68qhM&4R`d9cfdKP'bkD@dHU+qe&XRfNZSqc10j
|
||||
|
||||
#8Me*&ZNfNZT0hSYd+dP&ri-FGM6G6P,p5D,rPNT0`dQLk5+6'NLb5"HDe'$L)Pe
|
||||
|
||||
X8N2bj-Z'$r$6-$NZjLGC)1lB-"jQSff@[ak%LJ[rI#%p2ddAGREN(@"V+,S6CI!
|
||||
|
||||
I!!!0$3KRBbj38%-ZZ@0M8&"$,VN!N"#$BJ#3%4B!!!d'!*!%rj!%68e38Ne33d-
|
||||
|
||||
"!+X[PfqV-$P*!!!'-3!!&UB!!!(&!!!&C80(jji!N!BMM#0%$L)UANhN3L9rV@9
|
||||
|
||||
B`f#c2p$XpAVVCc-[`k20Y5bJ+CTHPScj`Z'!lmr*#EPaRH(ZcR!J!!rqMKG"q)#
|
||||
|
||||
cj'G%46qffB3q8Aqp4R6FA83PM6`KUjaYD&IlZ@jDrY"pk[b&AZrdH*kFbb9PM*S
|
||||
|
||||
`4Kh$c8Lf0bVe+Y`Q$amM6mc%*C1(jF&1bFSdGIlLpc*04b#X&D8[&6R%+-#6HhJ
|
||||
|
||||
kX"#A+Bp6%6RGkB&kM%'jh$ZLmam[1Irq,r82rGM"5H4bh1ZB+b"Z%&-pD)5CL9(
|
||||
|
||||
AP(4UUK6$!(lkH+UPFXFARF-MIHHMXf!5Nd%SZYRQj'pfL)G3N!$94X#(q25G8U`
|
||||
|
||||
VXL'QU3Njk8[phV2@0Q92J#d6rA2N1["[!%c(M4X-8p,0IcYJf2lRBmD2c)*RQEF
|
||||
|
||||
68m'9jqq*MjHTji&GqDp$kh501r9fqVPJe4iQDRS)L!)ELqiX08i#@40jpP1+F@p
|
||||
|
||||
iC&))L)Qq4Bk-cK-i*h`cDlN1cMBUbZA3+beKhX*-&UD`X%ME%F91fHB3BaCC''Y
|
||||
|
||||
KNba-C@(,"-40Yl"l,#c8`YCDf%#"XGD%F4m3'*i'k"iah[Ddam+k"Xd3eV@02'B
|
||||
|
||||
bj'D90I9p!!!-q)[jAU2HhQ[NiCQC&f(Ne`JR!hlN1''4Sjc`)hcL5IK+f(@8(q&
|
||||
|
||||
(1&Nj2XreTBI[M!0dGB4'MK01#CFF2c,JK"*1MNZ1(q&(11@5ii5EKimF*ja``Np
|
||||
|
||||
#bA(#bBL6BpQ6jq5imT-m2mQ!dq2N'H&2RT2M%Nii'6$J,PF!#N#jGS3IS9Uba%G
|
||||
|
||||
'A-)*8[#%!j-9'#r3@EpUPQ9+NL6$ldj*kVS6INIK@`*q'q$hGRJCPb,`pUJm(fQ
|
||||
|
||||
3!#mGrdQqe$Nm22hkJ2cerNp"i3$m4Z62S5YA40V([V`MbHF@)QPT2IN@3@$ceHm
|
||||
|
||||
I&dT3GqF9K,'&&8[6LKMTbQ6@-*%bJE#4RM,b'FA*'VC5`0BBdTa"@aNXM#)mU'"
|
||||
|
||||
N@d@XSIKMMiMh#RbbLSjLT49GG9"F84)Q8QfN&![N1hK"A'V5F,,dJIF@+`iNJEb
|
||||
|
||||
H-(5Nar84j!"*Q54MH+j&08dYQc,(ipT9I+aFqIQc-XP313&803UUPPD4*+UAIlj
|
||||
|
||||
$U+jMAP1QUSfEYV2Qp4HKfZ#TYQTCT)hEaCbp+ZXH0"m5USfHDV1HbL4cCT@41rr
|
||||
|
||||
5+d+eL4&+'hR90)iLRp$LYcm)e5McQN@UMR#&$kKqr%eHU-DBejbUCC-k+P4N5r%
|
||||
|
||||
Iha+Uc5aj)kVfm*'ej*8Dali5ULfHDLah-l$Zfer1#G9@6l8TTf*r,RKTZ2#Q8'h
|
||||
|
||||
MA2&i%MYq(0aCicHKfPlfDYLeJ3*FFEG3l@"HmfJbqFrdHU&IU+jRHE95BmQFkJF
|
||||
|
||||
29)qp)93hX!aCGLfYP0!jSEU4HF9)-e8M9rADGfC4U(BbVVC66+8XR2Hj2RAmGk'
|
||||
|
||||
kLDNk8`@p0[6F"hrG,e3h`kmm(BhDMQjBm@`ejDH1pG)YbUXYM'Y'5aD`-H(VPZ)
|
||||
|
||||
,*i6A,Nqe)D1Y'5@UV@HM3VAE)a3$3MT+9jAGa)HI#%*E@9ie+jmf-PA9dY#66`Z
|
||||
|
||||
[fkMA!l&$eZ3)bP996crcal6`ZRdT$9NG0S#+V([`rRZ&eae,A%dMGB2V4H%9YPL
|
||||
|
||||
LfZ3B194,NC[ik!QKZSYlaE"deVc1$3[9(XVeFJIG0T,9**@'AVXJZ2Db$%'!,$a
|
||||
|
||||
e+d2+8SES`Z&RD1(C`m,VlM*Aj)cP#M@ZlJI#Djp(U28`fl)VL9dKY+IXeFM!HRJ
|
||||
|
||||
MVc0#YCpj6@!,M0VrHYh,CMQN!FBjl1ZVEPhjaCK)``"6,6JiU@@ekMjdmEEPI@M
|
||||
|
||||
3DpXKj3pi+f`LFFpIUPrF058)N4X)f4ZQ*P5c1[&!pGhC4i@Ue2BCE"bRL&haLRk
|
||||
|
||||
Thb#ZUK&ZK-Kc9k4Z-[QKhdaf&1KhN!#*#IdZ-XfJhdPQ)I6l#![SYjD'HXp$hdA
|
||||
|
||||
f$1LhNlN-r4DbV8$I8iS[RSEqj#URqY@$9b3dJG1XG))%khUHJMX,Vh896Z%"I%B
|
||||
|
||||
PFK1MejpP2[@,$LpbTe[Q%h#[hhai0BBHF+r-MrTeL9G6k!!IKHa1rmf2qMf,9c6
|
||||
|
||||
d)%I[5Hq$1hVVq60(`H@-9fb&cfkb$BBDc1-Ck@@#jrVH%0cXH$@cIK[C#F&2Q9X
|
||||
|
||||
[qpl(HTpEQ9F`KqVA3&iYS3Pl6#ARpIXMVpCP6[+ma`PkbJPkbJPkbJPkbJPkbJP
|
||||
|
||||
kbJPkbJPkbJPk1MHKTlbJTlbJpqGlF2RNe4CD`1XDTfUZEYjDHE@[F0T$,KbK"Vc
|
||||
|
||||
mA!9AAPiGS3Qjm[HQi+l-LraVj'p1i3&mcNKce1@eZ4pFX(PY@1(66rD18)Im"eF
|
||||
|
||||
YAJ1K#AYcK92peXpVBfM#AZAIKi*r&r$U$"h)dkhp2[JI!kp0S3GjhdZZV))A!43
|
||||
|
||||
jH4kk(TLQKF4pTXhHI!ITRb%hcX3KfeN#**1EI54a"'@Z8(9Dm%D@b"Y#qhm!N!-
|
||||
|
||||
0!!PRBfaTBLda,VPM8&"$,VN!N"#ah3#3%!9X!!!I``#3"2q3"&"56dT,38K-!3#
|
||||
|
||||
TY1))Uc!eD!!!@F-!N!B563#3"2$I!*!)22J1`2KbNQaPEr+hGEX``Jk!Vpa0&eT
|
||||
|
||||
RDl*eSGZ&%EEAc@iGG+hAYBDRapHZd6ETQH'lV2AbpMVJ4lN,ck0G4lMb)fcKAQi
|
||||
|
||||
*AeLhm1)VRfPGM,"Zi8pBG1%a3VYZi@m,@rM#2'iAfhjHacE,K"[bJGYB,ZcNP&#
|
||||
|
||||
"$cqJ[fRG`SmXR'aMC-H6r-)AXTaNHE+Fj"HkN!"0"R[G!H4jITB&`!(!dKX"PZ#
|
||||
|
||||
Z+PX+S(dCS&YGZI3,cN3L+P4H)V5R@D3p,54$JD"3'!j')mhRcl%mUJ)9e2PVUaF
|
||||
|
||||
j[6lNX)ll!4,jajb6UrZK!hSTX[caD`$ZIHl,pdeVm&EaLeKG-YjQB6AKT)84pF,
|
||||
|
||||
kB$+55%ID`b-4QF0T19ckfSl,d['15$X-4cTr0"2!dIR5%1j[S4JQa0,J4lT!pkc
|
||||
|
||||
"EjcQ2ZmmNDF36,1DH)X!8($N3ihbR+mcX1GC!E!0fi)+ra)rCUL`#HU&V9)ke`6
|
||||
|
||||
IhTB!b&RK%B!&4fA8Ecr8+8IBcr)4Z8L+$bmVaA0$-Lr)$3+SMf0Xkh!%1L(hiM$
|
||||
|
||||
H56i!P'Q(V3ZXrmCRE,f[6f'0N!"Z$E6%fl(AqCL20Ka-#kRdjh`qA&CRACe[!5i
|
||||
|
||||
+PSiKjh)6PJM4H$#5%&U%HF#GqF0F$MM6fH)T68dFSQ!hQ*["e3hGME'TS#e`Fmq
|
||||
|
||||
Sl`'0qRTZMfEcM@b8M`(hV,a,kqB4N8iZ[4Sh5b!9ddQpT9YP#5UK!NX`BDbr,"E
|
||||
|
||||
!TME)X#08Bm,*$)fP2Ci@G1bTGUbETe@@q%4QL60h[2d5)BQGX-U5,*6)q)99'NX
|
||||
|
||||
bP3a1pJZTH#BC&"!P%4'5XP`!Fm82LidDE@#h&eejC#m'cSQd"k1C&S(CD`*"Va"
|
||||
|
||||
S%C+TmmkE6aJ*6S3kTd8)4GS&PNjQ"#DY1419T&!JQT+cV-0*5@'9$$5+K-58Y"%
|
||||
|
||||
N8Ea'&)q3!*!!UeBZ'qd'!&14D",LQVJ'$qTI1DUU3$%0cAD!e9HMkl`KaGAASBj
|
||||
|
||||
TJ#pMhSb5Rq0c+LJ3l3LJkD2dcrJM2Q%3Kh&mZL-JR(&m+L$L-)j29b,%B4br8)j
|
||||
|
||||
X!Y$j4ZUh`)[eI!A!R(d!4AHG`LH[d[f@re6*b2mAI`)H5F0aI+2XYq2iC)+N`6M
|
||||
|
||||
qC$b5"Z2ij,N%KHI*24K!$k@Plm*Hm'Rd8-bci0h@*rK6m%JDM[-[aZ1Nhq+IKNH
|
||||
|
||||
UJA&mE-V&'KM(2a129!2Mq2,5(2qIrSHmNfTSR2rTH+3D'XHRfL81irM8FE,Ep4r
|
||||
|
||||
eTUeM[5Ra8bilkJJ6f!)lF0e(0'p*Cke+2Nq9ccEjh#UIZq6c&[RmM(3ZV*!!cL0
|
||||
|
||||
k&5l"Jp4$Ilc)-m$9BDMqeV0m$l6LhM(EAX9A,10lG,aR)2GNb6Sm29&b0@CfmMd
|
||||
|
||||
&Mr!pHLh'hX&p"qiPVV#h)jIcaN(YAHVY!-im,lH&lp&Fc$pX!KD$+,qKqbMQh",
|
||||
|
||||
@BjDAX[M-KFF0&bH!le%r'GC@E`LVXP9mKXdeG)3QcED[U18Vq4jY2c-fD8XFl$a
|
||||
|
||||
Jb0pEdXPRCYXVR!e1c(f%qF`GKAUQcPT3T6E-YjCF2GYHhq#[aqa0'*p@XJl4r*8
|
||||
|
||||
qM(Fa(e1(MAb2DUZDVTq-SD2mJ+kFAj*ldAQmX-KFQf"C5i,E1fA&P2jHj`!8*c4
|
||||
|
||||
Cbq,eU+LUqmriLrQ-H$8"RJ(GXC,YKXYCKk(M!EcN!3MV-HG3b@DB@MEAd"P5,9[
|
||||
|
||||
2CjDYplkH1ckr$1D5aNf'jH[,p0ehXaPCKe@(eI0#11SC',UQT)X9K3qD(G8hK#c
|
||||
|
||||
C@GQUfADhU*AQPE#2X"A&i-9KaAUdDe$"bpQU)@mfJNfL,U61YQ4RBFiKFac+[hC
|
||||
|
||||
Y@49Fi(Ye4UjKII9Fl[b`UM[(Ca+6ZhF[@mq`0Seer)R3*#Y$$IcK`pPc%EI6FKZ
|
||||
|
||||
I`IV"'%bLZK'Mdl!5jqQ+3J!feU'k*f(FZf(EGY@@N!!CGAmMqd9@CrDD68d'jf(
|
||||
|
||||
3TlQV6AYhAEJlGh4$epjV3bSqBiDXKA!BPjeTVUYp1pI,DPfESAK1"2eSD[B-elh
|
||||
|
||||
H#"KCEIFl0K-Um0E-CFr[,$HC6Hhc`fDr-eb-HmN5*`iSE-8)!#TL+mfKpUV"jrc
|
||||
|
||||
$X6fMXIlRYZ5'5$I94YXX-&C(`""L$Dkf)VmVe*%)GZr'mh(#3i3EqlYKNKblRf*
|
||||
|
||||
'9fi`h"aV43`ejERI0DPfA"MDB``XX)HHa#bYS3h1c!hCcPlQ0+mDh0Yr`mEU8Hk
|
||||
|
||||
YrAmUXCIMj8SFBkA%6iNVCjRI%C(IMj&E3@l3G[C&a#hGId-rBQbXrT)c0e6q'2p
|
||||
|
||||
eC)89`[fJmPd62,qrh"5fBCA-$%rb1d1R5hbj`ddQ1G,60%Q1l'T#EqB1)110@)h
|
||||
|
||||
%i!95M+ekEiM0HfqSHM1k9UQY&%V$jTQPB&VZFVm*4FmG"[Acbff$#qbZ,a3IKUr
|
||||
|
||||
B"VZ2A1J-[B%elK$paa&k8Z63JaakNVNdL$c1fP%+A`QGIJ'bm6iH0ZklkX(0S"E
|
||||
|
||||
8jP*3Mb,[3pbE@&fLD'2RS@ZY1`pG"kj1X1j#2R9*X*QX*TAMbYcVef*YX2)T6FA
|
||||
|
||||
Q@D$Hf'AE5@VBGSP+2*elSqN#9T4Gc"`I)"SMr!P3K8hPL)Se--@E+!*#j8qBAdA
|
||||
|
||||
F)f`H'*JMT!TSH@V*`'V2IZI1K@DpeEljYRXA2YJ9eU,IcfjLaVQJjXS%LTUELM'
|
||||
|
||||
UNU1Q*M@HTVX(FV[-AA`QqadqFr3i9[JU81PlSB$r%d$A3iqhZfXV+KG!GjBeeU(
|
||||
|
||||
[-cfI+9deX0(XqqDqeeCrEqGcqm6iUPf$i$#AQd`B@p0rSjJ6NR2d'hX'fX5-"MQ
|
||||
|
||||
MU,pRS%(-F-NCDZeUk[$*BA*h$2XG9RaZHj-D6bq3!1YJC6AD61@QEFZ@lXi09,[
|
||||
|
||||
#3r`40LMRE"V0'C!!FecYKJh1Q(D[`hN%90BLbX@@Y!c8C8j3QmY!ApD)[GhVGTJ
|
||||
|
||||
**CcApF6MTA!ZjkemqUrh9AKG,PI[cVeVI+q#h6`$QIm$kKcXmZ"@c&ph+[pbaRf
|
||||
|
||||
+-2[6I1-)JqV1YQR9UpZ-&Cd9Uc'6i5P6JCdV6"8c-TKV%$1eQ*@af2(L22GJCe"
|
||||
|
||||
VaTDFcfaEffcXh1Pef-$Pm$Vic)0VQmqbL$(+mRVQJpGcr8kVcZZakIJ-9F5"VJ2
|
||||
|
||||
A)XVacTfpDfd&ZhSY"9l2XleH6rpD3Epa6E1D10FlQJjH!G34SPGS&qM3*fC3Pe2
|
||||
|
||||
L`2L%lVY,CV!*T39qcpXH[fHHVQRU'%UAhk2&Qk`VKaD[,i2ZHk`cX2[6K&iQRrQ
|
||||
|
||||
lbPXmS@QX)1Y!&RH`da"Y"8BfPYDc4GPC#3lV4AhlG+E(2&HTGaMM!VD)&65CaPL
|
||||
|
||||
Dr4lQB&J09`k9kE(,mhf[0f[T[[2#[mfpH2-6*6k4bk,U5Z`kcd%Ia$UcfEZ2Z!G
|
||||
|
||||
1&'%PEF2B1aKl$'0hBH`R',X1BjX`pP1-h6AD-aHa8TJD0Z"T@[KdIJ$5L*0!R+1
|
||||
|
||||
)NmCi#mDEj(J5i`fS4KaV[49[Y[ASjjGJCfSIkdaR)f+)e-#cLpMMH4iTJQFE+B$
|
||||
|
||||
RFiN4RXfXNFpBZGXAc[3QM,G2Yh*CMh@3!(q8lFE6#ID-P'YZ"AefKT9M99N2Re%
|
||||
|
||||
Z5UJ[cKd0UjR$Y@%N5eQr[bVdDANH1X3[2[#XjcJ0%Se1!jKa'U#f[M%BE`p&`TC
|
||||
|
||||
@-mfEF*1J""c`J'Sc4b0!`0Q1cH9X!e(3aCl!)H`k4qIhpfYS1)*',+EMMLJR'JM
|
||||
|
||||
*XAVRp4,L3*6EFHJLENI+bThcfZ@BBX$BV8U1Sr-@+@iljX&F'M+D6*J-'5#(%1k
|
||||
|
||||
[1&EhlT'("@L3!%(&RA-a6V0,2#9X9%3D8*&8fT'k`V(k5V),NCZX$kh*MY@GDYV
|
||||
|
||||
4Y-8%c[bAlh!l-U6&69c*e@N4Mj-C)C2d+XbiMLZjUSJ3--Aq8HQ-$[R0RcMaPa8
|
||||
|
||||
e&lLqlpUj[TGS[iMVqri'VZr9AUl[KhZi[J-YA0r"GUl[d&eFhq'YA0rr0h*pEml
|
||||
|
||||
RqYlHa2Ap"212)[Ba!pGh2-6e$Gc+p3dqbr80[FMe`hbZAjA&I4IA2aN0'##DQ-I
|
||||
|
||||
F0B%8$M1bX*!!6V&dUi!$KD&N2-DNDAZFBic&F2BrKF2r6-!j%"D+4)8c'q,aD,f
|
||||
|
||||
3!-3j51B9SJP@RdlLA(j+(8X++A@L25E3BD9ki@,HV9l@i1F0$6KDbP$RC(bL'2*
|
||||
|
||||
%ikP8)(QCZL15MXe30%"dDAVbI)DMURqBCV&i5b4dfDrbrk!LN!!@@#SGL#9B+*j
|
||||
|
||||
N3JH#Y3HLV#@5r"fhhq@IS5Jp9LM&BLQF6+PSMTk2cbS%9c)KQ@5a90K#Sf4N5PN
|
||||
|
||||
S5M[3da4hiQK)k+XiA(ND$YpSYSe-m)LIZ,6N5rL%!p$M"e)Z2G@JJJ8FXU,((EM
|
||||
|
||||
pQ)@$C4*&(*ZN6`SqKSGP)q02Q+F@[iqA@RaFJFBHbCM4qfMF%h!%89`D('LN6e`
|
||||
|
||||
k'KDkIh4i5)XM8r4*4)JcM9hKZ+)%Kcj2Rl4%aj+pAcSALTmN,qQmF&6[3Z`$k*0
|
||||
|
||||
%H%M18RJEF-b22R&0qM&+6,@P[&-a!BIik*1U!BGKe64B611lY)`iBNHI9"S+Ab9
|
||||
|
||||
l)JjKd5HT3V25,H+!P%`9Z`rkT%9kNCS1THY!pHQ6Q&%@$8)T99L%Sfhd5H*hI$J
|
||||
|
||||
64C28Y,C`Djl#m$6b!XGfTmrR*X8$d@L`Y6QkdK+%4i(E8[b59GP&,"cqQPC3ih4
|
||||
|
||||
MlA''N6k&X1iVfl4IfC%6%hNG3kaD8[4Nmd+LGcpXR+[Xb-XNFZZYEkLS`Q4G+Yd
|
||||
|
||||
5L413!'S-T`$1NR'U9P55`+R)+U%aM8!K9-"b-+[Xk$GR5FTkh)hN*rJB5@-L'EP
|
||||
|
||||
%j(6IK+GdbSlH-e9"XT!!TkM$335*3-%BFqd`miD+#P4)M`VKJ,5STAS-5DFJ,A9
|
||||
|
||||
lRF6mdQ"V)#Q+K-c,[YUNl&M9XNEZ@PkXmY(k8'eCj+P3G[5T%69*)e+cY5@CqV"
|
||||
|
||||
#$%SP0969B)9`fR3N*L#-jAfF#50kqURL8%pU-)M3+FmipZBILqkTH!E9YJip)aj
|
||||
|
||||
%`mKhi"GMeDhkeqSZq1IU*VIi[,SeRcM3"dM$M['C$j!!BhcZ!m11mCN2&2k,$aK
|
||||
|
||||
qi32[Hr5%Rh[d,hX-I&T(k6&F2UIBBc4(!m'9d93k(d+2NBr*-djj`D*SpBJAZ,f
|
||||
|
||||
9j!86F'3iZ$+9LDAqShqJf[jh,cLPbr2V[SPKZ8BUA*j'UT'@jR"M,2UIAFerUC*
|
||||
|
||||
hbU&Hqqk24KaUB492qKV`$C4!&+Z"V#$rQ"GJ24rmKPrCa6X4KAZ0c$d@5+lmTal
|
||||
|
||||
hVejS(qNI[*91V#iSP&p#b,2@2paR1A6E52mJe6FBBMJ1dGJL*2+9p3qIhj!![Bp
|
||||
|
||||
M('C8fB"h)XK)5,I&%TpfThIZ`BHa&(9Vm2+9kL#QA,kQIZdYiIaLYrARRVV2f2q
|
||||
|
||||
YNG[k'UGr%8DeBN-EK0EmEAlarTd(p5,rIHIa&j&hIpETLXk#R@jbC@-b,9jkj$[
|
||||
|
||||
SG20dc3jaep#MG,*Rm*9,kClGd#jFfLM2Qq@TmibVrRcNcU2@95h1CX5Efl"&%5r
|
||||
|
||||
8mURGV@U5ZdHGS,k4EYRemG4[EPCrFjZ4PqYQYFV$Li`LB4cI%5Ak4CIabTc4cV5
|
||||
|
||||
Z`5pfTSPdXM(B'Xb,d*RQlCVl-6rbfNK(iUpddhemB9))4J14@"k%hM42efh'efl
|
||||
|
||||
%*i192U1qBE',qSa81Y2F(%qfjbIV-mbRlM2Dk!QiiGN-X@CeBXhQjHJG2R%#l)P
|
||||
|
||||
%*m$r!"'46R)DGS+2k[XNTp(qiGGq@r81$FI)IYZ`[)lZM!cTba)YbQKh2VHq(T'
|
||||
|
||||
iYATPahXMf583L9i#-b!5'SA3JP$LMk5FV"eL5P&e,)!2AM(fqq[&rAqqJEX3ZJ0
|
||||
|
||||
4GUAcq1#I[$MlrpXrj3jb$ZiY+2BkkdRM@qKR3r"mcb,mia%m2lM89dZ[Vqh!-,f
|
||||
|
||||
QqNbpVjjZ29qJCq04M`2d!b+N'UT5MqGLqX832%q[Aej$mA2Gr%)2D,J,T!VQVUK
|
||||
|
||||
`%6jhAB9V+HAI4,rjJHFl+Pb,m4eQEZZ5@KrPp5aF@N9GqC2+ql1S&YkPdTmG6Gr
|
||||
|
||||
!qEV`09U+&4c&223NLQNk-DpALZNdR1mDqVXNM'QAB`crlBKL%mp(M*G"*FCZ`&J
|
||||
|
||||
DZ&cZG*Ki-f,J@mmLMhX`*R29E-FB[Qe,XDNr4DlPFZc[1GrDKlkqQYkKeBBaYUl
|
||||
|
||||
YEqK(@E3aM+N[HKM14ThU%2X*Hb(-`McNHXhpB"3j2BDaPJB6I!Ne%&qEaD`r`V`
|
||||
|
||||
YU-G"k"3ar)MaKKaEKl'$NQC6hd1-Lq4B$Q0G-XB+e-BRajCJ,+'*V3bd4NrqAp,
|
||||
|
||||
B[bJT[kddmXG*R(e#AIa5)9RRT[cr!`!!$3!*Cf0XD@)Y-LkjBe"33bkj!*!3qL)
|
||||
|
||||
!N"!0"J!!,h3!N!6rN!438Np+5d&)6!%!UE6L#+X`0A!!!#*k!*!'$d%!N!43[J#
|
||||
|
||||
3#1j"$F$iCXbcEQ9ffFS2dS@*jbZl63NYVcACZY$0##1XPDZ$V[@ke[$dmVQ6K5h
|
||||
|
||||
FYGEmE+(Rmc@246PGf0D9hF)@VNAi`VhS`KGM(GQA+lmmdfiI)f`c`Tq`63P23V[
|
||||
|
||||
Y`VEH`KHqX)9f(@(E*!Zrf-)@IZi)AhKXi3[E,M3j*432"&!HrHaD@&$M#f(,qq3
|
||||
|
||||
@XL1hN!$"3Rk6AcKCb%+1%di@J&@""TeG+a&(42abSQ*m9@@VL(4[%29TUPEGj%S
|
||||
|
||||
NfN09'd1a&"q0T8,*F(-`0#85E)pZZ-eZrEB+Z[80G6A,A6ir2'5jYd$i*mlPdrI
|
||||
|
||||
-@8-1XA6I6r6dUG[h&cAjUSAPI(dbhQEPDb0*+mqX6fN-*U1*9$3@'8GN$c0%(%0
|
||||
|
||||
GelfTH&Fd4Q0)jLrR%MNc2aM&pcf8d``Y,Ak!B(cHb*GQH1E2Phb'JLQq0Yi5)P*
|
||||
|
||||
IZ&DMccNrDX`mDiN1BLbSE&MC!)B+3p!!(FM4Z3"pmf##5,64Fd39&fA9Eck6N4(
|
||||
|
||||
q-Kr+TK`qGQ`-&dGPAb51%'Q'J"dB3bK$iZYMHPIm%$'QJ`j8f2l6cq5j@TmTYD&
|
||||
|
||||
8Dh0,2)CCjkGqG*&J+Y5CqU@IDmIQUUrh9q!`X*4GG$59b(1#DBYLrXT3Hc`B6B4
|
||||
|
||||
D3NZ)Zr'(SNLFq4ETPX+0#01J@-c9Mci&E"ETe"lZK'B2D682F5pVpcl#6cM0`cF
|
||||
|
||||
VIh2RdI%LA6N'$6l@jXi1I@kfp+LX3395@i-*Bq1p(FdBDS-m*N)0#&FB@QXXRJV
|
||||
|
||||
TqHr&d$F[UDca!YiDjchaf-C3%T1`bTUFNM26%1V@@T1GbH#dKP"R2*d-KU#5L)D
|
||||
|
||||
5FVQ)&NXr0"XEY)Prh,6j`NN!Fk+aB(Zk*F3lDTZ$[P"c5bMC1Arq8UD4i#5T15f
|
||||
|
||||
KF$3@iP2*G)M2RB8&#LRFh0iTXfaMT'5S@aDD8))aK6DZ*"9[2BV(P+51c4hG,L+
|
||||
|
||||
c53S*k44Xa8Acmd49U9R$Xk-p6,4P'e,Rh4bZH3"e6"(G$Pjab5Ikh&MNk*3JKBH
|
||||
|
||||
am`[rd,p4KJ)IdrpGAkQ!SYrdArSB+K6p(4q-kaYR%DeiK@MHTTrT+airpFpf(!c
|
||||
|
||||
C6D6hMrH[fSGq[SpSi@NLdj2ApC8!q05rrM0pH5A%p,FGr*AqP!RpYPrTjl,kIr)
|
||||
|
||||
Mrc0p)kiXJcl9Cb(1%'6hP`BRQ0MP'EU4U`lF@CCrSLp0(%#3!"HAp98B52*lSGq
|
||||
|
||||
&ZrfkrM3CD5@kEp'%2R+m!*ldPFM#f(9p0R-`C#rdT5&)cLr`#Kk#rMULrlIXZ[j
|
||||
|
||||
d'6P$Y0N+!(Y!54rDdc&h'$"brDYqB3l4$[hhr$0$4PE$2eXNb2ieb2fErJLM)1T
|
||||
|
||||
RZCa*(rQIH68r2Xk[*I+#iKreEj!!r52r-kc1XRmYjSpI3ai@B(RaKIqI,BSqG$#
|
||||
|
||||
E'MkH69X[ckB'iJEe$Qi`RhhAFB-&cq&lKKZFKRc"-D9m50)#'Z6Fp%2+jFLffS0
|
||||
|
||||
N5Tj%4@C5"GI&cC(ZFcD,h$e838lFZmM*m-eX'F$dP%A,,mqff[SF8$&N-KPiM91
|
||||
|
||||
9NF2XSa0J@f1fH(J8"hGPCVYkTSRLJ,V55r6R486P'%J,"U5PdFrVi(p*UM20Z#1
|
||||
|
||||
AjGIGE[0r"EdLeqdcjp[mNSplX,Y)hCYJ5aj0I@@G*jb-Gm65lHf-'iiR1d+aG!I
|
||||
|
||||
M4Q-YACfKpTEfZ,40CpQLY-XkZ5B+lNFp6BS(cVppFXHLm)JE3biI%jRZ4TD29iR
|
||||
|
||||
SY!R1P$QEBbjeBD*lqi'1GccMbIje'bEC1H@a56dI1a@*I@9pEqBF-qYcdaaAM`b
|
||||
|
||||
5FjP9B(QLVT*e4Aa$'kXN*T*FX[j[jrbLXcJ8Me@X&Eh%AL-JTT!!Gd4B3#S&rjI
|
||||
|
||||
6(0UBDSje*M'BT4+G-9BhC9*@-5jcH$[1@!XpJKl'$ZGDCHXmRb03ICB4reapCC!
|
||||
|
||||
!(Mqj("6&rGSNfp+B@FQGKfZV'cfXb6ZLR8&V%2h"l5[mJ8hjJPR%eT0&kPUA"r-
|
||||
|
||||
MPcHq*D-)FI[,GTp4[[$$5jiqJ&BGP+G#UkjaI6!H#dFM9NbNa28pDebXI1(,,(N
|
||||
|
||||
ED'bUV!CChjPULFDCN!"U8NG00mXke@ZV@1Ge4VY$ke-3#PpeT"PAmJT`"+9)V,N
|
||||
|
||||
pTl6IHLkVI,'RZ6PAIkpR2HXM[+GCRdK'0dVZpqGr6kpmXC'CT5KCd3'NL33K%LA
|
||||
|
||||
eT(2pQ21Q5[3dR+GDX116UUkC9$)S5UXm2KGcINq`Y6NTP421bhiMS(ba5j&Vj+N
|
||||
|
||||
6f#aTQ1JNeElPhNVPLj`GVbDV%DYQDdZbmeS[j5Xpee4GLelLG+PS4`JbeUXka[&
|
||||
|
||||
k0V$H4$f6H2FMHFHjNP0bI"Sd(Fh4'2DERk5`R-%10TmaEFjrI`$I68b$mrG)kq6
|
||||
|
||||
aHBBP*&LlQC0%8Xl9HQQfr9b!L@&XcMHPT*eJ*QI3,1Ibj`$iNqZ&q@YbPJ1Ha&!
|
||||
|
||||
Tc3P+,rc(E-IjIaGE%9QEH@4l"'92bccba&FiN!#)&l6[jHikPAbI*GrYmVe9[[I
|
||||
|
||||
)phhbr86Z2U8bGeIk!)'b%TGV)mAiNDCMGeGHc9GI%IUT&GqZ"BjUSA+ed+mA[-2
|
||||
|
||||
LXC)(FAZaC"ZB'D&IrCc3Ep!"HarI&r!YF8GmAD,SLj2'YmVA4CaPLEK2k0IH*6a
|
||||
|
||||
V*Vk$fS9GI4I"H5aL!-[(@%*ka9$HA3N5qMA()VUDA4&9YPT)mi[cZX*6&cM@eJP
|
||||
|
||||
93VpZN!!h"R3P6RiqmI$[+mN)k3@15PH6#pcRH,qPD`T@&9NVUY3'[UeNf`)(%Um
|
||||
|
||||
4l0h!LdSHK&T$P4pi$qrR04'Md+mkS'(0E3aI&)EejF*+mAAAd"56T5l"Ckd*lZ6
|
||||
|
||||
dYG-("ec$9*M3CUehlN4&9Aer+0`PT+AR#H3GeRp3FMK[%pq9er8Y223JLKM!HEY
|
||||
|
||||
N,mdU@jbA#DY@la65UhIkhK'(PTE4BPEM30kDR@@'[UIiiUc6TNIh["CTp`k2hPr
|
||||
|
||||
5`jXLjbc1QSI$eZbmE28#KdHUPIB[)RkQV95-AKqV@,pZ+bUiLHmHp@@M''(eB8f
|
||||
|
||||
f*6X2R,FYF5Vrc4ePeE6)rfDaf,5cCM&h@d69*`VTa,5qikYhmZK0Ble`+6c9aU-
|
||||
|
||||
'$C(cf9ZKQl&q68LMIi$490Bh%PU%6PbL0f'aB1Hl9(X5aT1l$Kj@l3YE82GhXer
|
||||
|
||||
JkbdqLcQ3!1Fk6iB8YmemmZL+iq,&A6dRGi493YT#@5[6iERXA%YphBr&!El1[CF
|
||||
|
||||
+&dD44l1b0lLIpNA*b0Ie[@mhS`,[c9hpkT&bXm8F@aUa0,JLKIL@V(3KLJm!)8*
|
||||
|
||||
&l+8LDUmD1G8`KVdmJ3fHfLH1XVUTHZhcb&J6TE``hq4Z-c@i`ef*B0pah)HB(K3
|
||||
|
||||
H'HbMU6,f$BBChH*)C%0(+c3dM1IjL9Re`SV`bmEQ#NIi'&Lk[$Dk84behl,DCHN
|
||||
|
||||
H16RiF'r0K2I@`Gr,ZCIaFJ8(9XVm+EKbPreGN!$mr6@mUF84qbhVQ,I8i-1$d1L
|
||||
|
||||
YqD*,(#erAVJEVY!Kh&Y92c(6UfI+c4%lZQ4ZC'U$+c`cjjFl(c$,5(pJUS`F$5#
|
||||
|
||||
EZE0`h)YZC!jHBaAMZcmFjCGm1&U$M9+Ne&j+T4(,h&)bVh&lrSC-Tmk6jY8epT%
|
||||
|
||||
+KrZQ`[0dKhfNlm)+9rKGp,K6bKpRq*MNS4mHqT0LLL3I0lp35RH%Cbk#'pph)mE
|
||||
|
||||
6[h0S,fP#'NXTD5D86d2hbhap`Y5EHAZ(lFME$j!!1d1fSr"6Rb5lf@C@BB2jcJl
|
||||
|
||||
d"Pmq29"SQ8HDhKll%9B0qe'T%Lq*l`B@mDEXREcc)d9M9,K%USLj(+VSJHQqK)Q
|
||||
|
||||
BUR$*mLCd,r",+)phKPA01S'YCFRQb(lRkmXX"TYMlpHHARDS*k*$hLm)m'`$`C@
|
||||
|
||||
&''S*&!*9bDJjS-&YYQGB2'VT%G,Cl`MTLd2Sm'j5'3C),I`f)I@3!2%1,)HU+UJ
|
||||
|
||||
[bkq[4qlc"L&GfMhFDr(rrZQrf[,p)kG15hMhd4&b@XV0CQ"E"aq41''CBqMY(fk
|
||||
|
||||
6'%db`c6B2p`N-G`b3k2E`LC4PM$L%f0jKiiA$`FdZ,h'8JHGYGjZ,MFIA,hUZ$K
|
||||
|
||||
Fiik-#KIi%CQcHi)c,(2FXEaGVJlG5DIV!UPX*XE&5&T'QM)AD5aPC#KEMpRZ(3F
|
||||
|
||||
@d#@FcrhLGd[T9XjApG)IRkldZGhZJ5-RYrVI*)HP'-lr3A8KTMck#[J2AZG[`VV
|
||||
|
||||
Jha3@r)a[((G3NfNVUYR5CUc-9'i"NmFYABR*P@C*M$5iH4*6"eEDLVfl+"l+"(8
|
||||
|
||||
@M14#qZ$f$FE-%Cr66QkRcbQN$fhIF,09`KM,jee+2Zp$4fakRpHZ&p+X)mlfR0d
|
||||
|
||||
"PD(-NB(YG[A4!D[DjheP`1FGh"ibp'lGS''H'jf"FrF4Q`L4&ES+2A+LQ%dj*8l
|
||||
|
||||
JqAe2P46cqDAU"Zq2[3hH*IV!V%Q9RJD[$Y[IcD0hlLbM[MffBNarf[!E,'IqV1S
|
||||
|
||||
aElL)9fHGF2%%2`0UDi(dPMEbbl2c%Kck4I2iE0i!RV[80kDaL&r1U`2Q5CH@"Lr
|
||||
|
||||
[j0%0QdI,$*Mbr0mIb&Vl[VlL6mAA(hfaa#pj@9j6KDPc$R)3I@Chp&h`$&mbSC-
|
||||
|
||||
1!RXIf22!RJ6fYm!H!,BEf0m"Hh*LCMEaT63VNSGE8@5Q-%`Tk#5JFa%k+H!Y`!-
|
||||
|
||||
bRJ6HK'V%dHZYf,SBN!$R'c'C1LBRd`93$,0Ui1jQlR&I`LU#Zje9!2GEQ52F,Ia
|
||||
|
||||
k)@hM(PmfejF`2MlEaQ@pYK(Kfraah#la*h*F5bXCXX8fMUr1HS@dXLKKFl&i-D,
|
||||
|
||||
KRHjGikbVar'Y9la$l2RB6pmR,LdS'+0CVLaC,H`"dT@r%Z!F2cScr3P3LVMhU0$
|
||||
|
||||
RDQ6lXmIBIJ6h2FZaT-(pd#Tr(GX$[`!BEfIS4+1rNEepHBe0*1LCXfaR!QFkYKh
|
||||
|
||||
"[C!!E89`RpfiTTEKYhU%C9l5FSYb1eVZ[NShdqFHU(5[B[`[Xmd%lNp8ZZr%``V
|
||||
|
||||
Z`-Sk2q2e,eY9c6DeamCH2MPq""hf),AJ0Z`'mAk4BHU,`2"fN@(D$$6B3eKJHLe
|
||||
|
||||
ijh+BEJhfCmrNX"X@BR0iMP35pJI3b"!RLM2TKUm#`jj4mR%B@%X1Qrhh`&k8X3q
|
||||
|
||||
"I82'4(M5h,f&[F[64H#l[1e2f"XKA3FdhPMh,0f#,XX(PR*-SARJ23cXC6*+rTj
|
||||
|
||||
($GBeQHQ,U+Ad,JkXA`G[(hJpP*%d'S#PC1a"B'rNDPDX"RC'a[6!hT)eeX&I3XE
|
||||
|
||||
f-%rDMYpUEQfrmLafmJQYmYTfr+%XjmL[Mpm65YCl'2rr!!d!#'GMG'9cG#kjZ@0
|
||||
|
||||
38%-ZZ3#3%%0D!*!3(m-!!%+&!*!%rj!%8&*25NY"5%`"!+QdiJLV-$9B!!"5l3#
|
||||
|
||||
3"K+K!*!%$I3!N!Me"!i!pCQCc1abX2*Ef-,&mj8EA@KjV4fRQfkf--,fZP@[Eld
|
||||
|
||||
Z$dq2VmN'A5Bp-hbAY9lHAJFXfQdl+AG,Z2)ME*&GEJRrA-libQIDl@-,fic`*fc
|
||||
|
||||
6K5HKhAEKE`YIq-)mEQiRK(pXXmb@iapGq-+kKCfFELT3q1c,IZ&ZXPf1@pl#b%)
|
||||
|
||||
ffjdZC,)F@FK#&m,)B+r,!D4[CPq-FBbaqZ@-eH&@A,@%-I9,M(@V+THFE3i'I@,
|
||||
|
||||
PFV%p`R[E)f,)lA5*'SmV)SBMaKm`"H(DkkSAQQdeb1%*lP8%I"Kcj(3rX&H6m0M
|
||||
|
||||
IZTkaqjrj`UCT$PZ9X*!!V`m&fSamV5GNj#ReR!CAb"Z-H0XpDBqF`ePa(%eGaiT
|
||||
|
||||
)S-2EcP+HcTr1B+bXmm9Kh'q$6Mf`X[$"KF4R$RhYV2*CXk3m49H%V`fdL)`T"cl
|
||||
|
||||
J+-2j13Fpcq@-E8&E8'&IE%H%!Ne3,pZF#1HDf2Hf""Q,&l1('*Yr8%EphJ1GXSF
|
||||
|
||||
r%JrNr)3rGBV*(aq@mf,a)FC8Kq$ER2+`6KCr)B9h0"r'+0,%0Xm[rQdqSqFB2cQ
|
||||
|
||||
eBU69f4*S4krcbhc8LClZG$iIR'*cIAh0I"abUXM3iXkAEq$(ilQ,49r!j3f+,H)
|
||||
|
||||
maNhp56c112ejNK@"P6JkPXIB&fjK8aKcR!drZX6iG+jqq&li[TdQiqM4U(!CR@&
|
||||
|
||||
rGU+(,&FBA8QAdZJ+kKT@q*eSAPdm1Mm9!Sj'C"RE!a%aQhqm(IAaK-)B'-FE!ha
|
||||
|
||||
jS(fj'%,(Uc#'FK,*f-@9@FC3113DEaI$J@M)*3)Pk"9$i'!+Qm`pccf[0,(*#J2
|
||||
|
||||
h%ZcNS8*JE#k(6ij38,[0q$[cVaRB"FIjhRDA,pSLmUCDTmXQ1P[%8(M@V%X))mK
|
||||
|
||||
*81HhL'j[ZmK(3P'46jb,ab@$h%jI@)iU6J@&a*8bd!J5%NZ'TC%NDKY",5%K9lA
|
||||
|
||||
%%1kQ%f8Z9IE(4kQ5X*9Mq!UPK%dirih2+53-k[E(m!QELQ!-Rl#ccq$6B)6Z-I`
|
||||
|
||||
FQ(52iC0Hd6f'2a&QlKPm`YDG`5GX%V)aI-*'%r+rq)3prJ`qB9260)C2f"21i"-
|
||||
|
||||
feI!B2QRI@@I`#A[5'Ic*-1NH`dIV+GeMrFY8Q(52j8mG(mdXar#TGUKe(X1R`pq
|
||||
|
||||
T1G'EYSlfTT4IFZ446jL-RfpLA2G!eYX*@kf3!1dTXPdLfkfbh5AE'fAlbB5G8j'
|
||||
|
||||
`4rJkCZFXKT(SUhpj-0jKc0+KVIl1dd)2DmAG-GY8*93X&AUb"HYJr,'#0E!H,EJ
|
||||
|
||||
1NCe#Mr)KS8HMKZmGh)rJ,V"iE"haZ#h!9,BPYJl''HE&0`Sp@9F+$qSClfFqB9h
|
||||
|
||||
h3F6FlY%JbNC43[653pSVJdcS86hQ89H[mbKL98+8Rk[YF1I00PeH*e3+2HTqAYH
|
||||
|
||||
N,LMMCc%HqGX+1SASE&1&f@&'l%0mMD%M4m1VBND`e)EiiS,VCTXD(2B'40m'rl5
|
||||
|
||||
#08#c9pE!hmAAm#U26ZK4E&E48%VR2LJ-CTF+Lq-[Q!rPj"[UJRc-'14f6EKm3Rq
|
||||
|
||||
[HC!!63aQaBb,eS*44IHY`T9#9"TN-1YJpRX&fl4AmahDMZpMp-1B4i1Br38Ef*5
|
||||
|
||||
LZGT1Yf,T@L'kG+hYpILK5iVBA1+i5A[CfL*0plhmp&KCF6DUCir(CadF[VkJLmr
|
||||
|
||||
hl$189GrN0XCQaUTQQmSPVV*HpY33GT)apN++X4le+M"i0Epbf"EcSZR0GUYL,E'
|
||||
|
||||
CL0P[#,$5,pp39-AQe,`b2HjB@cfAZmLMk)i,dH$ilTe,er+S69fpF0LG9mb$!l[
|
||||
|
||||
R31a#i(BDla#LU"ri@"l9MH5GKNUFPjh[CUb%le$F&p6Y@VGPQf+Mf`$HhiaG`0F
|
||||
|
||||
EE!CpNpCmJ'NLh(AkA6XZh4NrZ+jVe`eZK4!eX*L4F(JZ0X03ArHcH#pICpR!*Pl
|
||||
|
||||
XK4j0L8ffh'rc-KeIere1L4i-[$eMkE2E5r8'IIXP(S2Gl*Q)Zf#a'@X,Qq&K$)b
|
||||
|
||||
8&-E"[@,S'A[+pp5)VrqCMI&KiNfa[Q3Qde9lQGE01baYqAD,Zb2SkYi*qa$K!H(
|
||||
|
||||
QrQk@*rZq5ckG*6lNDIDh!N0&FHA[kK@2A1Tq5ZHFEh)rKLLeYSe0M3qAR,I8E&J
|
||||
|
||||
jY+[rT[A9)lQhp[p4)R[CAjVd`eG)q5Ap59[1Ed$+lfq3!*Xb2P4bhK@8@k6rTRj
|
||||
|
||||
JV+rq[$NqA2U`m"9NK3VKAUem9mqHIDj8lbP"PFc`j0R0lNQ*I,N$6AVCdp18*hY
|
||||
|
||||
f0%'EZEh)H$fUN6,B3ica+pmIjZHp2ebp!DT9@&,)#Mf''B9-IjQPr#f@rm`"TRV
|
||||
|
||||
fXT+Kq5E,f4-2X#q@$(82A'Tf[iND,j2dTmcpQ*4$$h,S#F8M6-VMR%F+f4IGNqB
|
||||
|
||||
J'pZ22,VGhpLkJDP%PD'3!+P'N!"h!rF@[MkB[ljcr`h&frIIb#bGV(J(mUN2X4*
|
||||
|
||||
pX9j4GNhmp4Y3'hcTK+D*KTP-YEkVC$Za8E*$BZ+*q*Y0FrMmf#+ql$LLcLXFCJU
|
||||
|
||||
2[K5SU)%*YQ!q)e6KX1%9i!l`mjL@,h-VR'U"@M4@E)Vpm1i&"NfaDF-GpbrBfZ9
|
||||
|
||||
43qpR0r'kZ8c&&BRN0640K&FKHr90+PMRPJr'GaLkK'MXKd,di#&8q%UQd23bTI"
|
||||
|
||||
9"Y@$aT[+kbSUjl2Z'0pB$phR08+dF1AJHN20YhDrGZhcfjrC,IPAlKKLCBC5[4k
|
||||
|
||||
q9Idh5c&Z18Dc[QH`6BT`b"(jr6f$$LR#)NHSe0H#a(a5Q2KG+Ee$aFHh0DPJl5(
|
||||
|
||||
93@8ePZK,p9Z@,YNC(kbfH)D&!Aj)MVPY*'C3MV'dDpHCrHTGCHB"TLM1TeLdU%9
|
||||
|
||||
-9@4Q+N-4da3eSVGlhF4QX!,1CRRd4iAX3Xj@qF4Il+k`@5b@hZfl9Y@m`Nb'kFM
|
||||
|
||||
m(e%[4TI(rJ6aDdl'AmecRb,-rM4HPmkJZV0Y@[@eEEU+cSTV%FR$LPDJFf96T)J
|
||||
|
||||
SBV95T"T4851Qcr(ieNkAfS!@ABKZ@GfXkpaZ+bYKPM*EQ4$GZVVj(+2NSbLEp4*
|
||||
|
||||
QXhjcHh'fc9U5,85T)[CflEd"+)FkYrHZ,P(Zk$8UEGDRHfh@rY@LC[fUCKAPh&$
|
||||
|
||||
@Y1rVM$T#D)9kIMCdBMTe139Pm1GfheX`RFmY90UY2l2DVI1bQkD-SR6CVHVV',Y
|
||||
|
||||
QH0(D)YCpAr&dG(pClTG)CrkkmRDVHaU[M*8KLl[iXi"f16cV#a[iKE'C33leSVV
|
||||
|
||||
cA&k$1%ZK,B8aKer)+j[dSeNDl&DqM%FeA$0FT%'A9r0mEmcBIIHPIa9riGZ2&Y4
|
||||
|
||||
)Z5bXVN6AH6jd%(9@BZSH+"mmR)p+fJ,I1r!p$0mpm2dGI$I#GaYmI`rI25-pFcj
|
||||
|
||||
Ib+CiY,#QH5B*Jb`#R#"`$J)R!Rm,r%fb2`5r!f`%81ZYQ*CVS1I,dCQD4M[6f8"
|
||||
|
||||
d%aZ`,C3pl(R%#1`5BJ$fKC34E!2I+%5,Z6XAc,!&GAHH@mc&V-9$`JriRE!1mdm
|
||||
|
||||
QBJfY6"1EAXca96'V%%d15UJ[MKrdU2JbblTde+I(r2fRV)GU*0F[GKFZ'6FZ&@C
|
||||
|
||||
!@&e$S`1V*BfZ3,[Ekc'f'QM#1TGaI6mfFAd[dRd&lTYa2mhe[DcQqPkGarAYVFD
|
||||
|
||||
pRq[EGj!!kh[Gb2@pdFVerHebVZqYjlLqJ6bZladIehI`(Ul[(a4Fhf(J[@rMqRk
|
||||
|
||||
qJHZ,jh2ph!,FAqIkPGrNqY@YA,rQDG`$A2piD5R$)dE#I+49a0+%1a6`miQp3Qa
|
||||
|
||||
bq2hBFJaMcC%A-H[Lh9kI1084#2JDa"!f3ALEk![b$C%30K$$+Rp)$+Z#lAk4M'@
|
||||
|
||||
U"BZ%FY95Keh3%Y-m5!m&aNNZUbm3$MY$+e3GhSKrHRQY-ib9%UaRb2XM&r&Bb[Q
|
||||
|
||||
$#1m2Y(MG+riPr[FUR"'4$dHFrL$[$S4iX30Jl8iIhq)0r5khhm926M)p@LJ6T9)
|
||||
|
||||
i'P,4l,[)jI1kP[&L+-6l`aiMMHaaP!k@(kR(!$5jIF64)2HV9c"fkm2Bb8M[NA,
|
||||
|
||||
5*ahe$KKB9T9'TSPBKI4**`H4UR2Kk*+M&9J[`FHC*Q&NUD#pVUA83F[45Jadk'0
|
||||
|
||||
F3Yf1$dpTM65,Hfl&AGM3!#1U'a&eQabGKF82I&eA%c-D$%HjjT%"U4TMFAb*[&A
|
||||
|
||||
h)@)HETXFRBf&$h`V0NVHj1U3!,`K#cY(qL511H*j`3MI14L%iN0H')LU%pY@kEb
|
||||
|
||||
e@+I!ap@!&jDr$K6[395bNR+a,%&ISM6!LST@Uj*V5MUX3Y#A)"$4+kM@NKY`il$
|
||||
|
||||
S30pF$R`T#q@S*(BHeKMSieHp#Flf)`,0AQTaDcb@&2)PHQQ)5fb5Xdb1cXF+!Vj
|
||||
|
||||
N8DB2,Ic5f4Kjid'T!M!XRlE0,$48%8&NcjVeLhiPLG[pfVbedR#BF'qX0CFl+(-
|
||||
|
||||
SP#2N$)DCki1*FLTMEYAMF%qMfLlECUkT+5IZR$kIUlACYmcS)YhC12(&iZ3YB9'
|
||||
|
||||
@5Q5*+ZHdkID)X$BCAmp+hXKTKT6AHm#U3r4C*hSQB(BrU*ZE[*&EJ[hH"NF&f1H
|
||||
|
||||
b`j%@Ei"`&+-i5TRYhSDUbbZ*lE"hTGJB!9#%@0JA5pj3Yh-5l&V,'fQFRq0a03C
|
||||
|
||||
$hZ956TYb(mp1hP#k+8NN)bQBbZ-#L*FT4c0ATc*h9&5!)3dB`XSCTF08SdMC5D3
|
||||
|
||||
Pj6BcCAk9Up8CNNK#jN9IDNVH8!QCSr)k39+0G(N`aFD&eSVN$99-XdNF%CZY,D(
|
||||
|
||||
`"a@L69D5SkS@&F+T)ekr#"MM-CcF0*pfUMM`5Hd-*A450pjlk`mPT8VU"Y9h0R3
|
||||
|
||||
Mi#,4b)#J'D-9V[Mh#PIqZX**-8jAH0BrUp"aT*4UR0)#8Sh6@T!!8Se6@T!!maX
|
||||
|
||||
Yd(kN"FGd1[HIG2TA[3DH,8Mf'TBDXp4V02ZFVQ8q2,U3!#'KemM%T"XRp@#KVcU
|
||||
|
||||
Y"q@f5Y+$A#aMZCD&Srj`4S3qiL3hckljPY445pa8@+b09#FYcCj'[bpc@BGcr'Q
|
||||
|
||||
!%69iq@)m[C*8URU(RG4!'ib%'PfYVS`*8j,-6"h[aReIXbG[D8k5c,e@cYh[$#h
|
||||
|
||||
lT)pilFFr65[(JLU"+N',p`QF2Y40KM[Pq2-plHN1e&CT4R@a((P61@0C"rU4'Q`
|
||||
|
||||
blVmMh8FNDTaTr9MRD@`4JjR-qSM6-pGM1,T84T8160L3!*%BDI-(2jh'hIh8YR5
|
||||
|
||||
r8BZ42Y@"2cR5GhfQ,m$+0,B(FZ(*qFCchdR[JG5Dl3[K98[0EFBhc6Jf!k'Hj$p
|
||||
|
||||
R)(rUIIG)ebZT#lVHd,,'8%3DJQ5UfdlEP"@LKiU5A8P9!ff@U2hH-(@biF`FQ[(
|
||||
|
||||
KV+6++NJeiI9JS(a#A@K@FPTGe,p@Pj4QR&)AdSc6kT,5M&2U3T15dqU5QT4mULl
|
||||
|
||||
T5FPrl#eaeipXJ`L95k4YN!"fmDV'M(FlXp`hrMJpBDZc9%XlCB(Q0M6#dJJhdpT
|
||||
|
||||
%2bZdFd30'KTT[d-6#2rA22prCQFCZHEjar[pNj2C69PYp)K@DM)V+8'fT!3C%RU
|
||||
|
||||
0$!Sc%%F&0K8NII&jQb@NScQPp1@%DKc0DD4,rDbV-ccd@PV(lCAPY$H4%a*G2UI
|
||||
|
||||
ARl'MdM)(c3+5MpDF8)f1Rr4*kNc)faB*9I4DMcVDlZfJPej1UXfAEck8RMde1"C
|
||||
|
||||
Ci0@')p(QjN#S(A*Mr%a[J*8"E)T3G!%pL5YhHBl+"RVj4bhpa)5,Y@G#d)*M[FH
|
||||
|
||||
rp@3IGap(N9*kF+TlbrUSQrlA5IIaD[aidXeYj&CVNMH83&CM+!&9RaC+%&Q"[`%
|
||||
|
||||
!PM5C'9(,)ph(*fUTr9!YMqT9DV2iP&iGfErj4+r'r8D[mMkHFibb02iMPNjf1PA
|
||||
|
||||
[d("$VLh(CI8d(p1LX&VN*cJbP(8k[pfF2kE#ZPqTX(51-%LC%ZXU[a22)[*i8[E
|
||||
|
||||
rZJ[cIcUGL4G#pHMBk,e2kCF0VX,2PP#E5Iik[#T1$qmHrqXJc[6'Fa2`XLUETTM
|
||||
|
||||
$*YV-$D3cYp12%m#qEb(qhJ$feL8eGE5PqJMF0!YqXU&'QZAY39+9b(8[r8`"-MX
|
||||
|
||||
Ah$6![T!!ITF!pTb'bfV*EbNA&PMaKL[H#UA+i@kTX"!qGeH&C3R&EkCI&X"$k6d
|
||||
|
||||
9PN9@f#m[VUY"R%+aB%N90%@4PhahPUZj([c3IkY-$A%eUr''+[Q8"m(LQS3[kcE
|
||||
|
||||
1G+!PiF[1j8b6mBiYqG4I![EZK'rFji"Ab"55leDmdYV+9*,[$[MHa&2kj,XIH(K
|
||||
|
||||
90KkIa-Ep'I$!Tj5(&h&2b4cN`,G2pSf$$kqZ5Vi*m(hh+pHLCV(B#pqMEAp*2`L
|
||||
|
||||
K$S-ce482X[1!F4&mDd`jE#EL`-(e-DD6q,X(FCd12IXm1+#IdU#-2SFi1q)HB*d
|
||||
|
||||
54KI`ANVie'C`8jVJFZTNa%85A%ip'ebqP1"bkZr$jj-acJ0'8-Di!,i@'@-Q-2E
|
||||
|
||||
*q68KTiMXZ`ja[9RqCFj@hp%rG"RpQjINMlqNrpQ&-qA@"ki53rAP&2rr!!!0$3p
|
||||
|
||||
YGbpRBh4PFh3Z0MK,,VN!N""453#3%#pd!!"+8`#3"2q3"%e08&*0680$!3#V,jH
|
||||
|
||||
ZUc!jB!!!"M%!!"R%!!!"V3!!"E(*MaZS!*!'[VXM4!iL+Pj0j%)PIdhl9fbRBC!
|
||||
|
||||
!DR1(JAFp3hUJ2KNcZ@(k&LeHlIYc*cMM1X2GRCf"!*`N(81C&iAQNTm4&Ifii1"
|
||||
|
||||
EpGII4h6#PiP+'R-jb[e$&IeM12rA3hh-XBk+D2XK9#@U!P9e!@eRU22XRT!!%ar
|
||||
|
||||
%6jaP3[FjFKhiIjQ@hidE$&25cAm$`-IrIXai*1U*jZd88q%pXX1%F$M`RNJbAQS
|
||||
|
||||
ih%%N0J*@A""6p[pE#%1,cL9X%K8j[Z%i38$F)*'R%8!QpTQQT&06TCMf4amme9+
|
||||
|
||||
jii[1iC(HE43E%aa#QlrCjZ4[GSL(8*!!e8D-E"#r6LR@&GN3aF6F'028K*cdTGk
|
||||
|
||||
aT$fkUhhK6F,P(Tj11!CFTLJ+QQSXDINp,M$RL-+Cm9q6j"VK+Hr'rhrjXB16b1@
|
||||
|
||||
iec&AC&Z,)bAP)A[QZNkT`brFF9bj0@L(b*(4H3)$i*YCbh9`YK90aj%$0a!Gm&!
|
||||
|
||||
,de[B3!XlC'%$"-Eme,D0'(Z229-8DlB`9Q$FC!Y6@9L'KA%@PQm[")V0YM#PKBP
|
||||
|
||||
$[mI#m!L#i#MfjAH50i4eE512Q3bj@@90I4m!N!--!'XcXfpJlh2Ij$4lRaZHF-P
|
||||
|
||||
a`Tr-D)4&@%FjIAiV9hi5rZ3i@3NqRhV5`hI'm8m[3MNjENHi%AjN`!NMR"`rbB$
|
||||
|
||||
bTrc)FA,m$%r*F51Fm*03FTa`FTa`-Q#%%hlN'4R`Pa`RA(+FF+mMamRa)mq2m$2
|
||||
|
||||
#bB!#GjN8B'@Y6-+0iUpN*rl)-F)*2m)*8[#%!j-9H"9SN!!()1QkKK#+`Hm@K$S
|
||||
|
||||
HJ&m,rN[#E`hmIJLEJ,q0bk)PQTCS@&q4J@q@4d"9U,FU)md-(0Yrf-'kLSC3Ech
|
||||
|
||||
QTZ6PDfM!,6kXTJh48"8c3%-B$Af2ZR8CG9Ip2$-35k-p#&9[4Zd)$4`EE%%G46!
|
||||
|
||||
,R0"9-23T99CN34j4,-#2%@HJ4P(6T'aDQa#N[iMDX5G2a3J5j8hqU`G8AI)J-HU
|
||||
|
||||
[2pc+8DXTel3Q5K1DDDe`rC'MeMLS#5QV5"2QC-jFKV@(Y,XiDUf$'TI6Q941+fY
|
||||
|
||||
NIrEXmabeMLSdTZC&6Ae8m48krm8h(,@HFXdUSU`BRMk!q[lRHBlD3,RQ4#QENT@
|
||||
|
||||
#"cXRI2X+4ie6jif)dMfM+mkEUadrc9%E(G5'h+TKlGFqRHHS#3He,LFDrPe`h($
|
||||
|
||||
QCBlDa(3e*P+'jG["RP9riDM0,PI9V"`8d09SikJYP'YH1C5kHVfHlZ'SDkKIpI4
|
||||
|
||||
i+LIkaJ28)bpbe,88e9!N694cCG6ZNqFjkMUUN!"T6DE6ZT(h&AViKGmikRVU"NX
|
||||
|
||||
TAdR(H9q1FY4@bY@D,XL9SfF2rY6286HiPp,*+'9G,aJIFG50p#Uce14Gj3Y'd81
|
||||
|
||||
Ek"h5cFV&)blrQ+1f8B8b8UTJU&0#eN-9cVh+8GXGe*U-j!-kU)P6p4b9*UB'dj*
|
||||
|
||||
PCDb-E#IIrF$K4qBkCkfIRK)eFi@ZrFEXr4ae-h@$T1I(e%`C&K,!AUi3T&L#1U`
|
||||
|
||||
I'P&bCG3h(rRp#Fje+d8&50fBrKHeFp&j@4Q5M3GV$pea1eGSfk+(0$9pa80R1GF
|
||||
|
||||
ZCkfce*a5FDbGI1mKMRSpifUSq482fFRj!BlD6Id+#UPkaDr(MfcMU0YGVSSeRLY
|
||||
|
||||
8Z0V[F05H43q4)19lk0aM"lL(GMKViS"LkT1'T(MH+rPeTkZ3!*U"!([&H8FjkLl
|
||||
|
||||
+0@RS306mKfX[64ZJ+`31D"5@fGUaCaUiVRd8Y@!C+5NVP42Ef6h&a0E[S,D5e*Z
|
||||
|
||||
k$e*4k[,4R"1qUq@S0cKV-k$Hk86c@fiEqT2V*rYSlLHcfePEppip1YM9Hl2Del9
|
||||
|
||||
2!&`"@TQ,U#F1&[Z''jdelZ4b1(ZHmdimH"0(45eR)(&!*q9f)f6q6PCX0VTUBad
|
||||
|
||||
IAd$pf!@`[ik1Br'KUlR)+fakrN"cHF(H36)2h%jb&H(+NrX0&jMF9VMIj$*$&L)
|
||||
|
||||
T"p)0cLf`Yq1%"AXR6JQ`Yq'FKMf0GB,GdbRXPYLiZ+lq4#IBL8k`%jeJ*cV"6R5
|
||||
|
||||
#RHJ%1p%*GU)6l%3Rf)P1h%qc#+[@Y15RS-eL8qhT&"fJcd&k4dVkK,dC'pb'AVi
|
||||
|
||||
MRZjKXmB'HccD3(IrcJ8G(KYmfk)&p1R"5Hkrqa'fKQc`$Bdfm0&Ek'dF5*Cm&25
|
||||
|
||||
6E"T+qQc(16M5i"iI4FpKHCCb3p#-XSR6I3[1YF$(e@dVrAm(hAhGA,f#1a4fVQ`
|
||||
|
||||
D)a0bM1IcX19PNiJXd-QrQrjp$rTP0Nh4$ljDEE6C0*GdfSPEQNJ$[AaI"9dkQjE
|
||||
|
||||
)"&rjZ5PSlpQXL6c)65I42'&jkHi((6HE659pGY(F%GhJrk#CBp-AQC!!QcfG`RF
|
||||
|
||||
BE0C'2GbTm18(Qh@4"hI+cbI"'a-fkb-2I05,Qq*VI86`ZS90Dq6"IEUNPpZrZ6d
|
||||
|
||||
IkmP@hp@`f9$5UmK,"LjZ2dGjKIdd'pTRSrf,Re6[[[HdcbYXX0R3aK[KcVI)#mr
|
||||
|
||||
A-dm"R8jJFcLjAc2T0r!1Xr%Ph(NRKdhm"Y1PM9qd9#9(PFc#![X)[SNKr!e@jAm
|
||||
|
||||
!N!-0$3pYGbpRBh4PFh3Z8&"$,VN!N"!4c!#3%%+&!*!)rj!%68e38Ne33d-"!+X
|
||||
|
||||
[PkkV-$P&!!!'-3!!'Z!!!!'T!!!&bE5F%03!N!B"fL0%$L)UANhN3L9r6IYAE+G
|
||||
|
||||
KN!"UFiH"Gce$HU!q'61jBIV#iB$[cjhJM1X-GhH'!`%ib6Q'-Lm+c58r)bVkFF(
|
||||
|
||||
"YqU[[irS4$#9MENFjIkKL[iaR2rVS6lQ@%G&Y2d3UK*9JDUkJ,Bce(Pf6fJm&6R
|
||||
|
||||
b2Z8HRJiXa'A+ir""h#2TreqK*11PKX-G4'@dI[MrP@fl(cXiL9b1Haec4BbeKmP
|
||||
|
||||
aeJj"iNA$iL1d#Y1J+HR89#QQrG%86l98l[LLFhLNlhad)NaL2JK&0pZFr-d1m4!
|
||||
|
||||
+XYS)fcSm[diTeKAC%-A8h"M6e)5Fp+AHXD3p1ZNm1FY%rabj$[`E!$0bi`E$P26
|
||||
|
||||
rG@!p"$aQr-JXH*CjLX,-Um9UPGj1-5VH)fY@`*(4VHaDSf,&r6CPrlq&--R1K6X
|
||||
|
||||
*#r!9a`Q#"HZ@0$hdcLR&Z$Fm-LN%a%6I)NG'j`NF&EkCY9`(CaX9iFL4(fpK!IC
|
||||
|
||||
B8#c-*P,XP1dG-@D4KE%@0XR#9"C'PcdhhF,ZXE"3#eYVB3-&a[CDHNU"FB-@YXI
|
||||
|
||||
#PPJD!bcX5f0T(aH0)DaV'hR-C-M0+Q[Uq``!Da0l'f3fmMSr"jhCCQZ%N3NRNdf
|
||||
|
||||
14LJRP"rPR[a@3Sqr%8D1NjAJmk5Hp2#G-Ic6Le"1MJm)Pachb(2###I(6c*J%8k
|
||||
|
||||
j%8k1RiHRj,J46[K*+$P11$P11"P3`JNrmS`-q)!-Z'6!D6eKj2L4C`f-F$+J`(8
|
||||
|
||||
Q"D$m9QE4e,T1r"&qK,q%%k6J#3FQ+c!qS%%HJ+LU#N)S",rE%'S`i2Fjq"D$ha,
|
||||
|
||||
iI4qf+2P[K53BJQi)Q['&0I#IjBQL)Y4CP"42pjcUHm,'ZSf'8'HBF--Ck@qdLS0
|
||||
|
||||
b3K-d'HXH'L*+S#ZS9C93Dp(hThY##E32SH*'Y!@KRP2p0@MV!TJ"6QM*DZUi,'%
|
||||
|
||||
T+JeJ!r"$PM03TD!SBLUKM%E&Qd60d0-c)3Z*mVDqK3&9&I13!!6eTfr[iUM&P'Y
|
||||
|
||||
#%F4446G@Z(l(88YXe)LB`Z+S2TE@Pf(0!mTp(,A84Uf3!",*H&STD'4qmZcc(,@
|
||||
|
||||
-+M3XC`4&IJbl#Phql%Z1'UCF8eL3!,#@e`G3hrdd`e(,+GHd)+EL%XlQBDHLAlh
|
||||
|
||||
-85ZSm`B%mB'K&HG0PBjFj+L90QTjHXf`jUXI6h28L)eDPKBdpblBE[Mm*BjDaA6
|
||||
|
||||
94Z1DiGV"R*4rj+M9$PGCAcdSS+ZfQD2@8+iCI$4qqhSpdmj4DkPIeF4)2#fiaJ2
|
||||
|
||||
8Bbpbe(889F1L)XMT!QVVKFXFYBiUT"YMLB5UC9b&(RhKCikkRVV"`)8VDEQKZf-
|
||||
|
||||
V4kfRA)f*V,4kp-cqUedFGB0c+Hf-8Y$eQ[B"4pe)Vc*,6IQVI%eEm0!QHSG8IIA
|
||||
|
||||
L@5lrN!#MEUCQhhrr8(p,Ec3@kie#4,V"pIbK)a`9-T!!GBlk-`E@KJ84,f%LG'i
|
||||
|
||||
f[T!!!'KLUKNie$XiPM(N0&lQH[KU'dGYS"j+L['X*Sp(8hPGSl0R1'UMM9U5&&e
|
||||
|
||||
!'c8b%qDSN!"L,3rTKL6Ki3+b'A[l2CZI0G[Y06`a,LMk#PhcpFQ(1'S6pDZSCSE
|
||||
|
||||
PC!&fUR[r&Uj3-eASS(Td!+F,U1H1r2)8jpT#83&5e5EZS1kBGej+JZb9Kc82h(-
|
||||
|
||||
h9kKehN1+R,MPS8ZFDjZpPPPABF@aCZbG`abeRA(9j-b+KmcBG!p(lD"q"B9NGG@
|
||||
|
||||
[CimeFp5G$PGXM+5cUec0YcMUVRN2@9(2pG$Xii2F3jhf'KR%ZMUQL6M[[CaIGcX
|
||||
|
||||
+b8Q)f,HFGj+MGP'Z-8d&S[SrA2I32!5k3L5#cQ1CV4NkAXjer4pehS"JT*BMJmh
|
||||
|
||||
eq+jHMVUAFXdD@Pa-LB8NHQRI3K)PI3p-0D6jHqhb!-,0lkJIrAq#kpTYIkZh1S$
|
||||
|
||||
iJj!!%H0,"hSUqR8TjiTU6d$LH!3qd"l'QVp5(*Z0MQj%N5IR8$IK#2YVk#b4%AU
|
||||
|
||||
KAhRjVG*[D*cA0T*HB1mJp`hf9R+*B@mR9a,f0R*MBGp1mJVX655"`0j)XK,X1mL
|
||||
|
||||
pKlf"*+irG2*l,$B1E[#"6T2S$,#X@[56ejba+FlV&"bJcm2dMZ6dm6Xk0U4jAES
|
||||
|
||||
MHGhp&Sp0DH#"lZkGmrT#0Q@"!rVX)TRXhr[K0j4X`S%(2RS$[3RXDKCpj(@KE-T
|
||||
|
||||
cqZ`NL6E3i"kI4160319LE["D@$B9G'mQ#4Ai1,Ued1qGG(GeFr6blT!!hqqbU3a
|
||||
|
||||
-b$&jRrZ0-TY)B)&1lYedll[ACE1T#Rl`e9TlcUBkTp0ZdVF%-H4Z[lGR8a1Bi#X
|
||||
|
||||
h0hN["GM8"KlNTJYSfQ*jrHjlI6UE66PpZQMZ#'l`[pH@XGNEQ*!!Qr-kq@mqf+`
|
||||
|
||||
,HVK6rLX60R@""hI+c5IHHaBfk`-2I,5(G,jrpK(H5aSfpB%(pqQkANlrj[4mV#G
|
||||
|
||||
EHm2$CN01V`9H%R"aqMR+bhpj`iDqe%&p8bAIR!qTj%[4$kpFY(MK'lcmYcPXk&Z
|
||||
|
||||
H1lcmlTi0lIT[mPVbJIFUL!elGjRM4BM8c8"+#$@"@kr%qK5GrJGH8d5JeDSp%6Z
|
||||
|
||||
S`aY94TZmpLQ+$H(Nh"cl%r`RK-KrL#Vr!3#3!aq$!!!"!*!$!43!N!-8!*!$-Tr
|
||||
|
||||
lRLe!rr#`!,K[$#eZd!6rm2rdd"lm`FAKdkSV8FY+$deKBe"bEfTPBh4c,R0TG!)
|
||||
|
||||
!N!06594%8dP8)3#3"P0*9%46593K!*!BUc!jI3!!8M8!!!&'"1"2l'mDG@6JrHc
|
||||
|
||||
K@5U#NI*HN@GK!Z"2kQ`FG&2UN!"S!!,L@5[48(adA`CdC!EJ6qj[8hJS!!EJEHl
|
||||
|
||||
LEe5!)D$!FJC1ANl!*IrX51FI-#D`jL63G!*&0K!+1Li!&Ri!)VX-S"lbUKQJ(Z`
|
||||
|
||||
3!+SDI!$!#3ZT8,aIE!!!Q$!'8!6"aG!!N!-3!#X!"3%B!J#3"`-!N!-"!*!$!43
|
||||
|
||||
!N!-8!*!$-J$j(l!@#J#3!a`!-J!!8f9dC`#3!`S!!2rr!*!&q@G%'@B:
|
||||
|
||||
91
src/engine/boehm_gc/Mac_files/MacOS_Test_config.h
Normal file
91
src/engine/boehm_gc/Mac_files/MacOS_Test_config.h
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
MacOS_Test_config.h
|
||||
|
||||
Configuration flags for Macintosh development systems.
|
||||
|
||||
Test version.
|
||||
|
||||
<Revision History>
|
||||
|
||||
11/16/95 pcb Updated compilation flags to reflect latest 4.6 Makefile.
|
||||
|
||||
by Patrick C. Beard.
|
||||
*/
|
||||
/* Boehm, November 17, 1995 12:05 pm PST */
|
||||
|
||||
#ifdef __MWERKS__
|
||||
|
||||
// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
|
||||
// #define MSL_USE_PRECOMPILED_HEADERS 0
|
||||
#include <ansi_prefix.mac.h>
|
||||
#ifndef __STDC__
|
||||
#define __STDC__ 0
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
// these are defined again in gc_priv.h.
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
|
||||
#define ALL_INTERIOR_POINTERS // follows interior pointers.
|
||||
//#define SILENT // want collection messages.
|
||||
//#define DONT_ADD_BYTE_AT_END // no padding.
|
||||
//#define SMALL_CONFIG // whether to a smaller heap.
|
||||
#define NO_SIGNALS // signals aren't real on the Macintosh.
|
||||
#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
|
||||
|
||||
// CFLAGS= -O -DNO_SIGNALS -DALL_INTERIOR_POINTERS -DSILENT
|
||||
//
|
||||
//LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
|
||||
// -DREDIRECT_MALLOC=GC_malloc_uncollectable \
|
||||
// -DDONT_ADD_BYTE_AT_END -DALL_INTERIOR_POINTERS
|
||||
// Flags for building libgc.a -- the last two are required.
|
||||
//
|
||||
// Setjmp_test may yield overly optimistic results when compiled
|
||||
// without optimization.
|
||||
// -DSILENT disables statistics printing, and improves performance.
|
||||
// -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
|
||||
// altered stubborn objects, at substantial performance cost.
|
||||
// Use only for incremental collector debugging.
|
||||
// -DFIND_LEAK causes the collector to assume that all inaccessible
|
||||
// objects should have been explicitly deallocated, and reports exceptions.
|
||||
// Finalization and the test program are not usable in this mode.
|
||||
// -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
|
||||
// (Clients should also define SOLARIS_THREADS and then include
|
||||
// gc.h before performing thr_ or GC_ operations.)
|
||||
// This is broken on nonSPARC machines.
|
||||
// -DALL_INTERIOR_POINTERS allows all pointers to the interior
|
||||
// of objects to be recognized. (See gc_priv.h for consequences.)
|
||||
// -DSMALL_CONFIG tries to tune the collector for small heap sizes,
|
||||
// usually causing it to use less space in such situations.
|
||||
// Incremental collection no longer works in this case.
|
||||
// -DLARGE_CONFIG tunes the collector for unusually large heaps.
|
||||
// Necessary for heaps larger than about 500 MB on most machines.
|
||||
// Recommended for heaps larger than about 64 MB.
|
||||
// -DDONT_ADD_BYTE_AT_END is meaningful only with
|
||||
// -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
|
||||
// causes all objects to be padded so that pointers just past the end of
|
||||
// an object can be recognized. This can be expensive. (The padding
|
||||
// is normally more than one byte due to alignment constraints.)
|
||||
// -DDONT_ADD_BYTE_AT_END disables the padding.
|
||||
// -DNO_SIGNALS does not disable signals during critical parts of
|
||||
// the GC process. This is no less correct than many malloc
|
||||
// implementations, and it sometimes has a significant performance
|
||||
// impact. However, it is dangerous for many not-quite-ANSI C
|
||||
// programs that call things like printf in asynchronous signal handlers.
|
||||
// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
|
||||
// new syntax "operator new[]" for allocating and deleting arrays.
|
||||
// See gc_cpp.h for details. No effect on the C part of the collector.
|
||||
// This is defined implicitly in a few environments.
|
||||
// -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined
|
||||
// as aliases for X, GC_realloc, and GC_free, respectively.
|
||||
// Calloc is redefined in terms of the new malloc. X should
|
||||
// be either GC_malloc or GC_malloc_uncollectable.
|
||||
// The former is occasionally useful for working around leaks in code
|
||||
// you don't want to (or can't) look at. It may not work for
|
||||
// existing code, but it often does. Neither works on all platforms,
|
||||
// since some ports use malloc or calloc to obtain system memory.
|
||||
// (Probably works for UNIX, and win32.)
|
||||
// -DNO_DEBUG removes GC_dump and the debugging routines it calls.
|
||||
// Reduces code size slightly at the expense of debuggability.
|
||||
89
src/engine/boehm_gc/Mac_files/MacOS_config.h
Normal file
89
src/engine/boehm_gc/Mac_files/MacOS_config.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
MacOS_config.h
|
||||
|
||||
Configuration flags for Macintosh development systems.
|
||||
|
||||
<Revision History>
|
||||
|
||||
11/16/95 pcb Updated compilation flags to reflect latest 4.6 Makefile.
|
||||
|
||||
by Patrick C. Beard.
|
||||
*/
|
||||
/* Boehm, November 17, 1995 12:10 pm PST */
|
||||
|
||||
#ifdef __MWERKS__
|
||||
|
||||
// for CodeWarrior Pro with Metrowerks Standard Library (MSL).
|
||||
// #define MSL_USE_PRECOMPILED_HEADERS 0
|
||||
#include <ansi_prefix.mac.h>
|
||||
#ifndef __STDC__
|
||||
#define __STDC__ 0
|
||||
#endif
|
||||
|
||||
#endif /* __MWERKS__ */
|
||||
|
||||
// these are defined again in gc_priv.h.
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
|
||||
#define ALL_INTERIOR_POINTERS // follows interior pointers.
|
||||
#define SILENT // no collection messages.
|
||||
//#define DONT_ADD_BYTE_AT_END // no padding.
|
||||
//#define SMALL_CONFIG // whether to use a smaller heap.
|
||||
#define NO_SIGNALS // signals aren't real on the Macintosh.
|
||||
#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
|
||||
|
||||
// CFLAGS= -O -DNO_SIGNALS -DSILENT -DALL_INTERIOR_POINTERS
|
||||
//
|
||||
//LIBGC_CFLAGS= -O -DNO_SIGNALS -DSILENT \
|
||||
// -DREDIRECT_MALLOC=GC_malloc_uncollectable \
|
||||
// -DDONT_ADD_BYTE_AT_END -DALL_INTERIOR_POINTERS
|
||||
// Flags for building libgc.a -- the last two are required.
|
||||
//
|
||||
// Setjmp_test may yield overly optimistic results when compiled
|
||||
// without optimization.
|
||||
// -DSILENT disables statistics printing, and improves performance.
|
||||
// -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
|
||||
// altered stubborn objects, at substantial performance cost.
|
||||
// Use only for incremental collector debugging.
|
||||
// -DFIND_LEAK causes the collector to assume that all inaccessible
|
||||
// objects should have been explicitly deallocated, and reports exceptions.
|
||||
// Finalization and the test program are not usable in this mode.
|
||||
// -DSOLARIS_THREADS enables support for Solaris (thr_) threads.
|
||||
// (Clients should also define SOLARIS_THREADS and then include
|
||||
// gc.h before performing thr_ or GC_ operations.)
|
||||
// This is broken on nonSPARC machines.
|
||||
// -DALL_INTERIOR_POINTERS allows all pointers to the interior
|
||||
// of objects to be recognized. (See gc_priv.h for consequences.)
|
||||
// -DSMALL_CONFIG tries to tune the collector for small heap sizes,
|
||||
// usually causing it to use less space in such situations.
|
||||
// Incremental collection no longer works in this case.
|
||||
// -DLARGE_CONFIG tunes the collector for unusually large heaps.
|
||||
// Necessary for heaps larger than about 500 MB on most machines.
|
||||
// Recommended for heaps larger than about 64 MB.
|
||||
// -DDONT_ADD_BYTE_AT_END is meaningful only with
|
||||
// -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
|
||||
// causes all objects to be padded so that pointers just past the end of
|
||||
// an object can be recognized. This can be expensive. (The padding
|
||||
// is normally more than one byte due to alignment constraints.)
|
||||
// -DDONT_ADD_BYTE_AT_END disables the padding.
|
||||
// -DNO_SIGNALS does not disable signals during critical parts of
|
||||
// the GC process. This is no less correct than many malloc
|
||||
// implementations, and it sometimes has a significant performance
|
||||
// impact. However, it is dangerous for many not-quite-ANSI C
|
||||
// programs that call things like printf in asynchronous signal handlers.
|
||||
// -DGC_OPERATOR_NEW_ARRAY declares that the C++ compiler supports the
|
||||
// new syntax "operator new[]" for allocating and deleting arrays.
|
||||
// See gc_cpp.h for details. No effect on the C part of the collector.
|
||||
// This is defined implicitly in a few environments.
|
||||
// -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined
|
||||
// as aliases for X, GC_realloc, and GC_free, respectively.
|
||||
// Calloc is redefined in terms of the new malloc. X should
|
||||
// be either GC_malloc or GC_malloc_uncollectable.
|
||||
// The former is occasionally useful for working around leaks in code
|
||||
// you don't want to (or can't) look at. It may not work for
|
||||
// existing code, but it often does. Neither works on all platforms,
|
||||
// since some ports use malloc or calloc to obtain system memory.
|
||||
// (Probably works for UNIX, and win32.)
|
||||
// -DNO_DEBUG removes GC_dump and the debugging routines it calls.
|
||||
// Reduces code size slightly at the expense of debuggability.
|
||||
9
src/engine/boehm_gc/Mac_files/dataend.c
Normal file
9
src/engine/boehm_gc/Mac_files/dataend.c
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
dataend.c
|
||||
|
||||
A hack to get the extent of global data for the Macintosh.
|
||||
|
||||
by Patrick C. Beard.
|
||||
*/
|
||||
|
||||
long __dataend;
|
||||
9
src/engine/boehm_gc/Mac_files/datastart.c
Normal file
9
src/engine/boehm_gc/Mac_files/datastart.c
Normal file
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
datastart.c
|
||||
|
||||
A hack to get the extent of global data for the Macintosh.
|
||||
|
||||
by Patrick C. Beard.
|
||||
*/
|
||||
|
||||
long __datastart;
|
||||
107
src/engine/boehm_gc/Makefile.DLLs
Normal file
107
src/engine/boehm_gc/Makefile.DLLs
Normal file
@@ -0,0 +1,107 @@
|
||||
#-----------------------------------------------------------------------------#
|
||||
|
||||
# Makefile.DLLs, version 0.4.
|
||||
|
||||
# Contributed by Fergus Henderson.
|
||||
|
||||
# This Makefile contains rules for creating DLLs on Windows using gnu-win32.
|
||||
|
||||
#-----------------------------------------------------------------------------#
|
||||
|
||||
# This rule creates a `.def' file, which lists the symbols that are exported
|
||||
# from the DLL. We use `nm' to get a list of all the exported text (`T')
|
||||
# symbols and data symbols -- including uninitialized data (`B'),
|
||||
# initialized data (`D'), read-only data (`R'), and common blocks (`C').
|
||||
%.def: %.a
|
||||
echo EXPORTS > $@
|
||||
nm $< | grep '^........ [BCDRT] _' | sed 's/[^_]*_//' >> $@
|
||||
|
||||
# We need to use macros to access global data:
|
||||
# the user of the DLL must refer to `foo' as `(*__imp_foo)'.
|
||||
# This rule creates a `_globals.h' file, which contains macros
|
||||
# for doing this.
|
||||
|
||||
SYM_PREFIX = $(firstword $(SYM_PREFIX-$*) $*)
|
||||
DLL_MACRO = $(SYM_PREFIX)_USE_DLL
|
||||
IMP_MACRO = $(SYM_PREFIX)_IMP
|
||||
GLOBAL_MACRO = $(SYM_PREFIX)_GLOBAL
|
||||
|
||||
%_globals.h: %.a
|
||||
echo "/* automatically generated by Makefile.DLLs */" > $@
|
||||
echo "#if defined(__GNUC__) && defined(_WIN32) \\" >> $@
|
||||
echo " && defined($(DLL_MACRO))" >> $@
|
||||
echo "# define $(IMP_MACRO)(name) __imp_##name" >> $@
|
||||
echo "# define $(GLOBAL_MACRO)(name) (*$(IMP_MACRO)(name))" >> $@
|
||||
echo "#else" >> $@
|
||||
echo "# define $(GLOBAL_MACRO)(name) name" >> $@
|
||||
echo "#endif" >> $@
|
||||
echo "" >> $@
|
||||
for sym in `nm $< | grep '^........ [BCDR] _' | sed 's/[^_]*_//'`; do \
|
||||
echo "#define $$sym $(GLOBAL_MACRO)($$sym)" >> $@; \
|
||||
done
|
||||
|
||||
# This rule creates the export object file (`foo.exp') which contains the
|
||||
# jump table array; this export object file becomes part of the DLL.
|
||||
# This rule also creates the import library (`foo_dll.a') which contains small
|
||||
# stubs for all the functions exported by the DLL which jump to them via the
|
||||
# jump table. Executables that will use the DLL must be linked against this
|
||||
# stub library.
|
||||
%.exp %_dll.a : %.def
|
||||
dlltool $(DLLTOOLFLAGS) $(DLLTOOLFLAGS-$*) \
|
||||
--def $< \
|
||||
--dllname $*.dll \
|
||||
--output-exp $*.exp \
|
||||
--output-lib $*_dll.a
|
||||
|
||||
# The `sed' commands below are to convert DOS-style `C:\foo\bar'
|
||||
# pathnames into Unix-style `//c/foo/bar' pathnames.
|
||||
CYGWIN32_LIBS = $(shell echo \
|
||||
-L`dirname \`gcc -print-file-name=libgcc.a | \
|
||||
sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
|
||||
-L`dirname \`gcc -print-file-name=libcygwin.a | \
|
||||
sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
|
||||
-L`dirname \`gcc -print-file-name=libkernel32.a | \
|
||||
sed -e 's@^\\\\([A-Za-z]\\\\):@//\\\\1@g' -e 's@\\\\\\\\@/@g' \` ` \
|
||||
-lgcc -lcygwin -lkernel32 -lgcc)
|
||||
|
||||
RELOCATABLE=yes
|
||||
|
||||
ifeq "$(strip $(RELOCATABLE))" "yes"
|
||||
|
||||
# to create relocatable DLLs, we need to do two passes
|
||||
%.dll: %.exp %.a dll_fixup.o dll_init.o
|
||||
$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $*.base \
|
||||
-e _dll_entry@12 dll_init.o \
|
||||
dll_fixup.o $*.exp $*.a \
|
||||
$(LDLIBS) $(LDLIBS-$*) \
|
||||
$(CYGWIN32_LIBS)
|
||||
$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll --base-file $*.base -o $@ \
|
||||
-e _dll_entry@12 dll_init.o \
|
||||
dll_fixup.o $*.exp $*.a \
|
||||
$(LDLIBS) $(LDLIBS-$*) \
|
||||
$(CYGWIN32_LIBS)
|
||||
rm -f $*.base
|
||||
else
|
||||
|
||||
%.dll: %.exp %.a dll_fixup.o dll_init.o
|
||||
$(LD) $(LDFLAGS) $(LDFLAGS-$*) --dll -o $@ \
|
||||
-e _dll_entry@12 dll_init.o \
|
||||
dll_fixup.o $*.exp $*.a \
|
||||
$(LDLIBS) $(LDLIBS-$*) \
|
||||
$(CYGWIN32_LIBS)
|
||||
|
||||
endif
|
||||
|
||||
# This black magic piece of assembler needs to be linked in in order to
|
||||
# properly terminate the list of imported DLLs.
|
||||
dll_fixup.s:
|
||||
echo '.section .idata$$3' > dll_fixup.s
|
||||
echo '.long 0,0,0,0, 0,0,0,0' >> dll_fixup.s
|
||||
|
||||
# This bit is necessary to provide an initialization function for the DLL.
|
||||
dll_init.c:
|
||||
echo '__attribute__((stdcall))' > dll_init.c
|
||||
echo 'int dll_entry(int handle, int reason, void *ptr)' >> dll_init.c
|
||||
echo '{return 1; }' >> dll_init.c
|
||||
|
||||
dont_throw_away: dll_fixup.o dll_init.o
|
||||
206
src/engine/boehm_gc/Makefile.am
Normal file
206
src/engine/boehm_gc/Makefile.am
Normal file
@@ -0,0 +1,206 @@
|
||||
# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
#
|
||||
# Permission is hereby granted to use or copy this program
|
||||
# for any purpose, provided the above notices are retained on all copies.
|
||||
# Permission to modify the code and to distribute modified code is granted,
|
||||
# provided the above notices are retained, and a notice that the code was
|
||||
# modified is included with the above copyright notice.
|
||||
#
|
||||
# Original author: Tom Tromey
|
||||
# Severely truncated by Hans-J. Boehm
|
||||
# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
|
||||
# Modified by: Petter Urkedal <petter.urkedal@nordita.dk> (2005-04)
|
||||
|
||||
## Process this file with automake to produce Makefile.in.
|
||||
|
||||
## FIXME: `make distcheck' in this directory will not currently work.
|
||||
## This is most likely to the explicit flags passed to submakes.
|
||||
|
||||
# We currently use the source files directly from libatomic_ops, if we
|
||||
# use the internal version. This is done since libatomic_ops doesn't
|
||||
# use libtool, since it has no real use for it. But that seems to make
|
||||
# it hard to use either the resulting object files or libraries.
|
||||
# Thus there seems too be no real reason to recusively build in the
|
||||
# libatomic_ops directory.
|
||||
# if USE_INTERNAL_LIBATOMICS_OPS
|
||||
# SUBDIRS = @maybe_libatomic_ops@
|
||||
# else
|
||||
# SUBDIRS =
|
||||
# endif
|
||||
SUBDIRS =
|
||||
|
||||
# Initialize variables so that we can declare files locally.
|
||||
EXTRA_DIST =
|
||||
lib_LTLIBRARIES =
|
||||
include_HEADERS =
|
||||
pkginclude_HEADERS =
|
||||
dist_noinst_HEADERS =
|
||||
check_PROGRAMS =
|
||||
TESTS =
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
dist_pkgconfig_DATA = bdw-gc.pc
|
||||
|
||||
# C Library
|
||||
# ---------
|
||||
|
||||
lib_LTLIBRARIES += libgc.la
|
||||
libgc_la_SOURCES = \
|
||||
allchblk.c alloc.c blacklst.c checksums.c dbg_mlc.c \
|
||||
dyn_load.c finalize.c gc_dlopen.c gcj_mlc.c headers.c \
|
||||
malloc.c mallocx.c mark.c mark_rts.c misc.c new_hblk.c \
|
||||
obj_map.c os_dep.c pcr_interface.c ptr_chck.c real_malloc.c reclaim.c \
|
||||
specific.c stubborn.c typd_mlc.c \
|
||||
backgraph.c thread_local_alloc.c
|
||||
|
||||
# C Library: Architecture Dependent
|
||||
# ---------------------------------
|
||||
|
||||
if PTHREADS
|
||||
libgc_la_SOURCES += pthread_support.c pthread_stop_world.c
|
||||
endif
|
||||
|
||||
if DARWIN_THREADS
|
||||
libgc_la_SOURCES += darwin_stop_world.c
|
||||
endif
|
||||
|
||||
if WIN32_THREADS
|
||||
libgc_la_SOURCES += win32_threads.c
|
||||
endif
|
||||
|
||||
if USE_INTERNAL_LIBATOMIC_OPS
|
||||
nodist_libgc_la_SOURCES = atomic_ops.c
|
||||
endif
|
||||
|
||||
if NEED_ATOMIC_OPS_ASM
|
||||
nodist_libgc_la_SOURCES = atomic_ops_sysdeps.S
|
||||
endif
|
||||
|
||||
# Include THREADDLLIBS here to ensure that the correct versions of
|
||||
# linuxthread semaphore functions get linked:
|
||||
libgc_la_LIBADD = @addobjs@ $(THREADDLLIBS) $(UNWINDLIBS)
|
||||
libgc_la_DEPENDENCIES = @addobjs@
|
||||
libgc_la_LDFLAGS = $(extra_ldflags_libgc) -version-info 1:3:0 -no-undefined
|
||||
|
||||
EXTRA_libgc_la_SOURCES = alpha_mach_dep.S \
|
||||
mips_sgi_mach_dep.s mips_ultrix_mach_dep.s \
|
||||
rs6000_mach_dep.s sparc_mach_dep.S sparc_netbsd_mach_dep.s \
|
||||
sparc_sunos4_mach_dep.s ia64_save_regs_in_stack.s
|
||||
|
||||
|
||||
# C++ Interface
|
||||
# -------------
|
||||
|
||||
if CPLUSPLUS
|
||||
lib_LTLIBRARIES += libgccpp.la
|
||||
pkginclude_HEADERS += include/gc_cpp.h include/gc_allocator.h
|
||||
libgccpp_la_SOURCES = gc_cpp.cc
|
||||
libgccpp_la_LIBADD = $(top_builddir)/libgc.la
|
||||
libgccpp_la_LDFLAGS = -version-info 1:3:0 -no-undefined
|
||||
endif
|
||||
|
||||
# FIXME: If Visual C++ users use Makefile.am, this should go into
|
||||
# pkginclude_HEADERS with proper AM_CONDITIONALization. Otherwise
|
||||
# delete this comment.
|
||||
EXTRA_DIST += gc_cpp.cpp
|
||||
|
||||
|
||||
# Misc
|
||||
# ----
|
||||
|
||||
AM_CXXFLAGS = @GC_CFLAGS@
|
||||
AM_CFLAGS = @GC_CFLAGS@
|
||||
|
||||
## FIXME: relies on internal code generated by automake.
|
||||
## FIXME: ./configure --enable-dependency-tracking should be used
|
||||
#all_objs = @addobjs@ $(libgc_la_OBJECTS)
|
||||
#$(all_objs) : include/private/gcconfig.h include/private/gc_priv.h \
|
||||
#include/private/gc_hdrs.h include/gc.h include/gc_gcj.h \
|
||||
#include/gc_pthread_redirects.h include/gc_config_macros.h \
|
||||
#include/private/thread_local_alloc.h include/private_support.h \
|
||||
#include/private/pthread_stop_world.h \
|
||||
#include/gc_mark.h @addincludes@
|
||||
|
||||
## FIXME: we shouldn't have to do this, but automake forces us to.
|
||||
## We use -Wp,-P to strip #line directives. Irix `as' chokes on
|
||||
## these.
|
||||
if COMPILER_XLC
|
||||
## XLC neither requires nor tolerates the unnecessary assembler goop
|
||||
ASM_CPP_OPTIONS =
|
||||
else
|
||||
## We use -Wp,-P to strip #line directives. Irix `as' chokes on
|
||||
## these.
|
||||
ASM_CPP_OPTIONS = -Wp,-P -x assembler-with-cpp
|
||||
endif
|
||||
.s.lo:
|
||||
$(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $<
|
||||
|
||||
.S.lo:
|
||||
$(LTCOMPILE) $(ASM_CPP_OPTIONS) -c $<
|
||||
|
||||
## We need to add DEFS to assembler flags
|
||||
## :FIXME: what if assembler does not accept -D... ?
|
||||
## (use Autoconf to prepare ASDEFS ???)
|
||||
|
||||
CCASFLAGS += $(DEFS)
|
||||
|
||||
dist_noinst_SCRIPTS = callprocs configure.host
|
||||
## callprocs --- used by Makefile.{dj,direct}
|
||||
## configure.host --- used by Makefile.{am,dj,direct}
|
||||
|
||||
# headers which are not installed
|
||||
# (see include/include.am for more)
|
||||
#
|
||||
dist_noinst_HEADERS += version.h
|
||||
|
||||
# documentation which is not installed
|
||||
#
|
||||
EXTRA_DIST += README.QUICK
|
||||
|
||||
# other makefiles
|
||||
# :GOTCHA: deliberately we do not include 'Makefile'
|
||||
EXTRA_DIST += BCC_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE \
|
||||
OS2_MAKEFILE PCR-Makefile digimars.mak EMX_MAKEFILE \
|
||||
Makefile.direct Makefile.dj Makefile.DLLs SMakefile.amiga \
|
||||
WCC_MAKEFILE configure_atomic_ops.sh \
|
||||
NT_STATIC_THREADS_MAKEFILE NT_X64_STATIC_THREADS_MAKEFILE
|
||||
|
||||
# files used by makefiles other than Makefile.am
|
||||
#
|
||||
EXTRA_DIST += add_gc_prefix.c gcname.c if_mach.c if_not_there.c \
|
||||
hpux_test_and_clear.s gc.mak MacOS.c \
|
||||
MacProjects.sit.hqx mach_dep.c setjmp_t.c \
|
||||
threadlibs.c AmigaOS.c \
|
||||
Mac_files/datastart.c Mac_files/dataend.c \
|
||||
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
|
||||
include/private/msvc_dbg.h msvc_dbg.c
|
||||
|
||||
# The libatomic_ops library. This is not ideal, since we pick up junk from
|
||||
# there. The hard-coded version number should also go.
|
||||
EXTRA_DIST += libatomic_ops-1.2
|
||||
|
||||
# this is an auxiliary shell file used by Makefile and Makefile.direct
|
||||
#
|
||||
CONFIG_STATUS_DEPENDENCIES = $(srcdir)/configure.host
|
||||
|
||||
# :FIXME: why do we distribute this one???
|
||||
#
|
||||
EXTRA_DIST += libtool.m4
|
||||
|
||||
#
|
||||
# :GOTCHA: GNU make rule for making .s out of .S is flawed,
|
||||
# it will not remove dest if building fails
|
||||
.S.s:
|
||||
if $(CPP) $< >$@ ; then :; else rm -f $@; fi
|
||||
|
||||
include include/include.am
|
||||
include cord/cord.am
|
||||
include tests/tests.am
|
||||
include doc/doc.am
|
||||
# Putting these at the top causes cord to be built first, and not find libgc.a
|
||||
# on HP/UX. There may be a better fix.
|
||||
|
||||
|
||||
737
src/engine/boehm_gc/Makefile.direct
Normal file
737
src/engine/boehm_gc/Makefile.direct
Normal file
@@ -0,0 +1,737 @@
|
||||
# This is the original manually generated Makefile. It may still be used
|
||||
# to build the collector.
|
||||
#
|
||||
# Primary targets:
|
||||
# gc.a - builds basic library
|
||||
# c++ - adds C++ interface to library
|
||||
# cords - adds cords (heavyweight strings) to library
|
||||
# test - prints porting information, then builds basic version of gc.a,
|
||||
# and runs some tests of collector and cords. Does not add cords or
|
||||
# c++ interface to gc.a
|
||||
# cord/de - builds dumb editor based on cords.
|
||||
ABI_FLAG=
|
||||
# ABI_FLAG should be the cc flag that specifies the ABI. On most
|
||||
# platforms this will be the empty string. Possible values:
|
||||
# +DD64 for 64-bit executable on HP/UX.
|
||||
# -n32, -n64, -o32 for SGI/MIPS ABIs.
|
||||
|
||||
AS_ABI_FLAG=$(ABI_FLAG)
|
||||
# ABI flag for assembler. On HP/UX this is +A64 for 64 bit
|
||||
# executables.
|
||||
|
||||
CC=cc $(ABI_FLAG)
|
||||
CXX=g++ $(ABI_FLAG)
|
||||
AS=as $(AS_ABI_FLAG)
|
||||
# The above doesn't work with gas, which doesn't run cpp.
|
||||
# Define AS as `gcc -c -x assembler-with-cpp' instead.
|
||||
|
||||
# Redefining srcdir allows object code for the nonPCR version of the collector
|
||||
# to be generated in different directories.
|
||||
srcdir= .
|
||||
VPATH= $(srcdir)
|
||||
|
||||
# Atomic_ops installation directory. If this doesn't exist, we create
|
||||
# it from the included libatomic_ops distribution.
|
||||
AO_VERSION=1.2
|
||||
AO_SRC_DIR=$(srcdir)/libatomic_ops-$(AO_VERSION)
|
||||
AO_INSTALL_DIR=$(srcdir)/libatomic_ops-install
|
||||
|
||||
CFLAGS= -O -I$(srcdir)/include -I$(AO_INSTALL_DIR)/include -DATOMIC_UNCOLLECTABLE -DNO_EXECUTE_PERMISSION -DALL_INTERIOR_POINTERS
|
||||
|
||||
# To build the parallel collector on Linux, add to the above:
|
||||
# -DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC
|
||||
# To build the thread-capable preload library that intercepts
|
||||
# malloc, add -DGC_USE_DLOPEN_WRAP -DREDIRECT_MALLOC=GC_malloc -fpic
|
||||
# To build the parallel collector in a static library on HP/UX,
|
||||
# add to the above:
|
||||
# -DGC_HPUX_THREADS -DTHREAD_LOCAL_ALLOC -D_POSIX_C_SOURCE=199506L -mt
|
||||
# FIXME: PARALLEL_MARK currently broken on HP/UX.
|
||||
# To build the thread-safe collector on Tru64, add to the above:
|
||||
# -pthread -DGC_OSF1_THREADS
|
||||
|
||||
# HOSTCC and HOSTCFLAGS are used to build executables that will be run as
|
||||
# part of the build process, i.e. on the build machine. These will usually
|
||||
# be the same as CC and CFLAGS, except in a cross-compilation environment.
|
||||
# Note that HOSTCFLAGS should include any -D flags that affect thread support.
|
||||
HOSTCC=$(CC)
|
||||
HOSTCFLAGS=$(CFLAGS)
|
||||
|
||||
# For dynamic library builds, it may be necessary to add flags to generate
|
||||
# PIC code, e.g. -fPIC on Linux.
|
||||
|
||||
# Setjmp_test may yield overly optimistic results when compiled
|
||||
# without optimization.
|
||||
|
||||
# These define arguments influence the collector configuration:
|
||||
# -DFIND_LEAK causes GC_find_leak to be initially set.
|
||||
# This causes the collector to assume that all inaccessible
|
||||
# objects should have been explicitly deallocated, and reports exceptions.
|
||||
# Finalization and the test program are not usable in this mode.
|
||||
#
|
||||
# IMPORTANT: Any of the _THREADS options must normally also be defined in
|
||||
# the client before including gc.h. This redefines thread primitives to
|
||||
# invoke the GC_ versions instead. Alternatively, linker-based symbol
|
||||
# interception can be used on a few platforms.
|
||||
# -DGC_THREADS should set the appropriate one of the below macros,
|
||||
# except -DGC_WIN32_PTHREADS, which must be set explicitly.
|
||||
# -DGC_SOLARIS_PTHREADS enables support for Solaris pthreads.
|
||||
# (Clients should also define GC_SOLARIS_THREADS and then include
|
||||
# gc.h before performing thr_ or dl* or GC_ operations.)
|
||||
# Must also define -D_REENTRANT.
|
||||
# -DGC_IRIX_THREADS enables support for Irix pthreads. See README.irix.
|
||||
# -DGC_HPUX_THREADS enables support for HP/UX 11 pthreads.
|
||||
# Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp.
|
||||
# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads
|
||||
# or NPTL threads. See README.linux. -D_REENTRANT may also be required.
|
||||
# -DGC_OSF1_THREADS enables support for Tru64 pthreads.
|
||||
# -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads.
|
||||
# Appeared to run into some underlying thread problems.
|
||||
# -DGC_DARWIN_THREADS enables support for Mac OS X pthreads.
|
||||
# -DGC_AIX_THREADS enables support for IBM AIX threads.
|
||||
# -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads.
|
||||
# See README.DGUX386. (Probably has not been tested recently.)
|
||||
# -DGC_WIN32_THREADS enables support for win32 threads. That makes sense
|
||||
# for this Makefile only under Cygwin.
|
||||
# -DGC_WIN32_PTHREADS enables support for Ming32 pthreads. This cannot be
|
||||
# enabled automatically by GC_THREADS, which would assume Win32 native
|
||||
# threads.
|
||||
# -DPTW32_STATIC_LIB causes the static version of the Mingw pthreads library
|
||||
# to be used. Requires -DGC_WIN32_PTHREADS.
|
||||
#
|
||||
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
|
||||
# of objects to be recognized. (See gc_priv.h for consequences.)
|
||||
# Alternatively, GC_all_interior_pointers can be set at process
|
||||
# initialization time.
|
||||
# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
|
||||
# usually causing it to use less space in such situations.
|
||||
# Incremental collection no longer works in this case.
|
||||
# -DLARGE_CONFIG tunes the collector for unusually large heaps.
|
||||
# Necessary for heaps larger than about 500 MB on most machines.
|
||||
# Recommended for heaps larger than about 64 MB.
|
||||
# -DDONT_ADD_BYTE_AT_END is meaningful only with -DALL_INTERIOR_POINTERS or
|
||||
# GC_all_interior_pointers = 1. Normally -DALL_INTERIOR_POINTERS
|
||||
# causes all objects to be padded so that pointers just past the end of
|
||||
# an object can be recognized. This can be expensive. (The padding
|
||||
# is normally more than one byte due to alignment constraints.)
|
||||
# -DDONT_ADD_BYTE_AT_END disables the padding.
|
||||
# -DNO_EXECUTE_PERMISSION may cause some or all of the heap to not
|
||||
# have execute permission, i.e. it may be impossible to execute
|
||||
# code from the heap. Currently this only affects the incremental
|
||||
# collector on UNIX machines. It may greatly improve its performance,
|
||||
# since this may avoid some expensive cache synchronization.
|
||||
# -DGC_NO_OPERATOR_NEW_ARRAY declares that the C++ compiler does not support
|
||||
# the new syntax "operator new[]" for allocating and deleting arrays.
|
||||
# See gc_cpp.h for details. No effect on the C part of the collector.
|
||||
# This is defined implicitly in a few environments. Must also be defined
|
||||
# by clients that use gc_cpp.h.
|
||||
# -DREDIRECT_MALLOC=X causes malloc to be defined as alias for X.
|
||||
# Unless the following macros are defined, realloc is also redirected
|
||||
# to GC_realloc, and free is redirected to GC_free.
|
||||
# Calloc and strdup are redefined in terms of the new malloc. X should
|
||||
# be either GC_malloc or GC_malloc_uncollectable, or
|
||||
# GC_debug_malloc_replacement. (The latter invokes GC_debug_malloc
|
||||
# with dummy source location information, but still results in
|
||||
# properly remembered call stacks on Linux/X86 and Solaris/SPARC.
|
||||
# It requires that the following two macros also be used.)
|
||||
# The former is occasionally useful for working around leaks in code
|
||||
# you don't want to (or can't) look at. It may not work for
|
||||
# existing code, but it often does. Neither works on all platforms,
|
||||
# since some ports use malloc or calloc to obtain system memory.
|
||||
# (Probably works for UNIX, and win32.) If you build with DBG_HDRS_ALL,
|
||||
# you should only use GC_debug_malloc_replacement as a malloc
|
||||
# replacement.
|
||||
# -DREDIRECT_REALLOC=X causes GC_realloc to be redirected to X.
|
||||
# The canonical use is -DREDIRECT_REALLOC=GC_debug_realloc_replacement,
|
||||
# together with -DREDIRECT_MALLOC=GC_debug_malloc_replacement to
|
||||
# generate leak reports with call stacks for both malloc and realloc.
|
||||
# This also requires the following:
|
||||
# -DREDIRECT_FREE=X causes free to be redirected to X. The
|
||||
# canonical use is -DREDIRECT_FREE=GC_debug_free.
|
||||
# -DIGNORE_FREE turns calls to free into a noop. Only useful with
|
||||
# -DREDIRECT_MALLOC.
|
||||
# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
|
||||
# Reduces code size slightly at the expense of debuggability.
|
||||
# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
|
||||
# order by specifying a nonstandard finalization mark procedure (see
|
||||
# finalize.c). Objects reachable from finalizable objects will be marked
|
||||
# in a separate postpass, and hence their memory won't be reclaimed.
|
||||
# Not recommended unless you are implementing a language that specifies
|
||||
# these semantics. Since 5.0, determines only the initial value
|
||||
# of GC_java_finalization variable.
|
||||
# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response
|
||||
# to explicit GC_invoke_finalizers() calls.
|
||||
# In 5.0 this became runtime adjustable, and this only determines the
|
||||
# initial value of GC_finalize_on_demand.
|
||||
# -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
|
||||
# This is useful if either the vendor malloc implementation is poor,
|
||||
# or if REDIRECT_MALLOC is used.
|
||||
# -DMARK_BIT_PER_GRANULE requests that a mark bit (or often byte)
|
||||
# be allocated for each allocation granule, as opposed to each object.
|
||||
# This often improves speed, possibly at some cost in space and/or
|
||||
# cache footprint. Normally it is best to let this decision be
|
||||
# made automatically depending on platform.
|
||||
# -DMARK_BIT_PER_OBJ requests that a mark bit be allocated for each
|
||||
# object instead of allocation granule. The opposiet of
|
||||
# MARK_BIT_PER_GRANULE.
|
||||
# -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly
|
||||
# sets the heap block size. Each heap block is devoted to a single size and
|
||||
# kind of object. For the incremental collector it makes sense to match
|
||||
# the most likely page size. Otherwise large values result in more
|
||||
# fragmentation, but generally better performance for large heaps.
|
||||
# -DUSE_MMAP use MMAP instead of sbrk to get new memory.
|
||||
# Works for Solaris and Irix.
|
||||
# -DUSE_MUNMAP causes memory to be returned to the OS under the right
|
||||
# circumstances. This currently disables VM-based incremental collection.
|
||||
# This is currently experimental, and works only under some Unix,
|
||||
# Linux and Windows versions.
|
||||
# -DMMAP_STACKS (for Solaris threads) Use mmap from /dev/zero rather than
|
||||
# GC_scratch_alloc() to get stack memory.
|
||||
# -DPRINT_BLACK_LIST Whenever a black list entry is added, i.e. whenever
|
||||
# the garbage collector detects a value that looks almost, but not quite,
|
||||
# like a pointer, print both the address containing the value, and the
|
||||
# value of the near-bogus-pointer. Can be used to identifiy regions of
|
||||
# memory that are likely to contribute misidentified pointers.
|
||||
# -DKEEP_BACK_PTRS Add code to save back pointers in debugging headers
|
||||
# for objects allocated with the debugging allocator. If all objects
|
||||
# through GC_MALLOC with GC_DEBUG defined, this allows the client
|
||||
# to determine how particular or randomly chosen objects are reachable
|
||||
# for debugging/profiling purposes. The gc_backptr.h interface is
|
||||
# implemented only if this is defined.
|
||||
# -DGC_ASSERTIONS Enable some internal GC assertion checking. Currently
|
||||
# this facility is only used in a few places. It is intended primarily
|
||||
# for debugging of the garbage collector itself, but could also
|
||||
# -DDBG_HDRS_ALL Make sure that all objects have debug headers. Increases
|
||||
# the reliability (from 99.9999% to 100% mod. bugs) of some of the debugging
|
||||
# code (especially KEEP_BACK_PTRS). Makes -DSHORT_DBG_HDRS possible.
|
||||
# Assumes that all client allocation is done through debugging
|
||||
# allocators.
|
||||
# -DSHORT_DBG_HDRS Assume that all objects have debug headers. Shorten
|
||||
# the headers to minimize object size, at the expense of checking for
|
||||
# writes past the end of an object. This is intended for environments
|
||||
# in which most client code is written in a "safe" language, such as
|
||||
# Scheme or Java. Assumes that all client allocation is done using
|
||||
# the GC_debug_ functions, or through the macros that expand to these,
|
||||
# or by redirecting malloc to GC_debug_malloc_replacement.
|
||||
# (Also eliminates the field for the requested object size.)
|
||||
# occasionally be useful for debugging of client code. Slows down the
|
||||
# collector somewhat, but not drastically.
|
||||
# -DSAVE_CALL_COUNT=<n> Set the number of call frames saved with objects
|
||||
# allocated through the debugging interface. Affects the amount of
|
||||
# information generated in leak reports. Only matters on platforms
|
||||
# on which we can quickly generate call stacks, currently Linux/(X86 & SPARC)
|
||||
# and Solaris/SPARC and platforms that provide execinfo.h.
|
||||
# Default is zero. On X86, client
|
||||
# code should NOT be compiled with -fomit-frame-pointer.
|
||||
# -DSAVE_CALL_NARGS=<n> Set the number of functions arguments to be
|
||||
# saved with each call frame. Default is zero. Ignored if we
|
||||
# don't know how to retrieve arguments on the platform.
|
||||
# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
|
||||
# altered stubborn objects, at substantial performance cost.
|
||||
# Use only for debugging of the incremental collector.
|
||||
# -DGC_GCJ_SUPPORT includes support for gcj (and possibly other systems
|
||||
# that include a pointer to a type descriptor in each allocated object).
|
||||
# Building this way requires an ANSI C compiler.
|
||||
# -DUSE_I686_PREFETCH causes the collector to issue Pentium III style
|
||||
# prefetch instructions. No effect except on X86 Linux platforms.
|
||||
# Assumes a very recent gcc-compatible compiler and assembler.
|
||||
# (Gas prefetcht0 support was added around May 1999.)
|
||||
# Empirically the code appears to still run correctly on Pentium II
|
||||
# processors, though with no performance benefit. May not run on other
|
||||
# X86 processors? In some cases this improves performance by
|
||||
# 15% or so.
|
||||
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
|
||||
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
|
||||
# Minimally tested. Didn't appear to be an obvious win on a K6-2/500.
|
||||
# -DUSE_PPC_PREFETCH causes the collector to issue PowerPC style
|
||||
# prefetch instructions. No effect except on PowerPC OS X platforms.
|
||||
# Performance impact untested.
|
||||
# -DGC_USE_LD_WRAP in combination with the old flags listed in README.linux
|
||||
# causes the collector some system and pthread calls in a more transparent
|
||||
# fashion than the usual macro-based approach. Requires GNU ld, and
|
||||
# currently probably works only with Linux.
|
||||
# -DGC_USE_DLOPEN_WRAP causes the collector to redefine malloc and intercepted
|
||||
# pthread routines with their real names, and causes it to use dlopen
|
||||
# and dlsym to refer to the original versions. This makes it possible to
|
||||
# build an LD_PRELOADable malloc replacement library.
|
||||
# -DTHREAD_LOCAL_ALLOC defines GC_malloc(), GC_malloc_atomic()
|
||||
# and GC_gcj_malloc() to use a per-thread set of free-lists.
|
||||
# These then allocate in a way that usually does not involve
|
||||
# acquisition of a global lock. Currently supported only on platforms
|
||||
# such as Linux that use pthread_support.c. Recommended for multiprocessors.
|
||||
# Requires explicit GC_INIT() call, unless REDIRECT_MALLOC is
|
||||
# defined and GC_malloc is used first.
|
||||
# -DUSE_COMPILER_TLS causes thread local allocation to use compiler-supported
|
||||
# "__thread" thread-local variables. This is the default in HP/UX. It
|
||||
# may help performance on recent Linux installations. (It failed for
|
||||
# me on RedHat 8, but appears to work on RedHat 9.)
|
||||
# -DPARALLEL_MARK allows the marker to run in multiple threads. Recommended
|
||||
# for multiprocessors. Currently requires Linux on X86 or IA64, though
|
||||
# support for other Posix platforms should be fairly easy to add,
|
||||
# if the thread implementation is otherwise supported.
|
||||
# -DNO_GETENV prevents the collector from looking at environment variables.
|
||||
# These may otherwise alter its configuration, or turn off GC altogether.
|
||||
# I don't know of a reason to disable this, except possibly if the
|
||||
# resulting process runs as a privileged user?
|
||||
# -DUSE_GLOBAL_ALLOC. Win32 only. Use GlobalAlloc instead of
|
||||
# VirtualAlloc to allocate the heap. May be needed to work around
|
||||
# a Windows NT/2000 issue. Incompatible with USE_MUNMAP.
|
||||
# See README.win32 for details.
|
||||
# -DMAKE_BACK_GRAPH. Enable GC_PRINT_BACK_HEIGHT environment variable.
|
||||
# See README.environment for details. Experimental. Limited platform
|
||||
# support. Implies DBG_HDRS_ALL. All allocation should be done using
|
||||
# the debug interface.
|
||||
# -DSTUBBORN_ALLOC allows allocation of "hard to change" objects, and thus
|
||||
# makes incremental collection easier. Was enabled by default until 6.0.
|
||||
# Rarely used, to my knowledge.
|
||||
# -DHANDLE_FORK attempts to make GC_malloc() work in a child process fork()ed
|
||||
# from a multithreaded parent. Currently only supported by pthread_support.c.
|
||||
# (Similar code should work on Solaris or Irix, but it hasn't been tried.)
|
||||
# -DTEST_WITH_SYSTEM_MALLOC causes gctest to allocate (and leak) large chunks
|
||||
# of memory with the standard system malloc. This will cause the root
|
||||
# set and collected heap to grow significantly if malloced memory is
|
||||
# somehow getting traced by the collector. This has no impact on the
|
||||
# generated library; it only affects the test.
|
||||
# -DNO_INCREMENTAL cases the gctest program to not invoke the incremental
|
||||
# collector. This has no impact on the generated library, only on the
|
||||
# test program. (This is often useful for debugging failures unrelated
|
||||
# to incremental GC.)
|
||||
# -DPOINTER_MASK=0x... causes candidate pointers to be ANDed with the
|
||||
# given mask before being considered. If either this or the following
|
||||
# macro is defined, it will be assumed that all pointers stored in
|
||||
# the heap need to be processed this way. Stack and register pointers
|
||||
# will be considered both with and without processing.
|
||||
# These macros are normally needed only to support systems that use
|
||||
# high-order pointer tags. EXPERIMENTAL.
|
||||
# -DPOINTER_SHIFT=n causes the collector to left shift candidate pointers
|
||||
# by the indicated amount before trying to interpret them. Applied
|
||||
# after POINTER_MASK. EXPERIMENTAL. See also the preceding macro.
|
||||
# -DENABLE_TRACE enables the GC_TRACE=addr environment setting to do its
|
||||
# job. By default this is not supported in order to keep the marker as fast
|
||||
# as possible.
|
||||
# -DDARWIN_DONT_PARSE_STACK Causes the Darwin port to discover thread
|
||||
# stack bounds in the same way as other pthread ports, without trying to
|
||||
# walk the frames onthe stack. This is recommended only as a fallback
|
||||
# for applications that don't support proper stack unwinding.
|
||||
# -DUSE_PROC_FOR_LIBRARIES Causes the Linux collector to treat writable
|
||||
# memory mappings (as reported by /proc) as roots, if it doesn't have
|
||||
# otherinformation about them. It no longer traverses dynamic loader
|
||||
# data structures to find dynamic library static data. This may be
|
||||
# required for applications that store pointers in mmapped segments without
|
||||
# informaing the collector. But it typically performs poorly, especially
|
||||
# since it will scan inactive but cached NPTL thread stacks completely.
|
||||
#
|
||||
|
||||
CXXFLAGS= $(CFLAGS)
|
||||
AR= ar
|
||||
RANLIB= ranlib
|
||||
|
||||
|
||||
OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o \
|
||||
headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o \
|
||||
malloc.o stubborn.o checksums.o pthread_support.o pthread_stop_world.o \
|
||||
darwin_stop_world.o typd_mlc.o ptr_chck.o mallocx.o gcj_mlc.o specific.o \
|
||||
gc_dlopen.o backgraph.o win32_threads.o thread_local_alloc.o
|
||||
|
||||
CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c \
|
||||
headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c \
|
||||
new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c \
|
||||
checksums.c pthread_support.c pthread_stop_world.c darwin_stop_world.c \
|
||||
typd_mlc.c ptr_chck.c mallocx.c gcj_mlc.c specific.c gc_dlopen.c \
|
||||
backgraph.c win32_threads.c thread_local_alloc.c
|
||||
|
||||
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC
|
||||
|
||||
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
|
||||
|
||||
SRCS= $(CSRCS) mips_sgi_mach_dep.s rs6000_mach_dep.s alpha_mach_dep.S \
|
||||
sparc_mach_dep.S include/gc.h include/gc_typed.h include/gc_tiny_fl.h \
|
||||
include/private/gc_hdrs.h include/private/gc_priv.h \
|
||||
include/private/gcconfig.h include/private/gc_pmark.h \
|
||||
include/gc_inline.h include/gc_mark.h \
|
||||
threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
|
||||
gcname.c include/weakpointer.h include/private/gc_locks.h \
|
||||
mips_ultrix_mach_dep.s \
|
||||
include/new_gc_alloc.h include/gc_allocator.h \
|
||||
include/javaxfc.h sparc_sunos4_mach_dep.s sparc_netbsd_mach_dep.s \
|
||||
include/gc_backptr.h \
|
||||
hpux_test_and_clear.s include/gc_gcj.h \
|
||||
include/private/dbg_mlc.h \
|
||||
include/private/specific.h \
|
||||
include/leak_detector.h include/gc_amiga_redirects.h \
|
||||
include/gc_pthread_redirects.h ia64_save_regs_in_stack.s \
|
||||
include/gc_config_macros.h include/private/pthread_support.h \
|
||||
include/private/pthread_stop_world.h include/private/darwin_semaphore.h \
|
||||
include/private/darwin_stop_world.h include/private/thread_local_alloc.h \
|
||||
$(CORD_SRCS)
|
||||
|
||||
DOC_FILES= README.QUICK doc/README.Mac doc/README.MacOSX doc/README.OS2 \
|
||||
doc/README.amiga doc/README.cords doc/debugging.html \
|
||||
doc/porting.html doc/overview.html \
|
||||
doc/README.dj doc/README.hp doc/README.linux doc/README.rs6000 \
|
||||
doc/README.sgi doc/README.solaris2 doc/README.uts \
|
||||
doc/README.win32 doc/barrett_diagram doc/README \
|
||||
doc/README.contributors doc/README.changes doc/gc.man \
|
||||
doc/README.environment doc/tree.html doc/gcdescr.html \
|
||||
doc/README.autoconf doc/README.macros doc/README.ews4800 \
|
||||
doc/README.DGUX386 doc/README.arm.cross doc/leak.html \
|
||||
doc/scale.html doc/gcinterface.html doc/README.darwin \
|
||||
doc/simple_example.html doc/README.win64
|
||||
|
||||
TESTS= tests/test.c tests/test_cpp.cc tests/trace_test.c \
|
||||
tests/leak_test.c tests/thread_leak_test.c tests/middle.c
|
||||
|
||||
GNU_BUILD_FILES= configure.ac Makefile.am configure acinclude.m4 \
|
||||
libtool.m4 install-sh configure.host Makefile.in \
|
||||
aclocal.m4 config.sub config.guess \
|
||||
include/include.am doc/doc.am \
|
||||
ltmain.sh mkinstalldirs depcomp missing \
|
||||
cord/cord.am tests/tests.am autogen.sh \
|
||||
bdw-gc.pc.in compile
|
||||
|
||||
OTHER_MAKEFILES= OS2_MAKEFILE NT_MAKEFILE NT_THREADS_MAKEFILE gc.mak \
|
||||
BCC_MAKEFILE EMX_MAKEFILE WCC_MAKEFILE Makefile.dj \
|
||||
PCR-Makefile SMakefile.amiga Makefile.DLLs \
|
||||
digimars.mak Makefile.direct NT_STATIC_THREADS_MAKEFILE \
|
||||
NT_X64_STATIC_THREADS_MAKEFILE configure_atomic_ops.sh
|
||||
# Makefile and Makefile.direct are copies of each other.
|
||||
|
||||
OTHER_FILES= Makefile setjmp_t.c callprocs \
|
||||
MacProjects.sit.hqx MacOS.c \
|
||||
Mac_files/datastart.c Mac_files/dataend.c \
|
||||
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
|
||||
add_gc_prefix.c gc_cpp.cpp \
|
||||
version.h AmigaOS.c mscvc_dbg.c include/private/msvc_dbg.h \
|
||||
$(TESTS) $(GNU_BUILD_FILES) $(OTHER_MAKEFILES)
|
||||
|
||||
CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
|
||||
$(srcdir)/include/ec.h $(srcdir)/include/private/cord_pos.h
|
||||
|
||||
UTILS= if_mach if_not_there threadlibs
|
||||
|
||||
# Libraries needed for curses applications. Only needed for de.
|
||||
CURSES= -lcurses -ltermlib
|
||||
|
||||
# The following is irrelevant on most systems. But a few
|
||||
# versions of make otherwise fork the shell specified in
|
||||
# the SHELL environment variable.
|
||||
SHELL= /bin/sh
|
||||
|
||||
SPECIALCFLAGS = -I$(srcdir)/include -I$(AO_INSTALL_DIR)/include
|
||||
# Alternative flags to the C compiler for mach_dep.c.
|
||||
# Mach_dep.c often doesn't like optimization, and it's
|
||||
# not time-critical anyway.
|
||||
# Set SPECIALCFLAGS to -q nodirect_code on Encore.
|
||||
|
||||
all: gc.a gctest
|
||||
|
||||
# if AO_INSTALL_DIR doesn't exist, we assume that it is pointing to
|
||||
# the default location, and we need to build
|
||||
$(AO_INSTALL_DIR):
|
||||
CC=$(CC) $(srcdir)/configure_atomic_ops.sh
|
||||
cd $(AO_SRC_DIR); make CC=$(CC) install
|
||||
|
||||
LEAKFLAGS=$(CFLAGS) -DFIND_LEAK
|
||||
|
||||
BSD-pkg-all: bsd-libgc.a bsd-libleak.a
|
||||
|
||||
bsd-libgc.a:
|
||||
$(MAKE) CFLAGS="$(CFLAGS)" clean c++-t
|
||||
mv gc.a bsd-libgc.a
|
||||
|
||||
bsd-libleak.a:
|
||||
$(MAKE) -f Makefile.direct CFLAGS="$(LEAKFLAGS)" clean c++-nt
|
||||
mv gc.a bsd-libleak.a
|
||||
|
||||
BSD-pkg-install: BSD-pkg-all
|
||||
${CP} bsd-libgc.a libgc.a
|
||||
${INSTALL_DATA} libgc.a ${PREFIX}/lib
|
||||
${INSTALL_DATA} gc.h gc_cpp.h ${PREFIX}/include
|
||||
${INSTALL_MAN} doc/gc.man ${PREFIX}/man/man3/gc.3
|
||||
|
||||
pcr: PCR-Makefile include/private/gc_private.h include/private/gc_hdrs.h \
|
||||
include/private/gc_locks.h include/gc.h include/private/gcconfig.h \
|
||||
mach_dep.o $(SRCS)
|
||||
$(MAKE) -f PCR-Makefile depend
|
||||
$(MAKE) -f PCR-Makefile
|
||||
|
||||
$(OBJS) tests/test.o dyn_load.o dyn_load_sunos53.o: \
|
||||
$(srcdir)/include/private/gc_priv.h \
|
||||
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
|
||||
$(srcdir)/include/gc.h $(srcdir)/include/gc_pthread_redirects.h \
|
||||
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
|
||||
$(srcdir)/include/gc_config_macros.h Makefile $(AO_INSTALL_DIR)
|
||||
# The dependency on Makefile is needed. Changing
|
||||
# options affects the size of GC_arrays,
|
||||
# invalidating all .o files that rely on gc_priv.h
|
||||
|
||||
mark.o typd_mlc.o finalize.o ptr_chck.o: $(srcdir)/include/gc_mark.h \
|
||||
$(srcdir)/include/private/gc_pmark.h
|
||||
|
||||
specific.o pthread_support.o thread_local_alloc.o win32_threads.o: \
|
||||
$(srcdir)/include/private/specific.h $(srcdir)/include/gc_inline.h \
|
||||
$(srcdir)/include/private/thread_local_alloc.h
|
||||
|
||||
dbg_mlc.o gcj_mlc.o: $(srcdir)/include/private/dbg_mlc.h
|
||||
|
||||
tests/test.o: tests $(srcdir)/tests/test.c
|
||||
$(CC) $(CFLAGS) -c $(srcdir)/tests/test.c
|
||||
mv test.o tests/test.o
|
||||
|
||||
tests:
|
||||
mkdir tests
|
||||
|
||||
base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
|
||||
echo > base_lib
|
||||
rm -f dont_ar_1
|
||||
cp $(AO_INSTALL_DIR)/lib/libatomic_ops.a gc.a
|
||||
./if_mach SPARC SOLARIS touch dont_ar_1
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
|
||||
./if_mach M68K AMIGA touch dont_ar_1
|
||||
./if_mach M68K AMIGA $(AR) -vrus gc.a $(OBJS) dyn_load.o
|
||||
./if_not_there dont_ar_1 $(AR) ru gc.a $(OBJS) dyn_load.o
|
||||
./if_not_there dont_ar_1 $(RANLIB) gc.a || cat /dev/null
|
||||
# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
|
||||
|
||||
cords: $(CORD_OBJS) cord/cordtest $(UTILS)
|
||||
rm -f dont_ar_3
|
||||
./if_mach SPARC SOLARIS touch dont_ar_3
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
|
||||
./if_mach M68K AMIGA touch dont_ar_3
|
||||
./if_mach M68K AMIGA $(AR) -vrus gc.a $(CORD_OBJS)
|
||||
./if_not_there dont_ar_3 $(AR) ru gc.a $(CORD_OBJS)
|
||||
./if_not_there dont_ar_3 $(RANLIB) gc.a || cat /dev/null
|
||||
|
||||
gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/include/gc_cpp.h $(srcdir)/include/gc.h Makefile
|
||||
$(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc
|
||||
|
||||
test_cpp: $(srcdir)/tests/test_cpp.cc $(srcdir)/include/gc_cpp.h gc_cpp.o $(srcdir)/include/gc.h \
|
||||
base_lib $(UTILS)
|
||||
rm -f test_cpp
|
||||
./if_mach HP_PA HPUX $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a -ldld `./threadlibs`
|
||||
./if_not_there test_cpp $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/tests/test_cpp.cc gc_cpp.o gc.a `./threadlibs`
|
||||
|
||||
c++-t: c++
|
||||
./test_cpp 1
|
||||
|
||||
c++-nt: c++
|
||||
@echo "Use ./test_cpp 1 to test the leak library"
|
||||
|
||||
c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp
|
||||
rm -f dont_ar_4
|
||||
./if_mach SPARC SOLARIS touch dont_ar_4
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
|
||||
./if_mach M68K AMIGA touch dont_ar_4
|
||||
./if_mach M68K AMIGA $(AR) -vrus gc.a gc_cpp.o
|
||||
./if_not_there dont_ar_4 $(AR) ru gc.a gc_cpp.o
|
||||
./if_not_there dont_ar_4 $(RANLIB) gc.a || cat /dev/null
|
||||
./test_cpp 1
|
||||
echo > c++
|
||||
|
||||
dyn_load_sunos53.o: dyn_load.c
|
||||
$(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c $(srcdir)/dyn_load.c -o $@
|
||||
|
||||
# SunOS5 shared library version of the collector
|
||||
sunos5gc.so: $(OBJS) dyn_load_sunos53.o
|
||||
$(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o $(AO_INSTALL_DIR)/lib/libatomic_ops.a -ldl
|
||||
ln sunos5gc.so libgc.so
|
||||
|
||||
# Alpha/OSF shared library version of the collector
|
||||
libalphagc.so: $(OBJS)
|
||||
ld -shared -o libalphagc.so $(OBJS) dyn_load.o -lc
|
||||
ln libalphagc.so libgc.so
|
||||
|
||||
# IRIX shared library version of the collector
|
||||
libirixgc.so: $(OBJS) dyn_load.o
|
||||
ld -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc
|
||||
ln libirixgc.so libgc.so
|
||||
|
||||
# Linux shared library version of the collector
|
||||
liblinuxgc.so: $(OBJS) dyn_load.o
|
||||
gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o
|
||||
ln liblinuxgc.so libgc.so
|
||||
|
||||
# Build gctest with dynamic library
|
||||
dyn_test:
|
||||
$(CC) $(CFLAGS) -o gctest tests/test.c libgc.so `./threadlibs`
|
||||
./gctest
|
||||
|
||||
# Alternative Linux rule. This is preferable, but is likely to break the
|
||||
# Makefile for some non-linux platforms.
|
||||
# LIBOBJS= $(patsubst %.o, %.lo, $(OBJS))
|
||||
#
|
||||
#.SUFFIXES: .lo $(SUFFIXES)
|
||||
#
|
||||
#.c.lo:
|
||||
# $(CC) $(CFLAGS) $(CPPFLAGS) -fPIC -c $< -o $@
|
||||
#
|
||||
# liblinuxgc.so: $(LIBOBJS) dyn_load.lo
|
||||
# gcc -shared -Wl,-soname=libgc.so.0 -o libgc.so.0 $(LIBOBJS) dyn_load.lo
|
||||
# touch liblinuxgc.so
|
||||
|
||||
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.s \
|
||||
$(srcdir)/mips_ultrix_mach_dep.s \
|
||||
$(srcdir)/rs6000_mach_dep.s \
|
||||
$(srcdir)/sparc_mach_dep.S $(srcdir)/sparc_sunos4_mach_dep.s \
|
||||
$(srcdir)/ia64_save_regs_in_stack.s \
|
||||
$(srcdir)/sparc_netbsd_mach_dep.s $(UTILS)
|
||||
rm -f mach_dep.o
|
||||
./if_mach SPARC SOLARIS $(CC) -c -o mach_dep2.o $(srcdir)/sparc_mach_dep.S
|
||||
./if_mach SPARC OPENBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_sunos4_mach_dep.s
|
||||
./if_mach SPARC NETBSD $(AS) -o mach_dep2.o $(srcdir)/sparc_netbsd_mach_dep.s
|
||||
./if_mach SPARC "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
|
||||
./if_mach SPARC "" ld -r -o mach_dep.o mach_dep1.o mach_dep2.o
|
||||
./if_mach IA64 "" as $(AS_ABI_FLAG) -o ia64_save_regs_in_stack.o $(srcdir)/ia64_save_regs_in_stack.s
|
||||
./if_mach IA64 "" $(CC) -c -o mach_dep1.o $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
|
||||
./if_mach IA64 "" ld -r -o mach_dep.o mach_dep1.o ia64_save_regs_in_stack.o
|
||||
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
|
||||
|
||||
mark_rts.o: $(srcdir)/mark_rts.c $(UTILS)
|
||||
rm -f mark_rts.o
|
||||
-./if_mach ALPHA OSF1 $(CC) -c $(CFLAGS) -Wo,-notail $(srcdir)/mark_rts.c
|
||||
./if_not_there mark_rts.o $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
|
||||
# Work-around for DEC optimizer tail recursion elimination bug.
|
||||
# The ALPHA-specific line should be removed if gcc is used.
|
||||
|
||||
alloc.o: version.h
|
||||
|
||||
cord:
|
||||
mkdir cord
|
||||
|
||||
cord/cordbscs.o: cord $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordbscs.c
|
||||
mv cordbscs.o cord/cordbscs.o
|
||||
# not all compilers understand -o filename
|
||||
|
||||
cord/cordxtra.o: cord $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordxtra.c
|
||||
mv cordxtra.o cord/cordxtra.o
|
||||
|
||||
cord/cordprnt.o: cord $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordprnt.c
|
||||
mv cordprnt.o cord/cordprnt.o
|
||||
|
||||
cord/cordtest: $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS)
|
||||
rm -f cord/cordtest
|
||||
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lucb
|
||||
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -ldld `./threadlibs`
|
||||
./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
|
||||
./if_not_there cord/cordtest $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a `./threadlibs`
|
||||
|
||||
cord/de: $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
|
||||
rm -f cord/de
|
||||
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
|
||||
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld `./threadlibs`
|
||||
./if_mach POWERPC AIX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
|
||||
./if_mach POWERPC DARWIN $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a
|
||||
./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
|
||||
./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
|
||||
./if_mach IA64 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
|
||||
./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
|
||||
./if_not_there cord/de $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) `./threadlibs`
|
||||
|
||||
if_mach: $(srcdir)/if_mach.c $(srcdir)/include/private/gcconfig.h
|
||||
$(HOSTCC) $(HOSTCFLAGS) -o if_mach $(srcdir)/if_mach.c
|
||||
|
||||
threadlibs: $(srcdir)/threadlibs.c $(srcdir)/include/private/gcconfig.h Makefile
|
||||
$(HOSTCC) $(HOSTCFLAGS) -o threadlibs $(srcdir)/threadlibs.c
|
||||
|
||||
if_not_there: $(srcdir)/if_not_there.c
|
||||
$(HOSTCC) $(HOSTCFLAGS) -o if_not_there $(srcdir)/if_not_there.c
|
||||
|
||||
clean:
|
||||
rm -f gc.a *.o *.exe tests/*.o gctest gctest_dyn_link test_cpp \
|
||||
setjmp_test mon.out gmon.out a.out core if_not_there if_mach \
|
||||
threadlibs $(CORD_OBJS) cord/cordtest cord/de
|
||||
-rm -f *~
|
||||
|
||||
gctest: tests/test.o gc.a $(UTILS)
|
||||
rm -f gctest
|
||||
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -lucb
|
||||
./if_mach HP_PA HPUX $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -ldld `./threadlibs`
|
||||
./if_mach M68K AMIGA $(CC) $(CFLAGS) -UGC_AMIGA_MAKINGLIB -o gctest tests/test.o gc.a `./threadlibs`
|
||||
./if_not_there gctest $(CC) $(CFLAGS) -o gctest tests/test.o gc.a `./threadlibs`
|
||||
|
||||
# If an optimized setjmp_test generates a segmentation fault,
|
||||
# odds are your compiler is broken. Gctest may still work.
|
||||
# Try compiling setjmp_t.c unoptimized.
|
||||
setjmp_test: $(srcdir)/setjmp_t.c $(srcdir)/include/gc.h $(UTILS) $(AO_INSTALL_DIR)
|
||||
$(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
|
||||
|
||||
test: KandRtest cord/cordtest
|
||||
cord/cordtest
|
||||
|
||||
# Those tests that work even with a K&R C compiler:
|
||||
KandRtest: setjmp_test gctest
|
||||
./setjmp_test
|
||||
./gctest
|
||||
|
||||
add_gc_prefix: $(srcdir)/add_gc_prefix.c $(srcdir)/version.h
|
||||
$(CC) -o add_gc_prefix $(srcdir)/add_gc_prefix.c
|
||||
|
||||
gcname: $(srcdir)/gcname.c $(srcdir)/version.h
|
||||
$(CC) -o gcname $(srcdir)/gcname.c
|
||||
|
||||
#We assume this is being done from source directory.
|
||||
dist gc.tar: $(SRCS) $(DOC_FILES) $(OTHER_FILES) add_gc_prefix gcname
|
||||
cp Makefile Makefile.old
|
||||
cp Makefile.direct Makefile
|
||||
CC=$(CC) ./configure_atomic_ops.sh
|
||||
cd $(AO_SRC_DIR); make dist
|
||||
if test $(srcdir)/libatomic_ops-$(AO_VERSION) = $(AO_SRC_DIR); \
|
||||
then \
|
||||
mv $(AO_SRC_DIR) $(AO_SRC_DIR).bak ; \
|
||||
tar xvfz $(AO_SRC_DIR).bak/libatomic_ops-$(AO_VERSION).tar.gz ; \
|
||||
else \
|
||||
tar xvfz $(AO_SRC_DIR)/libatomic_ops-$(AO_VERSION).tar.gz ; \
|
||||
fi
|
||||
rm -f `./gcname`
|
||||
ln -s . `./gcname`
|
||||
./add_gc_prefix $(SRCS) $(DOC_FILES) $(OTHER_FILES) libatomic_ops-$(AO_VERSION) > /tmp/gc.tar-files
|
||||
tar cvfh gc.tar `cat /tmp/gc.tar-files`
|
||||
cp gc.tar `./gcname`.tar
|
||||
gzip `./gcname`.tar
|
||||
rm `./gcname`
|
||||
|
||||
gc.tar.Z: gc.tar
|
||||
compress gc.tar
|
||||
|
||||
gc.tar.gz: gc.tar
|
||||
gzip gc.tar
|
||||
|
||||
lint: $(CSRCS) tests/test.c
|
||||
lint -DLINT $(CSRCS) tests/test.c | egrep -v "possible pointer alignment problem|abort|exit|sbrk|mprotect|syscall|change in ANSI|improper alignment"
|
||||
|
||||
# BTL: added to test shared library version of collector.
|
||||
# Currently works only under SunOS5. Requires GC_INIT call from statically
|
||||
# loaded client code.
|
||||
ABSDIR = `pwd`
|
||||
gctest_dyn_link: tests/test.o libgc.so
|
||||
$(CC) -L$(ABSDIR) -R$(ABSDIR) -o gctest_dyn_link tests/test.o -lgc -ldl -lthread
|
||||
|
||||
gctest_irix_dyn_link: tests/test.o libirixgc.so
|
||||
$(CC) -L$(ABSDIR) -o gctest_irix_dyn_link tests/test.o -lirixgc
|
||||
|
||||
# The following appear to be dead, especially since libgc_globals.h
|
||||
# is apparently lost.
|
||||
test_dll.o: tests/test.c libgc_globals.h
|
||||
$(CC) $(CFLAGS) -DGC_USE_DLL -c tests/test.c -o test_dll.o
|
||||
|
||||
test_dll: test_dll.o libgc_dll.a libgc.dll
|
||||
$(CC) test_dll.o -L$(ABSDIR) -lgc_dll -o test_dll
|
||||
|
||||
SYM_PREFIX-libgc=GC
|
||||
|
||||
# Uncomment the following line to build a GNU win32 DLL
|
||||
# include Makefile.DLLs
|
||||
|
||||
reserved_namespace: $(SRCS)
|
||||
for file in $(SRCS) tests/test.c tests/test_cpp.cc; do \
|
||||
sed s/GC_/_GC_/g < $$file > tmp; \
|
||||
cp tmp $$file; \
|
||||
done
|
||||
|
||||
user_namespace: $(SRCS)
|
||||
for file in $(SRCS) tests/test.c tests/test_cpp.cc; do \
|
||||
sed s/_GC_/GC_/g < $$file > tmp; \
|
||||
cp tmp $$file; \
|
||||
done
|
||||
428
src/engine/boehm_gc/Makefile.dj
Normal file
428
src/engine/boehm_gc/Makefile.dj
Normal file
@@ -0,0 +1,428 @@
|
||||
# This Makefile is intended only for DJGPP use.
|
||||
# It is mainly a copy of the main Makefile, but tends to get out of sync
|
||||
# with it. A merge would probably be appropriate.
|
||||
|
||||
# Primary targets:
|
||||
# gc.a - builds basic library
|
||||
# libgc.a - builds library for use with g++ "-fgc-keyword" extension
|
||||
# -fgc-keyword was never really available. Historical
|
||||
# interest only.
|
||||
# c++ - adds C++ interface to library
|
||||
# cords - adds cords (heavyweight strings) to library
|
||||
# test - prints porting information, then builds basic version of gc.a,
|
||||
# and runs some tests of collector and cords. Does not add cords or
|
||||
# c++ interface to gc.a
|
||||
# cord/de$(EXE_SUFFIX) - builds dumb editor based on cords.
|
||||
ABI_FLAG=
|
||||
CC=gcc $(ABI_FLAG)
|
||||
CXX=gxx $(ABI_FLAG)
|
||||
AS=gcc -c -x assembler-with-cpp $(ABI_FLAG)
|
||||
# The above doesn't work with gas, which doesn't run cpp.
|
||||
# Define AS as `gcc -c -x assembler-with-cpp' instead.
|
||||
# Under Irix 6, you will have to specify the ABI (-o32, -n32, or -64)
|
||||
# if you use something other than the default ABI on your machine.
|
||||
|
||||
# special defines for DJGPP
|
||||
CXXLD=gxx $(ABI_FLAG)
|
||||
EXE_SUFFIX=.exe
|
||||
|
||||
srcdir= .
|
||||
VPATH= $(srcdir)
|
||||
|
||||
CFLAGS= -gstabs+ -O2 -I$(srcdir)/include -DATOMIC_UNCOLLECTABLE -DALL_INTERIOR_POINTERS -DNO_EXECUTE_PERMISSION
|
||||
|
||||
# Setjmp_test may yield overly optimistic results when compiled
|
||||
# without optimization.
|
||||
# -DFIND_LEAK causes GC_find_leak to be initially set.
|
||||
# This causes the collector to assume that all inaccessible
|
||||
# objects should have been explicitly deallocated, and reports exceptions.
|
||||
# Finalization and the test program are not usable in this mode.
|
||||
# -DALL_INTERIOR_POINTERS allows all pointers to the interior
|
||||
# of objects to be recognized. (See gc_priv.h for consequences.)
|
||||
# -DSMALL_CONFIG tries to tune the collector for small heap sizes,
|
||||
# usually causing it to use less space in such situations.
|
||||
# Incremental collection no longer works in this case.
|
||||
# -DLARGE_CONFIG tunes the collector for unusually large heaps.
|
||||
# Necessary for heaps larger than about 500 MB on most machines.
|
||||
# Recommended for heaps larger than about 64 MB.
|
||||
# -DDONT_ADD_BYTE_AT_END is meaningful only with
|
||||
# -DALL_INTERIOR_POINTERS. Normally -DALL_INTERIOR_POINTERS
|
||||
# causes all objects to be padded so that pointers just past the end of
|
||||
# an object can be recognized. This can be expensive. (The padding
|
||||
# is normally more than one byte due to alignment constraints.)
|
||||
# -DDONT_ADD_BYTE_AT_END disables the padding.
|
||||
# -DNO_SIGNALS does not disable signals during critical parts of
|
||||
# the GC process. This is no less correct than many malloc
|
||||
# implementations, and it sometimes has a significant performance
|
||||
# impact. However, it is dangerous for many not-quite-ANSI C
|
||||
# programs that call things like printf in asynchronous signal handlers.
|
||||
# This is on by default. Turning it off has not been extensively tested with
|
||||
# compilers that reorder stores. It should have been.
|
||||
# -DNO_EXECUTE_PERMISSION may cause some or all of the heap to not
|
||||
# have execute permission, i.e. it may be impossible to execute
|
||||
# code from the heap. Currently this only affects the incremental
|
||||
# collector on UNIX machines. It may greatly improve its performance,
|
||||
# since this may avoid some expensive cache synchronization.
|
||||
# -DGC_NO_OPERATOR_NEW_ARRAY declares that the C++ compiler does not support
|
||||
# the new syntax "operator new[]" for allocating and deleting arrays.
|
||||
# See gc_cpp.h for details. No effect on the C part of the collector.
|
||||
# This is defined implicitly in a few environments. Must also be defined
|
||||
# by clients that use gc_cpp.h.
|
||||
# -DREDIRECT_MALLOC=X causes malloc, realloc, and free to be defined
|
||||
# as aliases for X, GC_realloc, and GC_free, respectively.
|
||||
# Calloc is redefined in terms of the new malloc. X should
|
||||
# be either GC_malloc or GC_malloc_uncollectable.
|
||||
# The former is occasionally useful for working around leaks in code
|
||||
# you don't want to (or can't) look at. It may not work for
|
||||
# existing code, but it often does. Neither works on all platforms,
|
||||
# since some ports use malloc or calloc to obtain system memory.
|
||||
# (Probably works for UNIX, and win32.)
|
||||
# -DIGNORE_FREE turns calls to free into a noop. Only useful with
|
||||
# -DREDIRECT_MALLOC.
|
||||
# -DNO_DEBUGGING removes GC_dump and the debugging routines it calls.
|
||||
# Reduces code size slightly at the expense of debuggability.
|
||||
# -DJAVA_FINALIZATION makes it somewhat safer to finalize objects out of
|
||||
# order by specifying a nonstandard finalization mark procedure (see
|
||||
# finalize.c). Objects reachable from finalizable objects will be marked
|
||||
# in a sepearte postpass, and hence their memory won't be reclaimed.
|
||||
# Not recommended unless you are implementing a language that specifies
|
||||
# these semantics. Since 5.0, determines only only the initial value
|
||||
# of GC_java_finalization variable.
|
||||
# -DFINALIZE_ON_DEMAND causes finalizers to be run only in response
|
||||
# to explicit GC_invoke_finalizers() calls.
|
||||
# In 5.0 this became runtime adjustable, and this only determines the
|
||||
# initial value of GC_finalize_on_demand.
|
||||
# -DATOMIC_UNCOLLECTABLE includes code for GC_malloc_atomic_uncollectable.
|
||||
# This is useful if either the vendor malloc implementation is poor,
|
||||
# or if REDIRECT_MALLOC is used.
|
||||
# -DHBLKSIZE=ddd, where ddd is a power of 2 between 512 and 16384, explicitly
|
||||
# sets the heap block size. Each heap block is devoted to a single size and
|
||||
# kind of object. For the incremental collector it makes sense to match
|
||||
# the most likely page size. Otherwise large values result in more
|
||||
# fragmentation, but generally better performance for large heaps.
|
||||
# -DPRINT_BLACK_LIST Whenever a black list entry is added, i.e. whenever
|
||||
# the garbage collector detects a value that looks almost, but not quite,
|
||||
# like a pointer, print both the address containing the value, and the
|
||||
# value of the near-bogus-pointer. Can be used to identifiy regions of
|
||||
# memory that are likely to contribute misidentified pointers.
|
||||
# -DKEEP_BACK_PTRS Add code to save back pointers in debugging headers
|
||||
# for objects allocated with the debugging allocator. If all objects
|
||||
# through GC_MALLOC with GC_DEBUG defined, this allows the client
|
||||
# to determine how particular or randomly chosen objects are reachable
|
||||
# for debugging/profiling purposes. The gc_backptr.h interface is
|
||||
# implemented only if this is defined.
|
||||
# -DGC_ASSERTIONS Enable some internal GC assertion checking. Currently
|
||||
# this facility is only used in a few places. It is intended primarily
|
||||
# for debugging of the garbage collector itself, but could also
|
||||
# -DDBG_HDRS_ALL Make sure that all objects have debug headers. Increases
|
||||
# the reliability (from 99.9999% to 100%) of some of the debugging
|
||||
# code (especially KEEP_BACK_PTRS). Makes -DSHORT_DBG_HDRS possible.
|
||||
# Assumes that all client allocation is done through debugging
|
||||
# allocators.
|
||||
# -DSHORT_DBG_HDRS Assume that all objects have debug headers. Shorten
|
||||
# the headers to minimize object size, at the expense of checking for
|
||||
# writes past the end of an object. This is intended for environments
|
||||
# in which most client code is written in a "safe" language, such as
|
||||
# Scheme or Java. Assumes that all client allocation is done using
|
||||
# the GC_debug_ functions (or through the macros that expand to these.
|
||||
# (Also eliminates the field for the requested object size.)
|
||||
# occasionally be useful for debugging of client code. Slows down the
|
||||
# collector somewhat, but not drastically.
|
||||
# -DCHECKSUMS reports on erroneously clear dirty bits, and unexpectedly
|
||||
# altered stubborn objects, at substantial performance cost.
|
||||
# Use only for debugging of the incremental collector.
|
||||
# -DGC_GCJ_SUPPORT includes support for gcj (and possibly other systems
|
||||
# that include a pointer to a type descriptor in each allocated object).
|
||||
# Building this way requires an ANSI C compiler.
|
||||
# -DUSE_I686_PREFETCH causes the collector to issue Pentium III style
|
||||
# prefetch instructions. No effect except on X86 Linux platforms.
|
||||
# Assumes a very recent gcc-compatible compiler and assembler.
|
||||
# (Gas prefetcht0 support was added around May 1999.)
|
||||
# Empirically the code appears to still run correctly on Pentium II
|
||||
# processors, though with no performance benefit. May not run on other
|
||||
# X86 processors? In some cases this improves performance by
|
||||
# 15% or so.
|
||||
# -DUSE_3DNOW_PREFETCH causes the collector to issue AMD 3DNow style
|
||||
# prefetch instructions. Same restrictions as USE_I686_PREFETCH.
|
||||
# UNTESTED!!
|
||||
# -DGC_USE_LD_WRAP in combination with the gld flags listed in README.linux
|
||||
# causes the collector some system and pthread calls in a more transparent
|
||||
# fashion than the usual macro-based approach. Requires GNU ld, and
|
||||
# currently probably works only with Linux.
|
||||
|
||||
|
||||
CXXFLAGS= $(CFLAGS) -DGC_OPERATOR_NEW_ARRAY
|
||||
AR= ar
|
||||
RANLIB= ranlib
|
||||
|
||||
|
||||
OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mallocx.o solaris_pthreads.o gcj_mlc.o specific.o
|
||||
|
||||
CSRCS= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mallocx.c solaris_pthreads.c gcj_mlc.c specific.c
|
||||
|
||||
CORD_SRCS= cord/cordbscs.c cord/cordxtra.c cord/cordprnt.c cord/de.c cord/cordtest.c include/cord.h include/ec.h include/private/cord_pos.h cord/de_win.c cord/de_win.h cord/de_cmds.h cord/de_win.ICO cord/de_win.RC cord/SCOPTIONS.amiga cord/SMakefile.amiga
|
||||
|
||||
CORD_OBJS= cord/cordbscs.o cord/cordxtra.o cord/cordprnt.o
|
||||
|
||||
SRCS= $(CSRCS) mips_sgi_mach_dep.S rs6000_mach_dep.s alpha_mach_dep.S \
|
||||
sparc_mach_dep.S include/gc.h include/gc_typed.h \
|
||||
include/private/gc_hdrs.h include/private/gc_priv.h \
|
||||
include/private/gcconfig.h include/private/gc_mark.h \
|
||||
include/gc_inline.h gc.man \
|
||||
threadlibs.c if_mach.c if_not_there.c gc_cpp.cc include/gc_cpp.h \
|
||||
include/weakpointer.h include/private/gc_locks.h \
|
||||
gcc_support.c mips_ultrix_mach_dep.s include/gc_alloc.h \
|
||||
include/new_gc_alloc.h include/javaxfc.h sparc_sunos4_mach_dep.s \
|
||||
include/private/solaris_threads.h include/gc_backptr.h \
|
||||
hpux_test_and_clear.s include/gc_gcj.h \
|
||||
include/gc_local_alloc.h include/private/dbg_mlc.h \
|
||||
include/private/specific.h \
|
||||
include/leak_detector.h $(CORD_SRCS)
|
||||
|
||||
OTHER_FILES= Makefile PCR-Makefile OS2_MAKEFILE NT_MAKEFILE BCC_MAKEFILE \
|
||||
README tests/test.c test_cpp.cc setjmp_t.c SMakefile.amiga \
|
||||
SCoptions.amiga README.amiga README.win32 cord/README \
|
||||
README.rs6000 README.QUICK callprocs pc_excludes \
|
||||
barrett_diagram README.OS2 README.Mac MacProjects.sit.hqx \
|
||||
MacOS.c EMX_MAKEFILE README.debugging \
|
||||
Mac_files/datastart.c Mac_files/dataend.c \
|
||||
Mac_files/MacOS_config.h Mac_files/MacOS_Test_config.h \
|
||||
add_gc_prefix.c README.solaris2 README.sgi README.hp README.uts \
|
||||
win32_threads.c NT_THREADS_MAKEFILE gc.mak README.dj Makefile.dj \
|
||||
README.alpha README.linux README.MacOSX version.h Makefile.DLLs \
|
||||
WCC_MAKEFILE nursery.c include/gc_nursery.h include/gc_copy_descr.h
|
||||
|
||||
CORD_INCLUDE_FILES= $(srcdir)/include/gc.h $(srcdir)/include/cord.h \
|
||||
$(srcdir)/include/ec.h $(srcdir)/include/private/cord_pos.h
|
||||
|
||||
UTILS= if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX)
|
||||
|
||||
# Libraries needed for curses applications. Only needed for de.
|
||||
CURSES= -lcurses -ltermlib
|
||||
|
||||
# The following is irrelevant on most systems. But a few
|
||||
# versions of make otherwise fork the shell specified in
|
||||
# the SHELL environment variable.
|
||||
SHELL= /bin/sh
|
||||
|
||||
SPECIALCFLAGS = -I$(srcdir)/include
|
||||
# Alternative flags to the C compiler for mach_dep.c.
|
||||
# Mach_dep.c often doesn't like optimization, and it's
|
||||
# not time-critical anyway.
|
||||
# Set SPECIALCFLAGS to -q nodirect_code on Encore.
|
||||
|
||||
all: gc.a gctest$(EXE_SUFFIX)
|
||||
|
||||
$(OBJS) test.o dyn_load.o dyn_load_sunos53.o: \
|
||||
$(srcdir)/include/private/gc_priv.h \
|
||||
$(srcdir)/include/private/gc_hdrs.h $(srcdir)/include/private/gc_locks.h \
|
||||
$(srcdir)/include/gc.h \
|
||||
$(srcdir)/include/private/gcconfig.h $(srcdir)/include/gc_typed.h \
|
||||
Makefile
|
||||
# The dependency on Makefile is needed. Changing
|
||||
# options affects the size of GC_arrays,
|
||||
# invalidating all .o files that rely on gc_priv.h
|
||||
|
||||
mark.o typd_mlc.o finalize.o: $(srcdir)/include/gc_mark.h
|
||||
|
||||
base_lib gc.a: $(OBJS) dyn_load.o $(UTILS)
|
||||
echo > base_lib
|
||||
rm -f on_sparc_sunos5_1
|
||||
./if_mach SPARC SOLARIS touch on_sparc_sunos5_1
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a $(OBJS) dyn_load.o
|
||||
./if_not_there on_sparc_sunos5_1 $(AR) ru gc.a $(OBJS) dyn_load.o
|
||||
-./if_not_there on_sparc_sunos5_1 $(RANLIB) gc.a
|
||||
# ignore ranlib failure; that usually means it doesn't exist, and isn't needed
|
||||
|
||||
cords: $(CORD_OBJS) cord/cordtest$(EXE_SUFFIX) $(UTILS)
|
||||
rm -f on_sparc_sunos5_3
|
||||
./if_mach SPARC SOLARIS touch on_sparc_sunos5_3
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a $(CORD_OBJS)
|
||||
./if_not_there on_sparc_sunos5_3 $(AR) ru gc.a $(CORD_OBJS)
|
||||
-./if_not_there on_sparc_sunos5_3 $(RANLIB) gc.a
|
||||
|
||||
gc_cpp.o: $(srcdir)/gc_cpp.cc $(srcdir)/include/gc_cpp.h $(srcdir)/include/gc.h Makefile
|
||||
$(CXX) -c $(CXXFLAGS) $(srcdir)/gc_cpp.cc
|
||||
|
||||
test_cpp$(EXE_SUFFIX): $(srcdir)/test_cpp.cc $(srcdir)/include/gc_cpp.h gc_cpp.o $(srcdir)/include/gc.h \
|
||||
base_lib $(UTILS)
|
||||
rm -f test_cpp test_cpp$(EXE_SUFFIX)
|
||||
./if_mach HP_PA "" $(CXX) $(CXXFLAGS) -o test_cpp $(srcdir)/test_cpp.cc gc_cpp.o gc.a -ldld
|
||||
./if_not_there test_cpp$(EXE_SUFFIX) $(CXXLD) $(CXXFLAGS) -o test_cpp$(EXE_SUFFIX) $(srcdir)/test_cpp.cc gc_cpp.o gc.a
|
||||
rm -f test_cpp
|
||||
|
||||
c++: gc_cpp.o $(srcdir)/include/gc_cpp.h test_cpp$(EXE_SUFFIX)
|
||||
rm -f on_sparc_sunos5_4
|
||||
./if_mach SPARC SOLARIS touch on_sparc_sunos5_4
|
||||
./if_mach SPARC SOLARIS $(AR) rus gc.a gc_cpp.o
|
||||
./if_not_there on_sparc_sunos5_4 $(AR) ru gc.a gc_cpp.o
|
||||
-./if_not_there on_sparc_sunos5_4 $(RANLIB) gc.a
|
||||
./test_cpp$(EXE_SUFFIX) 1
|
||||
echo > c++
|
||||
|
||||
dyn_load_sunos53.o: dyn_load.c
|
||||
$(CC) $(CFLAGS) -DSUNOS53_SHARED_LIB -c $(srcdir)/dyn_load.c -o $@
|
||||
|
||||
# SunOS5 shared library version of the collector
|
||||
sunos5gc.so: $(OBJS) dyn_load_sunos53.o
|
||||
$(CC) -G -o sunos5gc.so $(OBJS) dyn_load_sunos53.o -ldl
|
||||
ln sunos5gc.so libgc.so
|
||||
|
||||
# Alpha/OSF shared library version of the collector
|
||||
libalphagc.so: $(OBJS)
|
||||
ld -shared -o libalphagc.so $(OBJS) dyn_load.o -lc
|
||||
ln libalphagc.so libgc.so
|
||||
|
||||
# IRIX shared library version of the collector
|
||||
libirixgc.so: $(OBJS) dyn_load.o
|
||||
ld -shared $(ABI_FLAG) -o libirixgc.so $(OBJS) dyn_load.o -lc
|
||||
ln libirixgc.so libgc.so
|
||||
|
||||
# Linux shared library version of the collector
|
||||
liblinuxgc.so: $(OBJS) dyn_load.o
|
||||
gcc -shared -o liblinuxgc.so $(OBJS) dyn_load.o -lo
|
||||
ln liblinuxgc.so libgc.so
|
||||
|
||||
mach_dep.o: $(srcdir)/mach_dep.c $(srcdir)/mips_sgi_mach_dep.S $(srcdir)/mips_ultrix_mach_dep.s \
|
||||
$(srcdir)/rs6000_mach_dep.s $(UTILS)
|
||||
rm -f mach_dep.o
|
||||
./if_mach MIPS IRIX5 $(AS) -o mach_dep.o $(srcdir)/mips_sgi_mach_dep.S
|
||||
./if_mach MIPS RISCOS $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
|
||||
./if_mach MIPS ULTRIX $(AS) -o mach_dep.o $(srcdir)/mips_ultrix_mach_dep.s
|
||||
./if_mach POWERPC AIX $(AS) -o mach_dep.o $(srcdir)/rs6000_mach_dep.s
|
||||
./if_mach ALPHA "" $(AS) -o mach_dep.o $(srcdir)/alpha_mach_dep.S
|
||||
./if_mach SPARC SOLARIS $(AS) -o mach_dep.o $(srcdir)/sparc_mach_dep.S
|
||||
./if_mach SPARC SUNOS4 $(AS) -o mach_dep.o $(srcdir)/sparc_sunos4_mach_dep.s
|
||||
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) $(srcdir)/mach_dep.c
|
||||
|
||||
mark_rts.o: $(srcdir)/mark_rts.c if_mach if_not_there $(UTILS)
|
||||
rm -f mark_rts.o
|
||||
-./if_mach ALPHA OSF1 $(CC) -c $(CFLAGS) -Wo,-notail $(srcdir)/mark_rts.c
|
||||
./if_not_there mark_rts.o $(CC) -c $(CFLAGS) $(srcdir)/mark_rts.c
|
||||
# Work-around for DEC optimizer tail recursion elimination bug.
|
||||
# The ALPHA-specific line should be removed if gcc is used.
|
||||
|
||||
alloc.o: version.h
|
||||
|
||||
cord/cordbscs.o: $(srcdir)/cord/cordbscs.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordbscs.c
|
||||
mv cordbscs.o cord/cordbscs.o
|
||||
# not all compilers understand -o filename
|
||||
|
||||
cord/cordxtra.o: $(srcdir)/cord/cordxtra.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordxtra.c
|
||||
mv cordxtra.o cord/cordxtra.o
|
||||
|
||||
cord/cordprnt.o: $(srcdir)/cord/cordprnt.c $(CORD_INCLUDE_FILES)
|
||||
$(CC) $(CFLAGS) -c -I$(srcdir) $(srcdir)/cord/cordprnt.c
|
||||
mv cordprnt.o cord/cordprnt.o
|
||||
|
||||
cord/cordtest$(EXE_SUFFIX): $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a $(UTILS) /tmp
|
||||
rm -f cord/cordtest$(EXE_SUFFIX)
|
||||
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -lucb
|
||||
./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/cordtest$(EXE_SUFFIX) $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a -ldld
|
||||
./if_not_there cord/cordtest$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/cordtest $(srcdir)/cord/cordtest.c $(CORD_OBJS) gc.a
|
||||
rm -f cord/cordtest cordtest
|
||||
-mv cordtest$(EXE_SUFFIX) cord/
|
||||
|
||||
/tmp: $(UTILS)
|
||||
./if_not_there /tmp mkdir /tmp
|
||||
|
||||
cord/de$(EXE_SUFFIX): $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(UTILS)
|
||||
rm -f cord/de cord/de$(EXE_SUFFIX)
|
||||
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -lucb `./threadlibs`
|
||||
./if_mach HP_PA "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES) -ldld
|
||||
./if_mach RS6000 "" $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
|
||||
./if_mach I386 LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses `./threadlibs`
|
||||
./if_mach ALPHA LINUX $(CC) $(CFLAGS) -o cord/de $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a -lcurses
|
||||
./if_not_there cord/de$(EXE_SUFFIX) $(CC) $(CFLAGS) -o cord/de$(EXE_SUFFIX) $(srcdir)/cord/de.c cord/cordbscs.o cord/cordxtra.o gc.a $(CURSES)
|
||||
|
||||
if_mach$(EXE_SUFFIX): $(srcdir)/if_mach.c $(srcdir)/include/private/gcconfig.h
|
||||
rm -f if_mach if_mach$(EXE_SUFFIX)
|
||||
$(CC) $(CFLAGS) -o if_mach $(srcdir)/if_mach.c
|
||||
|
||||
threadlibs$(EXE_SUFFIX): $(srcdir)/threadlibs.c $(srcdir)include/private/gcconfig.h Makefile
|
||||
rm -f threadlibs threadlibs$(EXE_SUFFIX)
|
||||
$(CC) $(CFLAGS) -o threadlibs $(srcdir)/threadlibs.c
|
||||
|
||||
if_not_there$(EXE_SUFFIX): $(srcdir)/if_not_there.c
|
||||
rm -f if_not_there if_not_there$(EXE_SUFFIX)
|
||||
$(CC) $(CFLAGS) -o if_not_there $(srcdir)/if_not_there.c
|
||||
|
||||
# Clean removes *.o several times,
|
||||
# because as the first one doesn't seem to get them all!
|
||||
clean:
|
||||
rm -f gc.a *.o
|
||||
rm -f *.o
|
||||
rm -f *.o
|
||||
rm -f cord/*.o
|
||||
rm -f gctest gctest_dyn_link test_cpp
|
||||
rm -f setjmp_test mon.out gmon.out a.out core if_not_there if_mach
|
||||
rm -f threadlibs $(CORD_OBJS) cordtest cord/cordtest de cord/de
|
||||
rm -f gctest$(EXE_SUFFIX) gctest_dyn_link$(EXE_SUFFIX) test_cpp$(EXE_SUFFIX)
|
||||
rm -f setjmp_test$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX) if_mach$(EXE_SUFFIX)
|
||||
rm -f threadlibs$(EXE_SUFFIX) cord/cordtest$(EXE_SUFFIX)
|
||||
-rm -f *~
|
||||
|
||||
gctest$(EXE_SUFFIX): tests/test.o gc.a if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX)
|
||||
rm -f gctest gctest$(EXE_SUFFIX)
|
||||
./if_mach SPARC DRSNX $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -lucb
|
||||
./if_mach HP_PA "" $(CC) $(CFLAGS) -o gctest tests/test.o gc.a -ldld
|
||||
./if_not_there gctest$(EXE_SUFFIX) $(CC) $(CFLAGS) -o gctest$(EXE_SUFFIX) tests/test.o gc.a
|
||||
rm -f gctest
|
||||
|
||||
# If an optimized setjmp_test generates a segmentation fault,
|
||||
# odds are your compiler is broken. Gctest may still work.
|
||||
# Try compiling setjmp_t.c unoptimized.
|
||||
setjmp_test$(EXE_SUFFIX): $(srcdir)/setjmp_t.c $(srcdir)/include/gc.h \
|
||||
if_mach$(EXE_SUFFIX) if_not_there$(EXE_SUFFIX)
|
||||
rm -f setjmp_test$(EXE_SUFFIX)
|
||||
$(CC) $(CFLAGS) -o setjmp_test $(srcdir)/setjmp_t.c
|
||||
rm -f setjmp_test
|
||||
|
||||
test: KandRtest cord/cordtest$(EXE_SUFFIX)
|
||||
./cord/cordtest$(EXE_SUFFIX)
|
||||
|
||||
# Those tests that work even with a K&R C compiler:
|
||||
KandRtest: setjmp_test$(EXE_SUFFIX) gctest$(EXE_SUFFIX)
|
||||
./setjmp_test$(EXE_SUFFIX)
|
||||
./gctest$(EXE_SUFFIX)
|
||||
|
||||
add_gc_prefix$(EXE_SUFFIX): add_gc_prefix.c
|
||||
$(CC) -o add_gc_prefix$(EXE_SUFFIX) $(srcdir)/add_gc_prefix.c
|
||||
rm -f add_gc_prefix
|
||||
|
||||
gc.tar: $(SRCS) $(OTHER_FILES) add_gc_prefix
|
||||
./add_gc_prefix$(EXE_SUFFIX) $(SRCS) $(OTHER_FILES) > /tmp/gc.tar-files
|
||||
(cd $(srcdir)/.. ; tar cvfh - `cat /tmp/gc.tar-files`) > gc.tar
|
||||
|
||||
pc_gc.tar: $(SRCS) $(OTHER_FILES)
|
||||
tar cvfX pc_gc.tar pc_excludes $(SRCS) $(OTHER_FILES)
|
||||
|
||||
gc.tar.Z: gc.tar
|
||||
compress gc.tar
|
||||
|
||||
gc.tar.gz: gc.tar
|
||||
gzip gc.tar
|
||||
|
||||
lint: $(CSRCS) tests/test.c
|
||||
lint -DLINT $(CSRCS) tests/test.c | egrep -v "possible pointer alignment problem|abort|exit|sbrk|mprotect|syscall"
|
||||
|
||||
# BTL: added to test shared library version of collector.
|
||||
# Currently works only under SunOS5. Requires GC_INIT call from statically
|
||||
# loaded client code.
|
||||
ABSDIR = `pwd`
|
||||
gctest_dyn_link: test.o libgc.so
|
||||
$(CC) -L$(ABSDIR) -R$(ABSDIR) -o gctest_dyn_link test.o -lgc -ldl -lthread
|
||||
|
||||
test_dll.o: tests/test.c libgc_globals.h
|
||||
$(CC) $(CFLAGS) -DGC_USE_DLL -c tests/test.c -o test_dll.o
|
||||
|
||||
test_dll: test_dll.o libgc_dll.a libgc.dll
|
||||
$(CC) test_dll.o -L$(ABSDIR) -lgc_dll -o test_dll
|
||||
|
||||
SYM_PREFIX-libgc=GC
|
||||
|
||||
# Uncomment the following line to build a GNU win32 DLL
|
||||
# include Makefile.DLLs
|
||||
|
||||
1405
src/engine/boehm_gc/Makefile.in
Normal file
1405
src/engine/boehm_gc/Makefile.in
Normal file
File diff suppressed because it is too large
Load Diff
60
src/engine/boehm_gc/NT_MAKEFILE
Executable file
60
src/engine/boehm_gc/NT_MAKEFILE
Executable file
@@ -0,0 +1,60 @@
|
||||
# Makefile for Windows NT. Assumes Microsoft compiler, and a single thread.
|
||||
# DLLs are included in the root set under NT, but not under win32S.
|
||||
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
|
||||
|
||||
MY_CPU=X86
|
||||
CPU=$(MY_CPU)
|
||||
!include <ntwin32.mak>
|
||||
|
||||
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj msvc_dbg.obj
|
||||
|
||||
all: gctest.exe cord\de.exe test_cpp.exe
|
||||
|
||||
.c.obj:
|
||||
$(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_BUILD $*.c /Fo$*.obj
|
||||
|
||||
.cpp.obj:
|
||||
$(cc) $(cdebug) $(cflags) $(cvars) -Iinclude -DALL_INTERIOR_POINTERS -DGC_NOT_DLL -DGC_BUILD $*.CPP /Fo$*.obj
|
||||
|
||||
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
|
||||
|
||||
gc.lib: $(OBJS)
|
||||
lib /MACHINE:i386 /out:gc.lib $(OBJS)
|
||||
# The original NT SDK used lib32 instead of lib
|
||||
|
||||
gctest.exe: tests\test.obj gc.lib
|
||||
# The following works for win32 debugging. For win32s debugging use debugtype:coff
|
||||
# and add mapsympe line.
|
||||
# This produces a "GUI" applications that opens no windows and writes to the log file
|
||||
# "gc.log". This is done to make the result runnable under win32s.
|
||||
$(link) -debug:full -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
|
||||
# mapsympe -n -o gctest.sym gctest.exe
|
||||
|
||||
cord\de_win.rbj: cord\de_win.res
|
||||
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
|
||||
|
||||
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
|
||||
|
||||
cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
|
||||
$(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc
|
||||
|
||||
# Cord/de is a real win32 gui application.
|
||||
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
|
||||
$(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
|
||||
|
||||
gc_cpp.obj: include\gc_cpp.h include\gc.h
|
||||
|
||||
gc_cpp.cpp: gc_cpp.cc
|
||||
copy gc_cpp.cc gc_cpp.cpp
|
||||
|
||||
test_cpp.cpp: tests\test_cpp.cc
|
||||
copy tests\test_cpp.cc test_cpp.cpp
|
||||
|
||||
# This generates the C++ test executable. The executable expects
|
||||
# a single numeric argument, which is the number of iterations.
|
||||
# The output appears in the file "gc.log".
|
||||
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
|
||||
$(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
|
||||
|
||||
|
||||
|
||||
74
src/engine/boehm_gc/NT_STATIC_THREADS_MAKEFILE
Normal file
74
src/engine/boehm_gc/NT_STATIC_THREADS_MAKEFILE
Normal file
@@ -0,0 +1,74 @@
|
||||
# Makefile for Windows NT. Assumes Microsoft compiler.
|
||||
# DLLs are included in the root set under NT, but not under win32S.
|
||||
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
|
||||
|
||||
MY_CPU=X86
|
||||
CPU=$(MY_CPU)
|
||||
!include <ntwin32.mak>
|
||||
|
||||
# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
|
||||
# not earlier versions. We can deal with either, but not inconsistency.
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .obj .cpp .c
|
||||
|
||||
# Atomic_ops installation directory. For win32, the source directory
|
||||
# should do, since we only need the headers.
|
||||
# We assume this was manually unpacked, since I'm not sure there is
|
||||
# a Windows standard command line tool to do this.
|
||||
AO_VERSION=1.2
|
||||
AO_SRC_DIR=libatomic_ops-$(AO_VERSION)/src
|
||||
AO_INCLUDE_DIR=$(AO_SRC_DIR)
|
||||
|
||||
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj msvc_dbg.obj thread_local_alloc.obj
|
||||
|
||||
all: gctest.exe cord\de.exe test_cpp.exe
|
||||
|
||||
.c.obj:
|
||||
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC $*.c /Fo$*.obj
|
||||
|
||||
.cpp.obj:
|
||||
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC /Fo$*.obj
|
||||
|
||||
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
|
||||
|
||||
gc.lib: $(OBJS)
|
||||
lib /MACHINE:i386 /out:gc.lib $(OBJS)
|
||||
# The original NT SDK used lib32 instead of lib
|
||||
|
||||
gctest.exe: tests\test.obj gc.lib
|
||||
# The following works for win32 debugging. For win32s debugging use debugtype:coff
|
||||
# and add mapsympe line.
|
||||
# This produces a "GUI" applications that opens no windows and writes to the log file
|
||||
# "gc.log". This is done to make the result runnable under win32s.
|
||||
$(link) -debug:full -debugtype:cv $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
|
||||
# mapsympe -n -o gctest.sym gctest.exe
|
||||
|
||||
cord\de_win.rbj: cord\de_win.res
|
||||
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
|
||||
|
||||
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
|
||||
|
||||
cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
|
||||
$(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc
|
||||
|
||||
# Cord/de is a real win32 gui application.
|
||||
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
|
||||
$(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
|
||||
|
||||
gc_cpp.obj: include\gc_cpp.h include\gc.h
|
||||
|
||||
gc_cpp.cpp: gc_cpp.cc
|
||||
copy gc_cpp.cc gc_cpp.cpp
|
||||
|
||||
test_cpp.cpp: tests\test_cpp.cc
|
||||
copy tests\test_cpp.cc test_cpp.cpp
|
||||
|
||||
# This generates the C++ test executable. The executable expects
|
||||
# a single numeric argument, which is the number of iterations.
|
||||
# The output appears in the file "gc.log".
|
||||
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
|
||||
$(link) -debug:full -debugtype:cv $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
|
||||
|
||||
AO_SCR_DIR:
|
||||
tar xvfz $(AO_SRC_DIR).tar.gz;
|
||||
|
||||
2220
src/engine/boehm_gc/NT_THREADS_MAKEFILE
Normal file
2220
src/engine/boehm_gc/NT_THREADS_MAKEFILE
Normal file
File diff suppressed because it is too large
Load Diff
74
src/engine/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE
Normal file
74
src/engine/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE
Normal file
@@ -0,0 +1,74 @@
|
||||
# Makefile for Windows NT. Assumes Microsoft compiler.
|
||||
# DLLs are included in the root set under NT, but not under win32S.
|
||||
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
|
||||
|
||||
MY_CPU=AMD64
|
||||
CPU=$(MY_CPU)
|
||||
!include <ntwin32.mak>
|
||||
|
||||
# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
|
||||
# not earlier versions. We can deal with either, but not inconsistency.
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .obj .cpp .c
|
||||
|
||||
# Atomic_ops installation directory. For win32, the source directory
|
||||
# should do, since we only need the headers.
|
||||
# We assume this was manually unpacked, since I'm not sure there is
|
||||
# a Windows standard command line tool to do this.
|
||||
AO_VERSION=1.2
|
||||
AO_SRC_DIR=libatomic_ops-$(AO_VERSION)/src
|
||||
AO_INCLUDE_DIR=$(AO_SRC_DIR)
|
||||
|
||||
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj typd_mlc.obj ptr_chck.obj gc_cpp.obj mallocx.obj win32_threads.obj msvc_dbg.obj thread_local_alloc.obj
|
||||
|
||||
all: gctest.exe cord\de.exe test_cpp.exe
|
||||
|
||||
.c.obj:
|
||||
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -D__STDC__ -DGC_NOT_DLL -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC $*.c /Fo$*.obj /wd4701 -D_CRT_SECURE_NO_DEPRECATE
|
||||
# Disable "may not be initialized" warnings. They're too approximate.
|
||||
# Disable crt security warnings, since unfortunately they warn about all sorts
|
||||
# of safe uses of strncpy. It would be nice to leave the rest enabled.
|
||||
|
||||
.cpp.obj:
|
||||
$(cc) $(cdebug) $(cflags) $(cvarsmt) -Iinclude -I$(AO_INCLUDE_DIR) -DALL_INTERIOR_POINTERS -DGC_NOT_DLL $*.CPP -DGC_WIN32_THREADS -DTHREAD_LOCAL_ALLOC /Fo$*.obj -D_CRT_SECURE_NO_DEPRECATE
|
||||
|
||||
$(OBJS) tests\test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h include\private\gc_locks.h include\private\gc_pmark.h include\gc_mark.h include\private\msvc_dbg.h
|
||||
|
||||
gc.lib: $(OBJS)
|
||||
lib /MACHINE:X64 /out:gc.lib $(OBJS)
|
||||
|
||||
gctest.exe: tests\test.obj gc.lib
|
||||
# This produces a "GUI" applications that opens no windows and writes to the log file
|
||||
# "gc.log". This was done to make the result runnable under win32s and
|
||||
# should be fixed.
|
||||
$(link) $(ldebug) $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
|
||||
|
||||
cord\de_win.rbj: cord\de_win.res
|
||||
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
|
||||
|
||||
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
|
||||
|
||||
cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
|
||||
$(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc
|
||||
|
||||
# Cord/de is a real win32 gui application.
|
||||
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
|
||||
$(link) $(ldebug) $(guiflags) -stack:16384 -out:cord\de.exe cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib $(guilibs)
|
||||
|
||||
gc_cpp.obj: include\gc_cpp.h include\gc.h
|
||||
|
||||
gc_cpp.cpp: gc_cpp.cc
|
||||
copy gc_cpp.cc gc_cpp.cpp
|
||||
|
||||
test_cpp.cpp: tests\test_cpp.cc
|
||||
copy tests\test_cpp.cc test_cpp.cpp
|
||||
|
||||
# This generates the C++ test executable. The executable expects
|
||||
# a single numeric argument, which is the number of iterations.
|
||||
# The output appears in the file "gc.log".
|
||||
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
|
||||
$(link) $(ldebug) $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
|
||||
|
||||
AO_SCR_DIR:
|
||||
tar xvfz $(AO_SRC_DIR).tar.gz;
|
||||
|
||||
45
src/engine/boehm_gc/OS2_MAKEFILE
Normal file
45
src/engine/boehm_gc/OS2_MAKEFILE
Normal file
@@ -0,0 +1,45 @@
|
||||
# Makefile for OS/2. Assumes IBM's compiler, static linking, and a single thread.
|
||||
# Adding dynamic linking support seems easy, but takes a little bit of work.
|
||||
# Adding thread support may be nontrivial, since we haven't yet figured out how to
|
||||
# look at another thread's registers.
|
||||
|
||||
# Significantly revised for GC version 4.4 by Mark Boulter (Jan 1994).
|
||||
|
||||
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj obj_map.obj blacklst.obj finalize.obj new_hblk.obj dbg_mlc.obj malloc.obj stubborn.obj typd_mlc.obj ptr_chck.obj mallocx.obj
|
||||
|
||||
CORDOBJS= cord\cordbscs.obj cord\cordxtra.obj cord\cordprnt.obj
|
||||
|
||||
CC= icc
|
||||
CFLAGS= /O /Q /DSMALL_CONFIG /DALL_INTERIOR_POINTERS
|
||||
# Use /Ti instead of /O for debugging
|
||||
# Setjmp_test may yield overly optimistic results when compiled
|
||||
# without optimization.
|
||||
|
||||
all: $(OBJS) gctest.exe cord\cordtest.exe
|
||||
|
||||
$(OBJS) test.obj: include\private\gc_priv.h include\private\gc_hdrs.h include\gc.h include\private\gcconfig.h
|
||||
|
||||
## ERASE THE LIB FIRST - if it is already there then this command will fail
|
||||
## (make sure its there or erase will fail!)
|
||||
gc.lib: $(OBJS)
|
||||
echo . > gc.lib
|
||||
erase gc.lib
|
||||
LIB gc.lib $(OBJS), gc.lst
|
||||
|
||||
mach_dep.obj: mach_dep.c
|
||||
$(CC) $(CFLAGS) /C mach_dep.c
|
||||
|
||||
gctest.exe: test.obj gc.lib
|
||||
$(CC) $(CFLAGS) /B"/STACK:524288" /Fegctest test.obj gc.lib
|
||||
|
||||
cord\cordbscs.obj: cord\cordbscs.c include\cord.h include\private\cord_pos.h
|
||||
$(CC) $(CFLAGS) /C /Focord\cordbscs cord\cordbscs.c
|
||||
|
||||
cord\cordxtra.obj: cord\cordxtra.c include\cord.h include\private\cord_pos.h include\ec.h
|
||||
$(CC) $(CFLAGS) /C /Focord\cordxtra cord\cordxtra.c
|
||||
|
||||
cord\cordprnt.obj: cord\cordprnt.c include\cord.h include\private\cord_pos.h include\ec.h
|
||||
$(CC) $(CFLAGS) /C /Focord\cordprnt cord\cordprnt.c
|
||||
|
||||
cord\cordtest.exe: cord\cordtest.c include\cord.h include\private\cord_pos.h include\ec.h $(CORDOBJS) gc.lib
|
||||
$(CC) $(CFLAGS) /B"/STACK:65536" /Fecord\cordtest cord\cordtest.c gc.lib $(CORDOBJS)
|
||||
68
src/engine/boehm_gc/PCR-Makefile
Normal file
68
src/engine/boehm_gc/PCR-Makefile
Normal file
@@ -0,0 +1,68 @@
|
||||
#
|
||||
# Default target
|
||||
#
|
||||
|
||||
default: gc.o
|
||||
|
||||
include ../config/common.mk
|
||||
|
||||
#
|
||||
# compilation flags, etc.
|
||||
#
|
||||
|
||||
|
||||
CPPFLAGS = $(INCLUDE) $(CONFIG_CPPFLAGS) \
|
||||
-DPCR_NO_RENAME -DPCR_NO_HOSTDEP_ERR
|
||||
#CFLAGS = -DPCR $(CONFIG_CFLAGS)
|
||||
CFLAGS = -DPCR $(CONFIG_CFLAGS)
|
||||
SPECIALCFLAGS = # For code involving asm's
|
||||
|
||||
ASPPFLAGS = $(INCLUDE) $(CONFIG_ASPPFLAGS) \
|
||||
-DPCR_NO_RENAME -DPCR_NO_HOSTDEP_ERR -DASM
|
||||
|
||||
ASFLAGS = $(CONFIG_ASFLAGS)
|
||||
|
||||
LDRFLAGS = $(CONFIG_LDRFLAGS)
|
||||
|
||||
LDFLAGS = $(CONFIG_LDFLAGS)
|
||||
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
# BEGIN PACKAGE-SPECIFIC PART
|
||||
#
|
||||
#
|
||||
#
|
||||
#
|
||||
|
||||
# Fix to point to local pcr installation directory.
|
||||
PCRDIR= ..
|
||||
|
||||
COBJ= alloc.o reclaim.o allchblk.o misc.o os_dep.o mark_rts.o headers.o mark.o obj_map.o pcr_interface.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o solaris_threads.o typd_mlc.o ptr_chck.o mallocx.o
|
||||
|
||||
CSRC= reclaim.c allchblk.c misc.c alloc.c mach_dep.c os_dep.c mark_rts.c headers.c mark.c obj_map.c pcr_interface.c blacklst.c finalize.c new_hblk.c real_malloc.c dyn_load.c dbg_mlc.c malloc.c stubborn.c checksums.c solaris_threads.c typd_mlc.c ptr_chck.c mallocx.c
|
||||
|
||||
SHELL= /bin/sh
|
||||
|
||||
default: gc.o
|
||||
|
||||
gc.o: $(COBJ) mach_dep.o
|
||||
$(LDR) $(CONFIG_LDRFLAGS) -o gc.o $(COBJ) mach_dep.o
|
||||
|
||||
|
||||
mach_dep.o: mach_dep.c mips_mach_dep.s rs6000_mach_dep.s if_mach if_not_there
|
||||
rm -f mach_dep.o
|
||||
./if_mach MIPS "" as -o mach_dep.o mips_mach_dep.s
|
||||
./if_mach POWERPC AIX as -o mach_dep.o rs6000_mach_dep.s
|
||||
./if_mach ALPHA "" as -o mach_dep.o alpha_mach_dep.s
|
||||
./if_mach SPARC SOLARIS as -o mach_dep.o sparc_mach_dep.s
|
||||
./if_not_there mach_dep.o $(CC) -c $(SPECIALCFLAGS) mach_dep.c
|
||||
|
||||
if_mach: if_mach.c gcconfig.h
|
||||
$(CC) $(CFLAGS) -o if_mach if_mach.c
|
||||
|
||||
if_not_there: if_not_there.c
|
||||
$(CC) $(CFLAGS) -o if_not_there if_not_there.c
|
||||
|
||||
|
||||
88
src/engine/boehm_gc/README.QUICK
Normal file
88
src/engine/boehm_gc/README.QUICK
Normal file
@@ -0,0 +1,88 @@
|
||||
Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
||||
Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved.
|
||||
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
||||
Copyright (c) 1999-2001 by Hewlett-Packard. All rights reserved.
|
||||
|
||||
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
||||
Permission is hereby granted to use or copy this program
|
||||
for any purpose, provided the above notices are retained on all copies.
|
||||
Permission to modify the code and to distribute modified code is granted,
|
||||
provided the above notices are retained, and a notice that the code was
|
||||
modified is included with the above copyright notice.
|
||||
|
||||
A few files have other copyright holders. A few of the files needed
|
||||
to use the GNU-style build procedure come with a modified GPL license
|
||||
that appears not to significantly restrict use of the collector, though
|
||||
use of those files for a purpose other than building the collector may
|
||||
require the resulting code to be covered by the GPL.
|
||||
|
||||
For more details and the names of other contributors, see the
|
||||
doc/README* files and include/gc.h. This file describes typical use of
|
||||
the collector on a machine that is already supported.
|
||||
|
||||
For the version number, see doc/README or version.h.
|
||||
|
||||
INSTALLATION:
|
||||
Under UN*X, Linux:
|
||||
Alternative 1 (the old way): type "make test" in this directory.
|
||||
Link against gc.a. With the most recent GC distributions
|
||||
you may have to copy Makefile.direct to Makefile first.
|
||||
|
||||
Alternative 2 (the new way): type
|
||||
"./configure --prefix=<dir>; make; make check; make install".
|
||||
Link against <dir>/lib/libgc.a or <dir>/lib/libgc.so.
|
||||
See README.autoconf for details
|
||||
|
||||
Under Windows 95, 98, Me, NT, or 2000:
|
||||
copy the appropriate makefile to MAKEFILE, read it, and type "nmake test".
|
||||
(Under Windows, this assumes you have Microsoft command-line tools
|
||||
installed, and suitably configured.)
|
||||
Read the machine specific README in the doc directory if one exists.
|
||||
|
||||
If you need thread support, you will need to follow the special
|
||||
platform-dependent instructions (win32), or define GC_THREADS
|
||||
as described in Makefile (Makefile.direct), or possibly use
|
||||
--enable-threads=posix when running the configure script.
|
||||
|
||||
If you wish to use the cord (structured string) library with the stand-alone
|
||||
Makefile.direct, type "make cords", after copying to "Makefile".
|
||||
(This requires an ANSI C compiler. You may
|
||||
need to redefine CC in the Makefile. The CORD_printf implementation in
|
||||
cordprnt.c is known to be less than perfectly portable. The rest of the
|
||||
package should still work.)
|
||||
|
||||
If you wish to use the collector from C++, type "make c++", or use
|
||||
--enable-cplusplus with the configure script. With Makefile.direct,
|
||||
hese add further files to gc.a and to the include subdirectory. With the
|
||||
alternat build process,this generates libgccpp.
|
||||
See cord/cord.h and include/gc_cpp.h.
|
||||
|
||||
TYPICAL USE:
|
||||
Include "gc.h" from the include subdirectory. Link against the
|
||||
appropriate library ("gc.a" under UN*X). Replace calls to malloc
|
||||
by calls to GC_MALLOC, and calls to realloc by calls to GC_REALLOC.
|
||||
If the object is known to never contain pointers, use GC_MALLOC_ATOMIC
|
||||
instead of GC_MALLOC.
|
||||
|
||||
Define GC_DEBUG before including gc.h for additional checking.
|
||||
|
||||
More documentation on the collector interface can be found at
|
||||
http://www.hpl.hp.com/personal/Hans_Boehm/gc/gcinterface.html,
|
||||
in doc/README and other files in the doc directory, and in include/gc.h .
|
||||
|
||||
WARNINGS:
|
||||
|
||||
Do not store the only pointer to an object in memory allocated
|
||||
with system malloc, since the collector usually does not scan
|
||||
memory allocated in this way.
|
||||
|
||||
Use with threads may be supported on your system, but requires the
|
||||
collector to be built with thread support. See Makefile. The collector
|
||||
does not guarantee to scan thread-local storage (e.g. of the kind
|
||||
accessed with pthread_getspecific()). The collector does scan
|
||||
thread stacks though, so generally the best solution is to ensure that
|
||||
any pointers stored in thread-local storage are also stored on the
|
||||
thread's stack for the duration of their lifetime.
|
||||
|
||||
177
src/engine/boehm_gc/SMakefile.amiga
Normal file
177
src/engine/boehm_gc/SMakefile.amiga
Normal file
@@ -0,0 +1,177 @@
|
||||
|
||||
# Rewritten smakefile for amiga / sas/c. -Kjetil M.
|
||||
# Dont use the cord-package if you define parm=both or parm=reg.
|
||||
|
||||
|
||||
#----------------TOOLS--------------------------------
|
||||
CC=sc
|
||||
LINKER=slink
|
||||
LIBER=oml
|
||||
|
||||
#----------------CPU OPTIONS--------------------------
|
||||
|
||||
CPU=68060
|
||||
|
||||
#----------------FPU OPTIONS--------------------------
|
||||
|
||||
MATH=8
|
||||
MATHLIB=LIB:scm881.lib
|
||||
|
||||
#----------------COMPILER OPTIONS---------------------
|
||||
|
||||
IGNORE= IGNORE=85 IGNORE=154 IGNORE=161 IGNORE=100
|
||||
|
||||
OPTIMIZE=optimize optimizetime optglobal optimizerdepth=100 optimizerpeephole optloop OPTSCHED optimizerinlocal optimizerrecurdepth=100
|
||||
# optimizerinline optimizercomplexity=100
|
||||
|
||||
OPT= $(OPTIMIZE) CPU=$(CPU) math=$(MATH) NOSTACKCHECK VERBOSE \
|
||||
MAPHUNK NOVERSION NOICONS nodebug \
|
||||
parm=reg \
|
||||
DEFINE __USE_SYSBASE
|
||||
|
||||
|
||||
SOPT= $(OPT) $(IGNORE) \
|
||||
DEFINE AMIGA_SKIP_SEG \
|
||||
DEFINE ATOMIC_UNCOLLECTABLE \
|
||||
DEFINE GC_AMIGA_FASTALLOC \
|
||||
DEFINE GC_AMIGA_RETRY \
|
||||
DEFINE GC_AMIGA_PRINTSTATS \
|
||||
DEFINE GC_AMIGA_GC
|
||||
|
||||
|
||||
#DEFINE ALL_INTERIOR_POINTERS \
|
||||
|
||||
|
||||
SCOPT= $(SOPT) define GC_AMIGA_MAKINGLIB
|
||||
|
||||
CSCOPT= $(OPT) DEFINE AMIGA IGNORE=100 IGNORE=161
|
||||
|
||||
#------------------LINKING----------------------------
|
||||
|
||||
|
||||
all: gctest setjmp_t cord/cordtest
|
||||
|
||||
clean:
|
||||
delete *.lib gctest setjmp_t *.o *.lnk cord/*.o cord/*.lib cord/*.lnk cord/cordtest
|
||||
smake
|
||||
|
||||
test: setjmp_t gctest cord/cordtest
|
||||
setjmp_t
|
||||
gctest
|
||||
cord/cordtest
|
||||
|
||||
gctest: gc$(CPU).lib GCAmigaOS$(CPU).lib test.o
|
||||
$(LINKER) LIB:c.o test.o TO gctest LIB gc$(CPU).lib LIB:sc.lib $(MATHLIB)
|
||||
|
||||
setjmp_t: setjmp_t.o gc.h
|
||||
$(LINKER) LIB:c.o setjmp_t.o to setjmp_t lib LIB:sc.lib
|
||||
|
||||
cord/cordtest: cord/cordtest.o cord/cord$(CPU).lib gc$(CPU).lib
|
||||
slink LIB:c.o cord/cordtest.o LIB $(MATHLIB) gc$(CPU).lib cord/cord$(CPU).lib LIB:sc.lib TO cord/cordtest
|
||||
|
||||
|
||||
#------------------LIBBING----------------------------
|
||||
|
||||
OBJS= alloc.o reclaim.o allchblk.o misc.o mach_dep.o os_dep.o mark_rts.o headers.o mark.o obj_map.o blacklst.o finalize.o new_hblk.o real_malloc.o dyn_load.o dbg_mlc.o malloc.o stubborn.o checksums.o typd_mlc.o ptr_chck.o mallocx.o
|
||||
|
||||
gc$(CPU).lib: $(OBJS)
|
||||
$(LIBER) gc$(CPU).lib r $(OBJS)
|
||||
|
||||
|
||||
COBJS = cord/cordbscs.o cord/cordprnt.o cord/cordxtra.o
|
||||
|
||||
cord/cord$(CPU).lib: $(COBJS)
|
||||
oml cord/cord$(CPU).lib r $(COBJS)
|
||||
|
||||
#------------------COMPILING--------------------------
|
||||
|
||||
INC= gc_private.h gc_hdrs.h gc.h gcconfig.h
|
||||
|
||||
alloc.o : alloc.c $(INC)
|
||||
$(CC) alloc.c $(SCOPT) ignore=7
|
||||
|
||||
reclaim.o : reclaim.c $(INC)
|
||||
$(CC) reclaim.c $(SCOPT)
|
||||
|
||||
allchblk.o : allchblk.c $(INC)
|
||||
$(CC) allchblk.c $(SCOPT)
|
||||
|
||||
misc.o : misc.c $(INC)
|
||||
$(CC) misc.c $(SCOPT)
|
||||
|
||||
os_dep.o : os_dep.c $(INC) AmigaOS.c
|
||||
$(CC) os_dep.c $(SCOPT)
|
||||
|
||||
mark_rts.o : mark_rts.c $(INC)
|
||||
$(CC) mark_rts.c $(SCOPT)
|
||||
|
||||
headers.o : headers.c $(INC)
|
||||
$(CC) headers.c $(SCOPT)
|
||||
|
||||
mark.o : mark.c $(INC)
|
||||
$(CC) mark.c $(SCOPT)
|
||||
|
||||
obj_map.o : obj_map.c $(INC)
|
||||
$(CC) obj_map.c $(SCOPT)
|
||||
|
||||
blacklst.o : blacklst.c $(INC)
|
||||
$(CC) blacklst.c $(SCOPT)
|
||||
|
||||
finalize.o : finalize.c $(INC)
|
||||
$(CC) finalize.c $(SCOPT) noopt #Could sas/c still have problems with this one? Gctest sometimes fails to finalize all.
|
||||
|
||||
new_hblk.o : new_hblk.c $(INC)
|
||||
$(CC) new_hblk.c $(SCOPT)
|
||||
|
||||
real_malloc.o : real_malloc.c $(INC)
|
||||
$(CC) real_malloc.c $(SCOPT)
|
||||
|
||||
dyn_load.o : dyn_load.c $(INC)
|
||||
$(CC) dyn_load.c $(SCOPT)
|
||||
|
||||
dbg_mlc.o : dbg_mlc.c $(INC)
|
||||
$(CC) dbg_mlc.c $(SCOPT)
|
||||
|
||||
malloc.o : malloc.c $(INC)
|
||||
$(CC) malloc.c $(SCOPT)
|
||||
|
||||
mallocx.o : mallocx.c $(INC)
|
||||
$(CC) mallocx.c $(SCOPT)
|
||||
|
||||
stubborn.o : stubborn.c $(INC)
|
||||
$(CC) stubborn.c $(SCOPT)
|
||||
|
||||
checksums.o : checksums.c $(INC)
|
||||
$(CC) checksums.c $(SCOPT)
|
||||
|
||||
typd_mlc.o: typd_mlc.c $(INC)
|
||||
$(CC) typd_mlc.c $(SCOPT)
|
||||
|
||||
mach_dep.o : mach_dep.c $(INC)
|
||||
$(CC) mach_dep.c $(SCOPT)
|
||||
|
||||
ptr_chck.o: ptr_chck.c $(INC)
|
||||
$(CC) ptr_chck.c $(SCOPT)
|
||||
|
||||
test.o : test.c $(INC)
|
||||
$(CC) test.c $(SOPT)
|
||||
|
||||
setjmp_t: setjmp_t.c gc.h
|
||||
$(CC) setjmp_t.c $(SOPT)
|
||||
|
||||
|
||||
# cords:
|
||||
|
||||
cord/cordbscs.o: cord/cordbscs.c
|
||||
sc cord/cordbscs.c $(CSCOPT)
|
||||
|
||||
cord/cordprnt.o: cord/cordprnt.c
|
||||
sc cord/cordprnt.c $(CSCOPT)
|
||||
|
||||
cord/cordxtra.o: cord/cordxtra.c
|
||||
sc cord/cordxtra.c $(CSCOPT)
|
||||
|
||||
cord/cordtest.o: cord/cordtest.c
|
||||
sc cord/cordtest.c $(CSCOPT)
|
||||
|
||||
|
||||
196
src/engine/boehm_gc/WCC_MAKEFILE
Normal file
196
src/engine/boehm_gc/WCC_MAKEFILE
Normal file
@@ -0,0 +1,196 @@
|
||||
# Makefile for Watcom C/C++ 10.5, 10.6, 11.0 on NT, OS2 and DOS4GW.
|
||||
# May work with Watcom 10.0.
|
||||
|
||||
# Uncoment one of the lines below for cross compilation.
|
||||
SYSTEM=MSWIN32
|
||||
#SYSTEM=DOS4GW
|
||||
#SYSTEM=OS2
|
||||
|
||||
# The collector can be built either as dynamic or as static library.
|
||||
# Select the library type you need.
|
||||
#MAKE_AS_DLL=1
|
||||
MAKE_AS_LIB=1
|
||||
|
||||
# Select calling conventions.
|
||||
# Possible choices are r and s.
|
||||
CALLING=s
|
||||
|
||||
# Select target CPU.
|
||||
# Possible choices are 3, 4, 5, and 6.
|
||||
# The last choice available only since version 11.0.
|
||||
CPU=5
|
||||
|
||||
# Set optimization options.
|
||||
# Watcom before 11.0 does not support option "-oh".
|
||||
OPTIM=-oneatx -s
|
||||
#OPTIM=-ohneatx -s
|
||||
|
||||
DEFS=-DALL_INTERIOR_POINTERS #-DSMALL_CONFIG #-DGC_DEBUG
|
||||
|
||||
|
||||
#####
|
||||
|
||||
!ifndef SYSTEM
|
||||
!ifdef __MSDOS__
|
||||
SYSTEM=DOS4GW
|
||||
!else ifdef __NT__
|
||||
SYSTEM=MSWIN32
|
||||
!else ifdef __OS2__
|
||||
SYSTEM=OS2
|
||||
!else
|
||||
SYSTEM=Unknown
|
||||
!endif
|
||||
!endif
|
||||
|
||||
!define $(SYSTEM)
|
||||
|
||||
!ifdef DOS4GW
|
||||
SYSFLAG=-DDOS4GW -bt=dos
|
||||
!else ifdef MSWIN32
|
||||
SYSFLAG=-DMSWIN32 -bt=nt
|
||||
!else ifdef OS2
|
||||
SYSFLAG=-DOS2 -bt=os2
|
||||
!else
|
||||
!error undefined or unsupported target platform: $(SYSTEM)
|
||||
!endif
|
||||
!ifdef MAKE_AS_DLL
|
||||
DLLFLAG=-bd -DGC_DLL
|
||||
TEST_DLLFLAG=-DGC_DLL
|
||||
!else ifdef MAKE_AS_LIB
|
||||
DLLFLAG=
|
||||
TEST_DLLFLAG=
|
||||
!else
|
||||
!error Either MAKE_AS_LIB or MAKE_AS_DLL should be defined
|
||||
!endif
|
||||
|
||||
CC=wcc386
|
||||
CXX=wpp386
|
||||
|
||||
# -DUSE_GENERIC is required !
|
||||
CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(DLLFLAG) -DGC_BUILD -DUSE_GENERIC $(DEFS)
|
||||
CXXFLAGS= $(CFLAGS)
|
||||
TEST_CFLAGS=-$(CPU)$(CALLING) $(OPTIM) -zp4 -zc $(SYSFLAG) $(TEST_DLLFLAG) $(DEFS)
|
||||
TEST_CXXFLAGS= $(TEST_CFLAGS)
|
||||
|
||||
OBJS= alloc.obj reclaim.obj allchblk.obj misc.obj &
|
||||
mach_dep.obj os_dep.obj mark_rts.obj headers.obj mark.obj &
|
||||
obj_map.obj blacklst.obj finalize.obj new_hblk.obj &
|
||||
dbg_mlc.obj malloc.obj stubborn.obj dyn_load.obj &
|
||||
typd_mlc.obj ptr_chck.obj mallocx.obj
|
||||
|
||||
all: gc.lib gctest.exe test_cpp.exe
|
||||
|
||||
!ifdef MAKE_AS_DLL
|
||||
|
||||
gc.lib: gc.dll gc_cpp.obj
|
||||
*wlib -b -c -n -p=512 $@ +gc.dll +gc_cpp.obj
|
||||
|
||||
gc.dll: $(OBJS) .AUTODEPEND
|
||||
@%create $*.lnk
|
||||
!ifdef DOS4GW
|
||||
@%append $*.lnk sys os2v2_dll
|
||||
!else ifdef MSWIN32
|
||||
@%append $*.lnk sys nt_dll
|
||||
!else ifdef OS2
|
||||
@%append $*.lnk sys os2v2_dll
|
||||
!endif
|
||||
@%append $*.lnk name $*
|
||||
@for %i in ($(OBJS)) do @%append $*.lnk file '%i'
|
||||
!ifeq CALLING s
|
||||
@%append $*.lnk export GC_is_marked
|
||||
@%append $*.lnk export GC_incr_bytes_allocd
|
||||
@%append $*.lnk export GC_incr_bytes_freed
|
||||
@%append $*.lnk export GC_generic_malloc_words_small
|
||||
!else
|
||||
@%append $*.lnk export GC_is_marked_
|
||||
@%append $*.lnk export GC_incr_bytes_allocd_
|
||||
@%append $*.lnk export GC_incr_bytes_freed_
|
||||
@%append $*.lnk export GC_generic_malloc_words_small_
|
||||
!endif
|
||||
*wlink @$*.lnk
|
||||
!else
|
||||
gc.lib: $(OBJS) gc_cpp.obj
|
||||
@%create $*.lb1
|
||||
@for %i in ($(OBJS)) do @%append $*.lb1 +'%i'
|
||||
@%append $*.lb1 +'gc_cpp.obj'
|
||||
*wlib -b -c -n -p=512 $@ @$*.lb1
|
||||
|
||||
!endif
|
||||
|
||||
|
||||
gctest.exe: test.obj gc.lib
|
||||
%create $*.lnk
|
||||
!ifdef DOS4GW
|
||||
@%append $*.lnk sys dos4g
|
||||
!else ifdef MSWIN32
|
||||
@%append $*.lnk sys nt
|
||||
!else ifdef OS2
|
||||
@%append $*.lnk sys os2v2
|
||||
!endif
|
||||
@%append $*.lnk op case
|
||||
@%append $*.lnk op stack=256K
|
||||
@%append $*.lnk name $*
|
||||
@%append $*.lnk file test.obj
|
||||
@%append $*.lnk library gc.lib
|
||||
!ifdef MAKE_AS_DLL
|
||||
!ifeq CALLING s
|
||||
@%append $*.lnk import GC_is_marked gc
|
||||
!else
|
||||
@%append $*.lnk import GC_is_marked_ gc
|
||||
!endif
|
||||
!endif
|
||||
*wlink @$*.lnk
|
||||
test_cpp.exe: test_cpp.obj gc.lib
|
||||
%create $*.lnk
|
||||
!ifdef DOS4GW
|
||||
@%append $*.lnk sys dos4g
|
||||
!else ifdef MSWIN32
|
||||
@%append $*.lnk sys nt
|
||||
!else ifdef OS2
|
||||
@%append $*.lnk sys os2v2
|
||||
!endif
|
||||
@%append $*.lnk op case
|
||||
@%append $*.lnk op stack=256K
|
||||
@%append $*.lnk name $*
|
||||
@%append $*.lnk file test_cpp.obj
|
||||
@%append $*.lnk library gc.lib
|
||||
!ifdef MAKE_AS_DLL
|
||||
!ifeq CALLING s
|
||||
@%append $*.lnk import GC_incr_bytes_allocd gc
|
||||
@%append $*.lnk import GC_incr_bytes_freed gc
|
||||
@%append $*.lnk import GC_generic_malloc_words_small gc
|
||||
!else
|
||||
@%append $*.lnk import GC_incr_bytes_allocd_ gc
|
||||
@%append $*.lnk import GC_incr_bytes_freed_ gc
|
||||
@%append $*.lnk import GC_generic_malloc_words_small_ gc
|
||||
!endif
|
||||
!endif
|
||||
*wlink @$*.lnk
|
||||
|
||||
gc_cpp.obj: gc_cpp.cc .AUTODEPEND
|
||||
$(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
|
||||
test.obj: tests\test.c .AUTODEPEND
|
||||
$(CC) $(TEST_CFLAGS) $*.c
|
||||
test_cpp.obj: tests\test_cpp.cc .AUTODEPEND
|
||||
$(CXX) $(TEST_CXXFLAGS) -iinclude $*.cc
|
||||
|
||||
|
||||
.c.obj: .AUTODEPEND
|
||||
$(CC) $(CFLAGS) $*.c
|
||||
|
||||
.cc.obj: .AUTODEPEND
|
||||
$(CXX) $(CXXFLAGS) $*.cc
|
||||
|
||||
clean : .SYMBOLIC
|
||||
@if exist *.obj del *.obj
|
||||
@if exist *.map del *.map
|
||||
@if exist *.lnk del *.lnk
|
||||
@if exist *.lb1 del *.lb1
|
||||
@if exist *.sym del *.sym
|
||||
@if exist *.err del *.err
|
||||
@if exist *.tmp del *.tmp
|
||||
@if exist *.lst del *.lst
|
||||
@if exist *.exe del *.exe
|
||||
@if exist *.log del *.log
|
||||
@if exist *.lib del *.lib
|
||||
@if exist *.dll del *.dll
|
||||
49
src/engine/boehm_gc/acinclude.m4
Normal file
49
src/engine/boehm_gc/acinclude.m4
Normal file
@@ -0,0 +1,49 @@
|
||||
#
|
||||
#
|
||||
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
#
|
||||
# Permission is hereby granted to use or copy this program
|
||||
# for any purpose, provided the above notices are retained on all copies.
|
||||
# Permission to modify the code and to distribute modified code is granted,
|
||||
# provided the above notices are retained, and a notice that the code was
|
||||
# modified is included with the above copyright notice.
|
||||
#
|
||||
# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
|
||||
|
||||
# GC_SET_VERSION
|
||||
# sets and AC_DEFINEs GC_VERSION_MAJOR, GC_VERSION_MINOR and GC_ALPHA_VERSION
|
||||
# based on the contents of PACKAGE_VERSION; PACKAGE_VERSION must conform to
|
||||
# [0-9]+[.][0-9]+(alpha[0.9]+)?
|
||||
# in lex syntax; if there is no alpha number, GC_ALPHA_VERSION is empty
|
||||
#
|
||||
AC_DEFUN(GC_SET_VERSION, [
|
||||
AC_MSG_CHECKING(GC version numbers)
|
||||
GC_VERSION_MAJOR=`echo $PACKAGE_VERSION | sed 's/^\([[0-9]][[0-9]]*\)[[.]].*$/\1/g'`
|
||||
GC_VERSION_MINOR=`echo $PACKAGE_VERSION | sed 's/^[[^.]]*[[.]]\([[0-9]][[0-9]]*\).*$/\1/g'`
|
||||
GC_ALPHA_VERSION=`echo $PACKAGE_VERSION | sed 's/^[[^.]]*[[.]][[0-9]]*//'`
|
||||
|
||||
case "$GC_ALPHA_VERSION" in
|
||||
alpha*)
|
||||
GC_ALPHA_VERSION=`echo $GC_ALPHA_VERSION \
|
||||
| sed 's/alpha\([[0-9]][[0-9]]*\)/\1/'` ;;
|
||||
*) GC_ALPHA_MAJOR='' ;;
|
||||
esac
|
||||
|
||||
if test :$GC_VERSION_MAJOR: = :: \
|
||||
-o :$GC_VERSION_MINOR: = :: ;
|
||||
then
|
||||
AC_MSG_RESULT(invalid)
|
||||
AC_MSG_ERROR([nonconforming PACKAGE_VERSION='$PACKAGE_VERSION'])
|
||||
fi
|
||||
|
||||
AC_DEFINE_UNQUOTED(GC_VERSION_MAJOR, $GC_VERSION_MAJOR)
|
||||
AC_DEFINE_UNQUOTED(GC_VERSION_MINOR, $GC_VERSION_MINOR)
|
||||
if test :$GC_ALPHA_VERSION: != :: ; then
|
||||
AC_DEFINE_UNQUOTED(GC_ALPHA_VERSION, $GC_ALPHA_VERSION)
|
||||
fi
|
||||
AC_MSG_RESULT(major=$GC_VERSION_MAJOR minor=$GC_VERSION_MINOR \
|
||||
${GC_ALPHA_VERSION:+alpha=}$GC_ALPHA_VERSION)
|
||||
])
|
||||
|
||||
sinclude(libtool.m4)
|
||||
929
src/engine/boehm_gc/aclocal.m4
vendored
Normal file
929
src/engine/boehm_gc/aclocal.m4
vendored
Normal file
@@ -0,0 +1,929 @@
|
||||
# generated automatically by aclocal 1.9.6 -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
|
||||
# 2005 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
|
||||
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
# PARTICULAR PURPOSE.
|
||||
|
||||
# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_AUTOMAKE_VERSION(VERSION)
|
||||
# ----------------------------
|
||||
# Automake X.Y traces this macro to ensure aclocal.m4 has been
|
||||
# generated from the m4 files accompanying Automake X.Y.
|
||||
AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"])
|
||||
|
||||
# AM_SET_CURRENT_AUTOMAKE_VERSION
|
||||
# -------------------------------
|
||||
# Call AM_AUTOMAKE_VERSION so it can be traced.
|
||||
# This function is AC_REQUIREd by AC_INIT_AUTOMAKE.
|
||||
AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
|
||||
[AM_AUTOMAKE_VERSION([1.9.6])])
|
||||
|
||||
# Figure out how to run the assembler. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_PROG_AS
|
||||
# ----------
|
||||
AC_DEFUN([AM_PROG_AS],
|
||||
[# By default we simply use the C compiler to build assembly code.
|
||||
AC_REQUIRE([AC_PROG_CC])
|
||||
test "${CCAS+set}" = set || CCAS=$CC
|
||||
test "${CCASFLAGS+set}" = set || CCASFLAGS=$CFLAGS
|
||||
AC_ARG_VAR([CCAS], [assembler compiler command (defaults to CC)])
|
||||
AC_ARG_VAR([CCASFLAGS], [assembler compiler flags (defaults to CFLAGS)])
|
||||
])
|
||||
|
||||
# AM_AUX_DIR_EXPAND -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
|
||||
# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to
|
||||
# `$srcdir', `$srcdir/..', or `$srcdir/../..'.
|
||||
#
|
||||
# Of course, Automake must honor this variable whenever it calls a
|
||||
# tool from the auxiliary directory. The problem is that $srcdir (and
|
||||
# therefore $ac_aux_dir as well) can be either absolute or relative,
|
||||
# depending on how configure is run. This is pretty annoying, since
|
||||
# it makes $ac_aux_dir quite unusable in subdirectories: in the top
|
||||
# source directory, any form will work fine, but in subdirectories a
|
||||
# relative path needs to be adjusted first.
|
||||
#
|
||||
# $ac_aux_dir/missing
|
||||
# fails when called from a subdirectory if $ac_aux_dir is relative
|
||||
# $top_srcdir/$ac_aux_dir/missing
|
||||
# fails if $ac_aux_dir is absolute,
|
||||
# fails when called from a subdirectory in a VPATH build with
|
||||
# a relative $ac_aux_dir
|
||||
#
|
||||
# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
|
||||
# are both prefixed by $srcdir. In an in-source build this is usually
|
||||
# harmless because $srcdir is `.', but things will broke when you
|
||||
# start a VPATH build or use an absolute $srcdir.
|
||||
#
|
||||
# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
|
||||
# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
|
||||
# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
|
||||
# and then we would define $MISSING as
|
||||
# MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# This will work as long as MISSING is not called from configure, because
|
||||
# unfortunately $(top_srcdir) has no meaning in configure.
|
||||
# However there are other variables, like CC, which are often used in
|
||||
# configure, and could therefore not use this "fixed" $ac_aux_dir.
|
||||
#
|
||||
# Another solution, used here, is to always expand $ac_aux_dir to an
|
||||
# absolute PATH. The drawback is that using absolute paths prevent a
|
||||
# configured tree to be moved without reconfiguration.
|
||||
|
||||
AC_DEFUN([AM_AUX_DIR_EXPAND],
|
||||
[dnl Rely on autoconf to set up CDPATH properly.
|
||||
AC_PREREQ([2.50])dnl
|
||||
# expand $ac_aux_dir to an absolute path
|
||||
am_aux_dir=`cd $ac_aux_dir && pwd`
|
||||
])
|
||||
|
||||
# AM_CONDITIONAL -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 7
|
||||
|
||||
# AM_CONDITIONAL(NAME, SHELL-CONDITION)
|
||||
# -------------------------------------
|
||||
# Define a conditional.
|
||||
AC_DEFUN([AM_CONDITIONAL],
|
||||
[AC_PREREQ(2.52)dnl
|
||||
ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
|
||||
[$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
|
||||
AC_SUBST([$1_TRUE])
|
||||
AC_SUBST([$1_FALSE])
|
||||
if $2; then
|
||||
$1_TRUE=
|
||||
$1_FALSE='#'
|
||||
else
|
||||
$1_TRUE='#'
|
||||
$1_FALSE=
|
||||
fi
|
||||
AC_CONFIG_COMMANDS_PRE(
|
||||
[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
|
||||
AC_MSG_ERROR([[conditional "$1" was never defined.
|
||||
Usually this means the macro was only invoked conditionally.]])
|
||||
fi])])
|
||||
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 8
|
||||
|
||||
# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be
|
||||
# written in clear, in which case automake, when reading aclocal.m4,
|
||||
# will think it sees a *use*, and therefore will trigger all it's
|
||||
# C support machinery. Also note that it means that autoscan, seeing
|
||||
# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
|
||||
|
||||
|
||||
# _AM_DEPENDENCIES(NAME)
|
||||
# ----------------------
|
||||
# See how the compiler implements dependency checking.
|
||||
# NAME is "CC", "CXX", "GCJ", or "OBJC".
|
||||
# We try a few techniques and use that to set a single cache variable.
|
||||
#
|
||||
# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
|
||||
# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
|
||||
# dependency, and given that the user is not expected to run this macro,
|
||||
# just rely on AC_PROG_CC.
|
||||
AC_DEFUN([_AM_DEPENDENCIES],
|
||||
[AC_REQUIRE([AM_SET_DEPDIR])dnl
|
||||
AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
|
||||
AC_REQUIRE([AM_MAKE_INCLUDE])dnl
|
||||
AC_REQUIRE([AM_DEP_TRACK])dnl
|
||||
|
||||
ifelse([$1], CC, [depcc="$CC" am_compiler_list=],
|
||||
[$1], CXX, [depcc="$CXX" am_compiler_list=],
|
||||
[$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
|
||||
[$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
|
||||
[depcc="$$1" am_compiler_list=])
|
||||
|
||||
AC_CACHE_CHECK([dependency style of $depcc],
|
||||
[am_cv_$1_dependencies_compiler_type],
|
||||
[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
|
||||
# We make a subdir and do the tests there. Otherwise we can end up
|
||||
# making bogus files that we don't know about and never remove. For
|
||||
# instance it was reported that on HP-UX the gcc test will end up
|
||||
# making a dummy file named `D' -- because `-MD' means `put the output
|
||||
# in D'.
|
||||
mkdir conftest.dir
|
||||
# Copy depcomp to subdir because otherwise we won't find it if we're
|
||||
# using a relative directory.
|
||||
cp "$am_depcomp" conftest.dir
|
||||
cd conftest.dir
|
||||
# We will build objects and dependencies in a subdirectory because
|
||||
# it helps to detect inapplicable dependency modes. For instance
|
||||
# both Tru64's cc and ICC support -MD to output dependencies as a
|
||||
# side effect of compilation, but ICC will put the dependencies in
|
||||
# the current directory while Tru64 will put them in the object
|
||||
# directory.
|
||||
mkdir sub
|
||||
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
if test "$am_compiler_list" = ""; then
|
||||
am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
|
||||
fi
|
||||
for depmode in $am_compiler_list; do
|
||||
# Setup a source with many dependencies, because some compilers
|
||||
# like to wrap large dependency lists on column 80 (with \), and
|
||||
# we should not choose a depcomp mode which is confused by this.
|
||||
#
|
||||
# We need to recreate these files for each test, as the compiler may
|
||||
# overwrite some of them when testing with obscure command lines.
|
||||
# This happens at least with the AIX C compiler.
|
||||
: > sub/conftest.c
|
||||
for i in 1 2 3 4 5 6; do
|
||||
echo '#include "conftst'$i'.h"' >> sub/conftest.c
|
||||
# Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
|
||||
# Solaris 8's {/usr,}/bin/sh.
|
||||
touch sub/conftst$i.h
|
||||
done
|
||||
echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
|
||||
|
||||
case $depmode in
|
||||
nosideeffect)
|
||||
# after this tag, mechanisms are not by side-effect, so they'll
|
||||
# only be used when explicitly requested
|
||||
if test "x$enable_dependency_tracking" = xyes; then
|
||||
continue
|
||||
else
|
||||
break
|
||||
fi
|
||||
;;
|
||||
none) break ;;
|
||||
esac
|
||||
# We check with `-c' and `-o' for the sake of the "dashmstdout"
|
||||
# mode. It turns out that the SunPro C++ compiler does not properly
|
||||
# handle `-M -o', and we need to detect this.
|
||||
if depmode=$depmode \
|
||||
source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \
|
||||
depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
|
||||
$SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \
|
||||
>/dev/null 2>conftest.err &&
|
||||
grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
|
||||
grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 &&
|
||||
${MAKE-make} -s -f confmf > /dev/null 2>&1; then
|
||||
# icc doesn't choke on unknown options, it will just issue warnings
|
||||
# or remarks (even with -Werror). So we grep stderr for any message
|
||||
# that says an option was ignored or not supported.
|
||||
# When given -MP, icc 7.0 and 7.1 complain thusly:
|
||||
# icc: Command line warning: ignoring option '-M'; no argument required
|
||||
# The diagnosis changed in icc 8.0:
|
||||
# icc: Command line remark: option '-MP' not supported
|
||||
if (grep 'ignoring option' conftest.err ||
|
||||
grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
|
||||
am_cv_$1_dependencies_compiler_type=$depmode
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
cd ..
|
||||
rm -rf conftest.dir
|
||||
else
|
||||
am_cv_$1_dependencies_compiler_type=none
|
||||
fi
|
||||
])
|
||||
AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
|
||||
AM_CONDITIONAL([am__fastdep$1], [
|
||||
test "x$enable_dependency_tracking" != xno \
|
||||
&& test "$am_cv_$1_dependencies_compiler_type" = gcc3])
|
||||
])
|
||||
|
||||
|
||||
# AM_SET_DEPDIR
|
||||
# -------------
|
||||
# Choose a directory name for dependency files.
|
||||
# This macro is AC_REQUIREd in _AM_DEPENDENCIES
|
||||
AC_DEFUN([AM_SET_DEPDIR],
|
||||
[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
|
||||
])
|
||||
|
||||
|
||||
# AM_DEP_TRACK
|
||||
# ------------
|
||||
AC_DEFUN([AM_DEP_TRACK],
|
||||
[AC_ARG_ENABLE(dependency-tracking,
|
||||
[ --disable-dependency-tracking speeds up one-time build
|
||||
--enable-dependency-tracking do not reject slow dependency extractors])
|
||||
if test "x$enable_dependency_tracking" != xno; then
|
||||
am_depcomp="$ac_aux_dir/depcomp"
|
||||
AMDEPBACKSLASH='\'
|
||||
fi
|
||||
AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
|
||||
AC_SUBST([AMDEPBACKSLASH])
|
||||
])
|
||||
|
||||
# Generate code to set up dependency tracking. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
#serial 3
|
||||
|
||||
# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# ------------------------------
|
||||
AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[for mf in $CONFIG_FILES; do
|
||||
# Strip MF so we end up with the name of the file.
|
||||
mf=`echo "$mf" | sed -e 's/:.*$//'`
|
||||
# Check whether this is an Automake generated Makefile or not.
|
||||
# We used to match only the files named `Makefile.in', but
|
||||
# some people rename them; so instead we look at the file content.
|
||||
# Grep'ing the first line is not enough: some people post-process
|
||||
# each Makefile.in and add a new line on top of each file to say so.
|
||||
# So let's grep whole file.
|
||||
if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then
|
||||
dirpart=`AS_DIRNAME("$mf")`
|
||||
else
|
||||
continue
|
||||
fi
|
||||
# Extract the definition of DEPDIR, am__include, and am__quote
|
||||
# from the Makefile without running `make'.
|
||||
DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
|
||||
test -z "$DEPDIR" && continue
|
||||
am__include=`sed -n 's/^am__include = //p' < "$mf"`
|
||||
test -z "am__include" && continue
|
||||
am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
|
||||
# When using ansi2knr, U may be empty or an underscore; expand it
|
||||
U=`sed -n 's/^U = //p' < "$mf"`
|
||||
# Find all dependency output files, they are included files with
|
||||
# $(DEPDIR) in their names. We invoke sed twice because it is the
|
||||
# simplest approach to changing $(DEPDIR) to its actual value in the
|
||||
# expansion.
|
||||
for file in `sed -n "
|
||||
s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
|
||||
sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do
|
||||
# Make sure the directory exists.
|
||||
test -f "$dirpart/$file" && continue
|
||||
fdir=`AS_DIRNAME(["$file"])`
|
||||
AS_MKDIR_P([$dirpart/$fdir])
|
||||
# echo "creating $dirpart/$file"
|
||||
echo '# dummy' > "$dirpart/$file"
|
||||
done
|
||||
done
|
||||
])# _AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
|
||||
|
||||
# AM_OUTPUT_DEPENDENCY_COMMANDS
|
||||
# -----------------------------
|
||||
# This macro should only be invoked once -- use via AC_REQUIRE.
|
||||
#
|
||||
# This code is only required when automatic dependency tracking
|
||||
# is enabled. FIXME. This creates each `.P' file that we will
|
||||
# need in order to bootstrap the dependency handling code.
|
||||
AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AC_CONFIG_COMMANDS([depfiles],
|
||||
[test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
|
||||
[AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
|
||||
])
|
||||
|
||||
# Do all the work for Automake. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 12
|
||||
|
||||
# This macro actually does too much. Some checks are only needed if
|
||||
# your package does certain things. But this isn't really a big deal.
|
||||
|
||||
# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
|
||||
# AM_INIT_AUTOMAKE([OPTIONS])
|
||||
# -----------------------------------------------
|
||||
# The call with PACKAGE and VERSION arguments is the old style
|
||||
# call (pre autoconf-2.50), which is being phased out. PACKAGE
|
||||
# and VERSION should now be passed to AC_INIT and removed from
|
||||
# the call to AM_INIT_AUTOMAKE.
|
||||
# We support both call styles for the transition. After
|
||||
# the next Automake release, Autoconf can make the AC_INIT
|
||||
# arguments mandatory, and then we can depend on a new Autoconf
|
||||
# release and drop the old call support.
|
||||
AC_DEFUN([AM_INIT_AUTOMAKE],
|
||||
[AC_PREREQ([2.58])dnl
|
||||
dnl Autoconf wants to disallow AM_ names. We explicitly allow
|
||||
dnl the ones we care about.
|
||||
m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
|
||||
AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
|
||||
AC_REQUIRE([AC_PROG_INSTALL])dnl
|
||||
# test to see if srcdir already configured
|
||||
if test "`cd $srcdir && pwd`" != "`pwd`" &&
|
||||
test -f $srcdir/config.status; then
|
||||
AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
|
||||
fi
|
||||
|
||||
# test whether we have cygpath
|
||||
if test -z "$CYGPATH_W"; then
|
||||
if (cygpath --version) >/dev/null 2>/dev/null; then
|
||||
CYGPATH_W='cygpath -w'
|
||||
else
|
||||
CYGPATH_W=echo
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([CYGPATH_W])
|
||||
|
||||
# Define the identity of the package.
|
||||
dnl Distinguish between old-style and new-style calls.
|
||||
m4_ifval([$2],
|
||||
[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
|
||||
AC_SUBST([PACKAGE], [$1])dnl
|
||||
AC_SUBST([VERSION], [$2])],
|
||||
[_AM_SET_OPTIONS([$1])dnl
|
||||
AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
|
||||
AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
|
||||
|
||||
_AM_IF_OPTION([no-define],,
|
||||
[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package])
|
||||
AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl
|
||||
|
||||
# Some tools Automake needs.
|
||||
AC_REQUIRE([AM_SANITY_CHECK])dnl
|
||||
AC_REQUIRE([AC_ARG_PROGRAM])dnl
|
||||
AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOCONF, autoconf)
|
||||
AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version})
|
||||
AM_MISSING_PROG(AUTOHEADER, autoheader)
|
||||
AM_MISSING_PROG(MAKEINFO, makeinfo)
|
||||
AM_PROG_INSTALL_SH
|
||||
AM_PROG_INSTALL_STRIP
|
||||
AC_REQUIRE([AM_PROG_MKDIR_P])dnl
|
||||
# We need awk for the "check" target. The system "awk" is bad on
|
||||
# some platforms.
|
||||
AC_REQUIRE([AC_PROG_AWK])dnl
|
||||
AC_REQUIRE([AC_PROG_MAKE_SET])dnl
|
||||
AC_REQUIRE([AM_SET_LEADING_DOT])dnl
|
||||
_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
|
||||
[_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
|
||||
[_AM_PROG_TAR([v7])])])
|
||||
_AM_IF_OPTION([no-dependencies],,
|
||||
[AC_PROVIDE_IFELSE([AC_PROG_CC],
|
||||
[_AM_DEPENDENCIES(CC)],
|
||||
[define([AC_PROG_CC],
|
||||
defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl
|
||||
AC_PROVIDE_IFELSE([AC_PROG_CXX],
|
||||
[_AM_DEPENDENCIES(CXX)],
|
||||
[define([AC_PROG_CXX],
|
||||
defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl
|
||||
])
|
||||
])
|
||||
|
||||
|
||||
# When config.status generates a header, we must update the stamp-h file.
|
||||
# This file resides in the same directory as the config header
|
||||
# that is generated. The stamp files are numbered to have different names.
|
||||
|
||||
# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
|
||||
# loop where config.status creates the headers, so we can generate
|
||||
# our stamp files there.
|
||||
AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
|
||||
[# Compute $1's index in $config_headers.
|
||||
_am_stamp_count=1
|
||||
for _am_header in $config_headers :; do
|
||||
case $_am_header in
|
||||
$1 | $1:* )
|
||||
break ;;
|
||||
* )
|
||||
_am_stamp_count=`expr $_am_stamp_count + 1` ;;
|
||||
esac
|
||||
done
|
||||
echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_INSTALL_SH
|
||||
# ------------------
|
||||
# Define $install_sh.
|
||||
AC_DEFUN([AM_PROG_INSTALL_SH],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
install_sh=${install_sh-"$am_aux_dir/install-sh"}
|
||||
AC_SUBST(install_sh)])
|
||||
|
||||
# Copyright (C) 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 2
|
||||
|
||||
# Check whether the underlying file-system supports filenames
|
||||
# with a leading dot. For instance MS-DOS doesn't.
|
||||
AC_DEFUN([AM_SET_LEADING_DOT],
|
||||
[rm -rf .tst 2>/dev/null
|
||||
mkdir .tst 2>/dev/null
|
||||
if test -d .tst; then
|
||||
am__leading_dot=.
|
||||
else
|
||||
am__leading_dot=_
|
||||
fi
|
||||
rmdir .tst 2>/dev/null
|
||||
AC_SUBST([am__leading_dot])])
|
||||
|
||||
# Add --enable-maintainer-mode option to configure. -*- Autoconf -*-
|
||||
# From Jim Meyering
|
||||
|
||||
# Copyright (C) 1996, 1998, 2000, 2001, 2002, 2003, 2004, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
AC_DEFUN([AM_MAINTAINER_MODE],
|
||||
[AC_MSG_CHECKING([whether to enable maintainer-specific portions of Makefiles])
|
||||
dnl maintainer-mode is disabled by default
|
||||
AC_ARG_ENABLE(maintainer-mode,
|
||||
[ --enable-maintainer-mode enable make rules and dependencies not useful
|
||||
(and sometimes confusing) to the casual installer],
|
||||
USE_MAINTAINER_MODE=$enableval,
|
||||
USE_MAINTAINER_MODE=no)
|
||||
AC_MSG_RESULT([$USE_MAINTAINER_MODE])
|
||||
AM_CONDITIONAL(MAINTAINER_MODE, [test $USE_MAINTAINER_MODE = yes])
|
||||
MAINT=$MAINTAINER_MODE_TRUE
|
||||
AC_SUBST(MAINT)dnl
|
||||
]
|
||||
)
|
||||
|
||||
AU_DEFUN([jm_MAINTAINER_MODE], [AM_MAINTAINER_MODE])
|
||||
|
||||
# Check to see how 'make' treats includes. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# AM_MAKE_INCLUDE()
|
||||
# -----------------
|
||||
# Check to see how make treats includes.
|
||||
AC_DEFUN([AM_MAKE_INCLUDE],
|
||||
[am_make=${MAKE-make}
|
||||
cat > confinc << 'END'
|
||||
am__doit:
|
||||
@echo done
|
||||
.PHONY: am__doit
|
||||
END
|
||||
# If we don't find an include directive, just comment out the code.
|
||||
AC_MSG_CHECKING([for style of include used by $am_make])
|
||||
am__include="#"
|
||||
am__quote=
|
||||
_am_result=none
|
||||
# First try GNU make style include.
|
||||
echo "include confinc" > confmf
|
||||
# We grep out `Entering directory' and `Leaving directory'
|
||||
# messages which can occur if `w' ends up in MAKEFLAGS.
|
||||
# In particular we don't look at `^make:' because GNU make might
|
||||
# be invoked under some other name (usually "gmake"), in which
|
||||
# case it prints its new name instead of `make'.
|
||||
if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then
|
||||
am__include=include
|
||||
am__quote=
|
||||
_am_result=GNU
|
||||
fi
|
||||
# Now try BSD make style include.
|
||||
if test "$am__include" = "#"; then
|
||||
echo '.include "confinc"' > confmf
|
||||
if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then
|
||||
am__include=.include
|
||||
am__quote="\""
|
||||
_am_result=BSD
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([am__include])
|
||||
AC_SUBST([am__quote])
|
||||
AC_MSG_RESULT([$_am_result])
|
||||
rm -f confinc confmf
|
||||
])
|
||||
|
||||
# Copyright (C) 1999, 2000, 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# AM_PROG_CC_C_O
|
||||
# --------------
|
||||
# Like AC_PROG_CC_C_O, but changed for automake.
|
||||
AC_DEFUN([AM_PROG_CC_C_O],
|
||||
[AC_REQUIRE([AC_PROG_CC_C_O])dnl
|
||||
AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
# FIXME: we rely on the cache variable name because
|
||||
# there is no other way.
|
||||
set dummy $CC
|
||||
ac_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
|
||||
if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
|
||||
# Losing compiler, so override with the script.
|
||||
# FIXME: It is wrong to rewrite CC.
|
||||
# But if we don't then we get into trouble of one sort or another.
|
||||
# A longer-term fix would be to have automake use am__CC in this case,
|
||||
# and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
|
||||
CC="$am_aux_dir/compile $CC"
|
||||
fi
|
||||
])
|
||||
|
||||
# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_MISSING_PROG(NAME, PROGRAM)
|
||||
# ------------------------------
|
||||
AC_DEFUN([AM_MISSING_PROG],
|
||||
[AC_REQUIRE([AM_MISSING_HAS_RUN])
|
||||
$1=${$1-"${am_missing_run}$2"}
|
||||
AC_SUBST($1)])
|
||||
|
||||
|
||||
# AM_MISSING_HAS_RUN
|
||||
# ------------------
|
||||
# Define MISSING if not defined so far and test if it supports --run.
|
||||
# If it does, set am_missing_run to use it, otherwise, to nothing.
|
||||
AC_DEFUN([AM_MISSING_HAS_RUN],
|
||||
[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
|
||||
test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing"
|
||||
# Use eval to expand $SHELL
|
||||
if eval "$MISSING --run true"; then
|
||||
am_missing_run="$MISSING --run "
|
||||
else
|
||||
am_missing_run=
|
||||
AC_MSG_WARN([`missing' script is too old or missing])
|
||||
fi
|
||||
])
|
||||
|
||||
# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_MKDIR_P
|
||||
# ---------------
|
||||
# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise.
|
||||
#
|
||||
# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories
|
||||
# created by `make install' are always world readable, even if the
|
||||
# installer happens to have an overly restrictive umask (e.g. 077).
|
||||
# This was a mistake. There are at least two reasons why we must not
|
||||
# use `-m 0755':
|
||||
# - it causes special bits like SGID to be ignored,
|
||||
# - it may be too restrictive (some setups expect 775 directories).
|
||||
#
|
||||
# Do not use -m 0755 and let people choose whatever they expect by
|
||||
# setting umask.
|
||||
#
|
||||
# We cannot accept any implementation of `mkdir' that recognizes `-p'.
|
||||
# Some implementations (such as Solaris 8's) are not thread-safe: if a
|
||||
# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c'
|
||||
# concurrently, both version can detect that a/ is missing, but only
|
||||
# one can create it and the other will error out. Consequently we
|
||||
# restrict ourselves to GNU make (using the --version option ensures
|
||||
# this.)
|
||||
AC_DEFUN([AM_PROG_MKDIR_P],
|
||||
[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then
|
||||
# We used to keeping the `.' as first argument, in order to
|
||||
# allow $(mkdir_p) to be used without argument. As in
|
||||
# $(mkdir_p) $(somedir)
|
||||
# where $(somedir) is conditionally defined. However this is wrong
|
||||
# for two reasons:
|
||||
# 1. if the package is installed by a user who cannot write `.'
|
||||
# make install will fail,
|
||||
# 2. the above comment should most certainly read
|
||||
# $(mkdir_p) $(DESTDIR)$(somedir)
|
||||
# so it does not work when $(somedir) is undefined and
|
||||
# $(DESTDIR) is not.
|
||||
# To support the latter case, we have to write
|
||||
# test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir),
|
||||
# so the `.' trick is pointless.
|
||||
mkdir_p='mkdir -p --'
|
||||
else
|
||||
# On NextStep and OpenStep, the `mkdir' command does not
|
||||
# recognize any option. It will interpret all options as
|
||||
# directories to create, and then abort because `.' already
|
||||
# exists.
|
||||
for d in ./-p ./--version;
|
||||
do
|
||||
test -d $d && rmdir $d
|
||||
done
|
||||
# $(mkinstalldirs) is defined by Automake if mkinstalldirs exists.
|
||||
if test -f "$ac_aux_dir/mkinstalldirs"; then
|
||||
mkdir_p='$(mkinstalldirs)'
|
||||
else
|
||||
mkdir_p='$(install_sh) -d'
|
||||
fi
|
||||
fi
|
||||
AC_SUBST([mkdir_p])])
|
||||
|
||||
# Helper functions for option handling. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 3
|
||||
|
||||
# _AM_MANGLE_OPTION(NAME)
|
||||
# -----------------------
|
||||
AC_DEFUN([_AM_MANGLE_OPTION],
|
||||
[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
|
||||
|
||||
# _AM_SET_OPTION(NAME)
|
||||
# ------------------------------
|
||||
# Set option NAME. Presently that only means defining a flag for this option.
|
||||
AC_DEFUN([_AM_SET_OPTION],
|
||||
[m4_define(_AM_MANGLE_OPTION([$1]), 1)])
|
||||
|
||||
# _AM_SET_OPTIONS(OPTIONS)
|
||||
# ----------------------------------
|
||||
# OPTIONS is a space-separated list of Automake options.
|
||||
AC_DEFUN([_AM_SET_OPTIONS],
|
||||
[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
|
||||
|
||||
# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
|
||||
# -------------------------------------------
|
||||
# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
|
||||
AC_DEFUN([_AM_IF_OPTION],
|
||||
[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
|
||||
|
||||
# Check to make sure that the build environment is sane. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
|
||||
# Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 4
|
||||
|
||||
# AM_SANITY_CHECK
|
||||
# ---------------
|
||||
AC_DEFUN([AM_SANITY_CHECK],
|
||||
[AC_MSG_CHECKING([whether build environment is sane])
|
||||
# Just in case
|
||||
sleep 1
|
||||
echo timestamp > conftest.file
|
||||
# Do `set' in a subshell so we don't clobber the current shell's
|
||||
# arguments. Must try -L first in case configure is actually a
|
||||
# symlink; some systems play weird games with the mod time of symlinks
|
||||
# (eg FreeBSD returns the mod time of the symlink's containing
|
||||
# directory).
|
||||
if (
|
||||
set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null`
|
||||
if test "$[*]" = "X"; then
|
||||
# -L didn't work.
|
||||
set X `ls -t $srcdir/configure conftest.file`
|
||||
fi
|
||||
rm -f conftest.file
|
||||
if test "$[*]" != "X $srcdir/configure conftest.file" \
|
||||
&& test "$[*]" != "X conftest.file $srcdir/configure"; then
|
||||
|
||||
# If neither matched, then we have a broken ls. This can happen
|
||||
# if, for instance, CONFIG_SHELL is bash and it inherits a
|
||||
# broken ls alias from the environment. This has actually
|
||||
# happened. Such a system could not be considered "sane".
|
||||
AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
|
||||
alias in your environment])
|
||||
fi
|
||||
|
||||
test "$[2]" = conftest.file
|
||||
)
|
||||
then
|
||||
# Ok.
|
||||
:
|
||||
else
|
||||
AC_MSG_ERROR([newly created file is older than distributed files!
|
||||
Check your system clock])
|
||||
fi
|
||||
AC_MSG_RESULT(yes)])
|
||||
|
||||
# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# AM_PROG_INSTALL_STRIP
|
||||
# ---------------------
|
||||
# One issue with vendor `install' (even GNU) is that you can't
|
||||
# specify the program used to strip binaries. This is especially
|
||||
# annoying in cross-compiling environments, where the build's strip
|
||||
# is unlikely to handle the host's binaries.
|
||||
# Fortunately install-sh will honor a STRIPPROG variable, so we
|
||||
# always use install-sh in `make install-strip', and initialize
|
||||
# STRIPPROG with the value of the STRIP variable (set by the user).
|
||||
AC_DEFUN([AM_PROG_INSTALL_STRIP],
|
||||
[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
|
||||
# Installed binaries are usually stripped using `strip' when the user
|
||||
# run `make install-strip'. However `strip' might not be the right
|
||||
# tool to use in cross-compilation environments, therefore Automake
|
||||
# will honor the `STRIP' environment variable to overrule this program.
|
||||
dnl Don't test for $cross_compiling = yes, because it might be `maybe'.
|
||||
if test "$cross_compiling" != no; then
|
||||
AC_CHECK_TOOL([STRIP], [strip], :)
|
||||
fi
|
||||
INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s"
|
||||
AC_SUBST([INSTALL_STRIP_PROGRAM])])
|
||||
|
||||
# Check how to create a tarball. -*- Autoconf -*-
|
||||
|
||||
# Copyright (C) 2004, 2005 Free Software Foundation, Inc.
|
||||
#
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# serial 2
|
||||
|
||||
# _AM_PROG_TAR(FORMAT)
|
||||
# --------------------
|
||||
# Check how to create a tarball in format FORMAT.
|
||||
# FORMAT should be one of `v7', `ustar', or `pax'.
|
||||
#
|
||||
# Substitute a variable $(am__tar) that is a command
|
||||
# writing to stdout a FORMAT-tarball containing the directory
|
||||
# $tardir.
|
||||
# tardir=directory && $(am__tar) > result.tar
|
||||
#
|
||||
# Substitute a variable $(am__untar) that extract such
|
||||
# a tarball read from stdin.
|
||||
# $(am__untar) < result.tar
|
||||
AC_DEFUN([_AM_PROG_TAR],
|
||||
[# Always define AMTAR for backward compatibility.
|
||||
AM_MISSING_PROG([AMTAR], [tar])
|
||||
m4_if([$1], [v7],
|
||||
[am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'],
|
||||
[m4_case([$1], [ustar],, [pax],,
|
||||
[m4_fatal([Unknown tar format])])
|
||||
AC_MSG_CHECKING([how to create a $1 tar archive])
|
||||
# Loop over all known methods to create a tar archive until one works.
|
||||
_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
|
||||
_am_tools=${am_cv_prog_tar_$1-$_am_tools}
|
||||
# Do not fold the above two line into one, because Tru64 sh and
|
||||
# Solaris sh will not grok spaces in the rhs of `-'.
|
||||
for _am_tool in $_am_tools
|
||||
do
|
||||
case $_am_tool in
|
||||
gnutar)
|
||||
for _am_tar in tar gnutar gtar;
|
||||
do
|
||||
AM_RUN_LOG([$_am_tar --version]) && break
|
||||
done
|
||||
am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
|
||||
am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
|
||||
am__untar="$_am_tar -xf -"
|
||||
;;
|
||||
plaintar)
|
||||
# Must skip GNU tar: if it does not support --format= it doesn't create
|
||||
# ustar tarball either.
|
||||
(tar --version) >/dev/null 2>&1 && continue
|
||||
am__tar='tar chf - "$$tardir"'
|
||||
am__tar_='tar chf - "$tardir"'
|
||||
am__untar='tar xf -'
|
||||
;;
|
||||
pax)
|
||||
am__tar='pax -L -x $1 -w "$$tardir"'
|
||||
am__tar_='pax -L -x $1 -w "$tardir"'
|
||||
am__untar='pax -r'
|
||||
;;
|
||||
cpio)
|
||||
am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
|
||||
am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
|
||||
am__untar='cpio -i -H $1 -d'
|
||||
;;
|
||||
none)
|
||||
am__tar=false
|
||||
am__tar_=false
|
||||
am__untar=false
|
||||
;;
|
||||
esac
|
||||
|
||||
# If the value was cached, stop now. We just wanted to have am__tar
|
||||
# and am__untar set.
|
||||
test -n "${am_cv_prog_tar_$1}" && break
|
||||
|
||||
# tar/untar a dummy directory, and stop if the command works
|
||||
rm -rf conftest.dir
|
||||
mkdir conftest.dir
|
||||
echo GrepMe > conftest.dir/file
|
||||
AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
|
||||
rm -rf conftest.dir
|
||||
if test -s conftest.tar; then
|
||||
AM_RUN_LOG([$am__untar <conftest.tar])
|
||||
grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
|
||||
fi
|
||||
done
|
||||
rm -rf conftest.dir
|
||||
|
||||
AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
|
||||
AC_MSG_RESULT([$am_cv_prog_tar_$1])])
|
||||
AC_SUBST([am__tar])
|
||||
AC_SUBST([am__untar])
|
||||
]) # _AM_PROG_TAR
|
||||
|
||||
m4_include([acinclude.m4])
|
||||
20
src/engine/boehm_gc/add_gc_prefix.c
Normal file
20
src/engine/boehm_gc/add_gc_prefix.c
Normal file
@@ -0,0 +1,20 @@
|
||||
# include <stdio.h>
|
||||
# include "version.h"
|
||||
|
||||
int main(argc, argv, envp)
|
||||
int argc;
|
||||
char ** argv;
|
||||
char ** envp;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (GC_ALPHA_VERSION == GC_NOT_ALPHA) {
|
||||
printf("gc%d.%d/%s ", GC_VERSION_MAJOR, GC_VERSION_MINOR, argv[i]);
|
||||
} else {
|
||||
printf("gc%d.%dalpha%d/%s ", GC_VERSION_MAJOR,
|
||||
GC_VERSION_MINOR, GC_ALPHA_VERSION, argv[i]);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
850
src/engine/boehm_gc/allchblk.c
Normal file
850
src/engine/boehm_gc/allchblk.c
Normal file
@@ -0,0 +1,850 @@
|
||||
/*
|
||||
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
||||
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
||||
* Copyright (c) 1998-1999 by Silicon Graphics. All rights reserved.
|
||||
* Copyright (c) 1999 by Hewlett-Packard Company. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
|
||||
/* #define DEBUG */
|
||||
#include <stdio.h>
|
||||
#include "private/gc_priv.h"
|
||||
|
||||
GC_bool GC_use_entire_heap = 0;
|
||||
|
||||
/*
|
||||
* Free heap blocks are kept on one of several free lists,
|
||||
* depending on the size of the block. Each free list is doubly linked.
|
||||
* Adjacent free blocks are coalesced.
|
||||
*/
|
||||
|
||||
|
||||
# define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
|
||||
/* largest block we will allocate starting on a black */
|
||||
/* listed block. Must be >= HBLKSIZE. */
|
||||
|
||||
|
||||
# define UNIQUE_THRESHOLD 32
|
||||
/* Sizes up to this many HBLKs each have their own free list */
|
||||
# define HUGE_THRESHOLD 256
|
||||
/* Sizes of at least this many heap blocks are mapped to a */
|
||||
/* single free list. */
|
||||
# define FL_COMPRESSION 8
|
||||
/* In between sizes map this many distinct sizes to a single */
|
||||
/* bin. */
|
||||
|
||||
# define N_HBLK_FLS (HUGE_THRESHOLD - UNIQUE_THRESHOLD)/FL_COMPRESSION \
|
||||
+ UNIQUE_THRESHOLD
|
||||
|
||||
struct hblk * GC_hblkfreelist[N_HBLK_FLS+1] = { 0 };
|
||||
|
||||
#ifndef USE_MUNMAP
|
||||
|
||||
word GC_free_bytes[N_HBLK_FLS+1] = { 0 };
|
||||
/* Number of free bytes on each list. */
|
||||
|
||||
/* Is bytes + the number of free bytes on lists n .. N_HBLK_FLS */
|
||||
/* > GC_max_large_allocd_bytes? */
|
||||
# ifdef __GNUC__
|
||||
__inline__
|
||||
# endif
|
||||
static GC_bool GC_enough_large_bytes_left(word bytes, int n)
|
||||
{
|
||||
int i;
|
||||
for (i = N_HBLK_FLS; i >= n; --i) {
|
||||
bytes += GC_free_bytes[i];
|
||||
if (bytes > GC_max_large_allocd_bytes) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
# define INCR_FREE_BYTES(n, b) GC_free_bytes[n] += (b);
|
||||
|
||||
# define FREE_ASSERT(e) GC_ASSERT(e)
|
||||
|
||||
#else /* USE_MUNMAP */
|
||||
|
||||
# define INCR_FREE_BYTES(n, b)
|
||||
# define FREE_ASSERT(e)
|
||||
|
||||
#endif /* USE_MUNMAP */
|
||||
|
||||
/* Map a number of blocks to the appropriate large block free list index. */
|
||||
int GC_hblk_fl_from_blocks(word blocks_needed)
|
||||
{
|
||||
if (blocks_needed <= UNIQUE_THRESHOLD) return (int)blocks_needed;
|
||||
if (blocks_needed >= HUGE_THRESHOLD) return N_HBLK_FLS;
|
||||
return (int)(blocks_needed - UNIQUE_THRESHOLD)/FL_COMPRESSION
|
||||
+ UNIQUE_THRESHOLD;
|
||||
|
||||
}
|
||||
|
||||
# define PHDR(hhdr) HDR(hhdr -> hb_prev)
|
||||
# define NHDR(hhdr) HDR(hhdr -> hb_next)
|
||||
|
||||
# ifdef USE_MUNMAP
|
||||
# define IS_MAPPED(hhdr) (((hhdr) -> hb_flags & WAS_UNMAPPED) == 0)
|
||||
# else /* !USE_MMAP */
|
||||
# define IS_MAPPED(hhdr) 1
|
||||
# endif /* USE_MUNMAP */
|
||||
|
||||
# if !defined(NO_DEBUGGING)
|
||||
void GC_print_hblkfreelist()
|
||||
{
|
||||
struct hblk * h;
|
||||
word total_free = 0;
|
||||
hdr * hhdr;
|
||||
word sz;
|
||||
unsigned i;
|
||||
|
||||
for (i = 0; i <= N_HBLK_FLS; ++i) {
|
||||
h = GC_hblkfreelist[i];
|
||||
# ifdef USE_MUNMAP
|
||||
if (0 != h) GC_printf("Free list %ld:\n",
|
||||
(unsigned long)i);
|
||||
# else
|
||||
if (0 != h) GC_printf("Free list %lu (Total size %lu):\n",
|
||||
i, (unsigned long)GC_free_bytes[i]);
|
||||
# endif
|
||||
while (h != 0) {
|
||||
hhdr = HDR(h);
|
||||
sz = hhdr -> hb_sz;
|
||||
GC_printf("\t%p size %lu ", h, (unsigned long)sz);
|
||||
total_free += sz;
|
||||
if (GC_is_black_listed(h, HBLKSIZE) != 0) {
|
||||
GC_printf("start black listed\n");
|
||||
} else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
|
||||
GC_printf("partially black listed\n");
|
||||
} else {
|
||||
GC_printf("not black listed\n");
|
||||
}
|
||||
h = hhdr -> hb_next;
|
||||
}
|
||||
}
|
||||
# ifndef USE_MUNMAP
|
||||
if (total_free != GC_large_free_bytes) {
|
||||
GC_printf("GC_large_free_bytes = %lu (INCONSISTENT!!)\n",
|
||||
(unsigned long) GC_large_free_bytes);
|
||||
}
|
||||
# endif
|
||||
GC_printf("Total of %lu bytes on free list\n", (unsigned long)total_free);
|
||||
}
|
||||
|
||||
/* Return the free list index on which the block described by the header */
|
||||
/* appears, or -1 if it appears nowhere. */
|
||||
int free_list_index_of(hdr *wanted)
|
||||
{
|
||||
struct hblk * h;
|
||||
hdr * hhdr;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= N_HBLK_FLS; ++i) {
|
||||
h = GC_hblkfreelist[i];
|
||||
while (h != 0) {
|
||||
hhdr = HDR(h);
|
||||
if (hhdr == wanted) return i;
|
||||
h = hhdr -> hb_next;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void GC_dump_regions()
|
||||
{
|
||||
unsigned i;
|
||||
ptr_t start, end;
|
||||
ptr_t p;
|
||||
size_t bytes;
|
||||
hdr *hhdr;
|
||||
for (i = 0; i < GC_n_heap_sects; ++i) {
|
||||
start = GC_heap_sects[i].hs_start;
|
||||
bytes = GC_heap_sects[i].hs_bytes;
|
||||
end = start + bytes;
|
||||
/* Merge in contiguous sections. */
|
||||
while (i+1 < GC_n_heap_sects && GC_heap_sects[i+1].hs_start == end) {
|
||||
++i;
|
||||
end = GC_heap_sects[i].hs_start + GC_heap_sects[i].hs_bytes;
|
||||
}
|
||||
GC_printf("***Section from %p to %p\n", start, end);
|
||||
for (p = start; p < end;) {
|
||||
hhdr = HDR(p);
|
||||
GC_printf("\t%p ", p);
|
||||
if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
|
||||
GC_printf("Missing header!!(%d)\n", hhdr);
|
||||
p += HBLKSIZE;
|
||||
continue;
|
||||
}
|
||||
if (HBLK_IS_FREE(hhdr)) {
|
||||
int correct_index = GC_hblk_fl_from_blocks(
|
||||
divHBLKSZ(hhdr -> hb_sz));
|
||||
int actual_index;
|
||||
|
||||
GC_printf("\tfree block of size 0x%lx bytes",
|
||||
(unsigned long)(hhdr -> hb_sz));
|
||||
if (IS_MAPPED(hhdr)) {
|
||||
GC_printf("\n");
|
||||
} else {
|
||||
GC_printf("(unmapped)\n");
|
||||
}
|
||||
actual_index = free_list_index_of(hhdr);
|
||||
if (-1 == actual_index) {
|
||||
GC_printf("\t\tBlock not on free list %d!!\n",
|
||||
correct_index);
|
||||
} else if (correct_index != actual_index) {
|
||||
GC_printf("\t\tBlock on list %d, should be on %d!!\n",
|
||||
actual_index, correct_index);
|
||||
}
|
||||
p += hhdr -> hb_sz;
|
||||
} else {
|
||||
GC_printf("\tused for blocks of size 0x%lx bytes\n",
|
||||
(unsigned long)(hhdr -> hb_sz));
|
||||
p += HBLKSIZE * OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# endif /* NO_DEBUGGING */
|
||||
|
||||
/* Initialize hdr for a block containing the indicated size and */
|
||||
/* kind of objects. */
|
||||
/* Return FALSE on failure. */
|
||||
static GC_bool setup_header(hdr * hhdr, struct hblk *block, size_t byte_sz,
|
||||
int kind, unsigned flags)
|
||||
{
|
||||
word descr;
|
||||
size_t granules;
|
||||
|
||||
/* Set size, kind and mark proc fields */
|
||||
hhdr -> hb_sz = byte_sz;
|
||||
hhdr -> hb_obj_kind = (unsigned char)kind;
|
||||
hhdr -> hb_flags = (unsigned char)flags;
|
||||
hhdr -> hb_block = block;
|
||||
descr = GC_obj_kinds[kind].ok_descriptor;
|
||||
if (GC_obj_kinds[kind].ok_relocate_descr) descr += byte_sz;
|
||||
hhdr -> hb_descr = descr;
|
||||
|
||||
# ifdef MARK_BIT_PER_OBJ
|
||||
/* Set hb_inv_sz as portably as possible. */
|
||||
/* We set it to the smallest value such that sz * inv_sz > 2**32 */
|
||||
/* This may be more precision than necessary. */
|
||||
if (byte_sz > MAXOBJBYTES) {
|
||||
hhdr -> hb_inv_sz = LARGE_INV_SZ;
|
||||
} else {
|
||||
word inv_sz;
|
||||
|
||||
# if CPP_WORDSZ == 64
|
||||
inv_sz = ((word)1 << 32)/byte_sz;
|
||||
if (((inv_sz*byte_sz) >> 32) == 0) ++inv_sz;
|
||||
# else /* 32 bit words */
|
||||
GC_ASSERT(byte_sz >= 4);
|
||||
inv_sz = ((unsigned)1 << 31)/byte_sz;
|
||||
inv_sz *= 2;
|
||||
while (inv_sz*byte_sz > byte_sz) ++inv_sz;
|
||||
# endif
|
||||
hhdr -> hb_inv_sz = inv_sz;
|
||||
}
|
||||
# else /* MARK_BIT_PER_GRANULE */
|
||||
hhdr -> hb_large_block = (unsigned char)(byte_sz > MAXOBJBYTES);
|
||||
granules = BYTES_TO_GRANULES(byte_sz);
|
||||
if (EXPECT(!GC_add_map_entry(granules), FALSE)) {
|
||||
/* Make it look like a valid block. */
|
||||
hhdr -> hb_sz = HBLKSIZE;
|
||||
hhdr -> hb_descr = 0;
|
||||
hhdr -> hb_large_block = TRUE;
|
||||
hhdr -> hb_map = 0;
|
||||
return FALSE;
|
||||
} else {
|
||||
size_t index = (hhdr -> hb_large_block? 0 : granules);
|
||||
hhdr -> hb_map = GC_obj_map[index];
|
||||
}
|
||||
# endif /* MARK_BIT_PER_GRANULE */
|
||||
|
||||
/* Clear mark bits */
|
||||
GC_clear_hdr_marks(hhdr);
|
||||
|
||||
hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
#define FL_UNKNOWN -1
|
||||
/*
|
||||
* Remove hhdr from the appropriate free list.
|
||||
* We assume it is on the nth free list, or on the size
|
||||
* appropriate free list if n is FL_UNKNOWN.
|
||||
*/
|
||||
void GC_remove_from_fl(hdr *hhdr, int n)
|
||||
{
|
||||
int index;
|
||||
|
||||
GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
|
||||
# ifndef USE_MUNMAP
|
||||
/* We always need index to mainatin free counts. */
|
||||
if (FL_UNKNOWN == n) {
|
||||
index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
|
||||
} else {
|
||||
index = n;
|
||||
}
|
||||
# endif
|
||||
if (hhdr -> hb_prev == 0) {
|
||||
# ifdef USE_MUNMAP
|
||||
if (FL_UNKNOWN == n) {
|
||||
index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
|
||||
} else {
|
||||
index = n;
|
||||
}
|
||||
# endif
|
||||
GC_ASSERT(HDR(GC_hblkfreelist[index]) == hhdr);
|
||||
GC_hblkfreelist[index] = hhdr -> hb_next;
|
||||
} else {
|
||||
hdr *phdr;
|
||||
GET_HDR(hhdr -> hb_prev, phdr);
|
||||
phdr -> hb_next = hhdr -> hb_next;
|
||||
}
|
||||
FREE_ASSERT(GC_free_bytes[index] >= hhdr -> hb_sz);
|
||||
INCR_FREE_BYTES(index, - (signed_word)(hhdr -> hb_sz));
|
||||
if (0 != hhdr -> hb_next) {
|
||||
hdr * nhdr;
|
||||
GC_ASSERT(!IS_FORWARDING_ADDR_OR_NIL(NHDR(hhdr)));
|
||||
GET_HDR(hhdr -> hb_next, nhdr);
|
||||
nhdr -> hb_prev = hhdr -> hb_prev;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Return a pointer to the free block ending just before h, if any.
|
||||
*/
|
||||
struct hblk * GC_free_block_ending_at(struct hblk *h)
|
||||
{
|
||||
struct hblk * p = h - 1;
|
||||
hdr * phdr;
|
||||
|
||||
GET_HDR(p, phdr);
|
||||
while (0 != phdr && IS_FORWARDING_ADDR_OR_NIL(phdr)) {
|
||||
p = FORWARDED_ADDR(p,phdr);
|
||||
phdr = HDR(p);
|
||||
}
|
||||
if (0 != phdr) {
|
||||
if(HBLK_IS_FREE(phdr)) {
|
||||
return p;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
p = GC_prev_block(h - 1);
|
||||
if (0 != p) {
|
||||
phdr = HDR(p);
|
||||
if (HBLK_IS_FREE(phdr) && (ptr_t)p + phdr -> hb_sz == (ptr_t)h) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add hhdr to the appropriate free list.
|
||||
* We maintain individual free lists sorted by address.
|
||||
*/
|
||||
void GC_add_to_fl(struct hblk *h, hdr *hhdr)
|
||||
{
|
||||
int index = GC_hblk_fl_from_blocks(divHBLKSZ(hhdr -> hb_sz));
|
||||
struct hblk *second = GC_hblkfreelist[index];
|
||||
hdr * second_hdr;
|
||||
# ifdef GC_ASSERTIONS
|
||||
struct hblk *next = (struct hblk *)((word)h + hhdr -> hb_sz);
|
||||
hdr * nexthdr = HDR(next);
|
||||
struct hblk *prev = GC_free_block_ending_at(h);
|
||||
hdr * prevhdr = HDR(prev);
|
||||
GC_ASSERT(nexthdr == 0 || !HBLK_IS_FREE(nexthdr) || !IS_MAPPED(nexthdr));
|
||||
GC_ASSERT(prev == 0 || !HBLK_IS_FREE(prevhdr) || !IS_MAPPED(prevhdr));
|
||||
# endif
|
||||
GC_ASSERT(((hhdr -> hb_sz) & (HBLKSIZE-1)) == 0);
|
||||
GC_hblkfreelist[index] = h;
|
||||
INCR_FREE_BYTES(index, hhdr -> hb_sz);
|
||||
FREE_ASSERT(GC_free_bytes[index] <= GC_large_free_bytes)
|
||||
hhdr -> hb_next = second;
|
||||
hhdr -> hb_prev = 0;
|
||||
if (0 != second) {
|
||||
GET_HDR(second, second_hdr);
|
||||
second_hdr -> hb_prev = h;
|
||||
}
|
||||
hhdr -> hb_flags |= FREE_BLK;
|
||||
}
|
||||
|
||||
#ifdef USE_MUNMAP
|
||||
|
||||
/* Unmap blocks that haven't been recently touched. This is the only way */
|
||||
/* way blocks are ever unmapped. */
|
||||
void GC_unmap_old(void)
|
||||
{
|
||||
struct hblk * h;
|
||||
hdr * hhdr;
|
||||
word sz;
|
||||
unsigned short last_rec, threshold;
|
||||
int i;
|
||||
# define UNMAP_THRESHOLD 6
|
||||
|
||||
for (i = 0; i <= N_HBLK_FLS; ++i) {
|
||||
for (h = GC_hblkfreelist[i]; 0 != h; h = hhdr -> hb_next) {
|
||||
hhdr = HDR(h);
|
||||
if (!IS_MAPPED(hhdr)) continue;
|
||||
threshold = (unsigned short)(GC_gc_no - UNMAP_THRESHOLD);
|
||||
last_rec = hhdr -> hb_last_reclaimed;
|
||||
if ((last_rec > GC_gc_no || last_rec < threshold)
|
||||
&& threshold < GC_gc_no /* not recently wrapped */) {
|
||||
sz = hhdr -> hb_sz;
|
||||
GC_unmap((ptr_t)h, sz);
|
||||
hhdr -> hb_flags |= WAS_UNMAPPED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Merge all unmapped blocks that are adjacent to other free */
|
||||
/* blocks. This may involve remapping, since all blocks are either */
|
||||
/* fully mapped or fully unmapped. */
|
||||
void GC_merge_unmapped(void)
|
||||
{
|
||||
struct hblk * h, *next;
|
||||
hdr * hhdr, *nexthdr;
|
||||
word size, nextsize;
|
||||
int i;
|
||||
|
||||
for (i = 0; i <= N_HBLK_FLS; ++i) {
|
||||
h = GC_hblkfreelist[i];
|
||||
while (h != 0) {
|
||||
GET_HDR(h, hhdr);
|
||||
size = hhdr->hb_sz;
|
||||
next = (struct hblk *)((word)h + size);
|
||||
GET_HDR(next, nexthdr);
|
||||
/* Coalesce with successor, if possible */
|
||||
if (0 != nexthdr && HBLK_IS_FREE(nexthdr)) {
|
||||
nextsize = nexthdr -> hb_sz;
|
||||
if (IS_MAPPED(hhdr)) {
|
||||
GC_ASSERT(!IS_MAPPED(nexthdr));
|
||||
/* make both consistent, so that we can merge */
|
||||
if (size > nextsize) {
|
||||
GC_remap((ptr_t)next, nextsize);
|
||||
} else {
|
||||
GC_unmap((ptr_t)h, size);
|
||||
hhdr -> hb_flags |= WAS_UNMAPPED;
|
||||
}
|
||||
} else if (IS_MAPPED(nexthdr)) {
|
||||
GC_ASSERT(!IS_MAPPED(hhdr));
|
||||
if (size > nextsize) {
|
||||
GC_unmap((ptr_t)next, nextsize);
|
||||
} else {
|
||||
GC_remap((ptr_t)h, size);
|
||||
hhdr -> hb_flags &= ~WAS_UNMAPPED;
|
||||
hhdr -> hb_last_reclaimed = nexthdr -> hb_last_reclaimed;
|
||||
}
|
||||
} else {
|
||||
/* Unmap any gap in the middle */
|
||||
GC_unmap_gap((ptr_t)h, size, (ptr_t)next, nexthdr -> hb_sz);
|
||||
}
|
||||
/* If they are both unmapped, we merge, but leave unmapped. */
|
||||
GC_remove_from_fl(hhdr, i);
|
||||
GC_remove_from_fl(nexthdr, FL_UNKNOWN);
|
||||
hhdr -> hb_sz += nexthdr -> hb_sz;
|
||||
GC_remove_header(next);
|
||||
GC_add_to_fl(h, hhdr);
|
||||
/* Start over at beginning of list */
|
||||
h = GC_hblkfreelist[i];
|
||||
} else /* not mergable with successor */ {
|
||||
h = hhdr -> hb_next;
|
||||
}
|
||||
} /* while (h != 0) ... */
|
||||
} /* for ... */
|
||||
}
|
||||
|
||||
#endif /* USE_MUNMAP */
|
||||
|
||||
/*
|
||||
* Return a pointer to a block starting at h of length bytes.
|
||||
* Memory for the block is mapped.
|
||||
* Remove the block from its free list, and return the remainder (if any)
|
||||
* to its appropriate free list.
|
||||
* May fail by returning 0.
|
||||
* The header for the returned block must be set up by the caller.
|
||||
* If the return value is not 0, then hhdr is the header for it.
|
||||
*/
|
||||
struct hblk * GC_get_first_part(struct hblk *h, hdr *hhdr,
|
||||
size_t bytes, int index)
|
||||
{
|
||||
word total_size = hhdr -> hb_sz;
|
||||
struct hblk * rest;
|
||||
hdr * rest_hdr;
|
||||
|
||||
GC_ASSERT((total_size & (HBLKSIZE-1)) == 0);
|
||||
GC_remove_from_fl(hhdr, index);
|
||||
if (total_size == bytes) return h;
|
||||
rest = (struct hblk *)((word)h + bytes);
|
||||
rest_hdr = GC_install_header(rest);
|
||||
if (0 == rest_hdr) {
|
||||
/* FIXME: This is likely to be very bad news ... */
|
||||
WARN("Header allocation failed: Dropping block.\n", 0);
|
||||
return(0);
|
||||
}
|
||||
rest_hdr -> hb_sz = total_size - bytes;
|
||||
rest_hdr -> hb_flags = 0;
|
||||
# ifdef GC_ASSERTIONS
|
||||
/* Mark h not free, to avoid assertion about adjacent free blocks. */
|
||||
hhdr -> hb_flags &= ~FREE_BLK;
|
||||
# endif
|
||||
GC_add_to_fl(rest, rest_hdr);
|
||||
return h;
|
||||
}
|
||||
|
||||
/*
|
||||
* H is a free block. N points at an address inside it.
|
||||
* A new header for n has already been set up. Fix up h's header
|
||||
* to reflect the fact that it is being split, move it to the
|
||||
* appropriate free list.
|
||||
* N replaces h in the original free list.
|
||||
*
|
||||
* Nhdr is not completely filled in, since it is about to allocated.
|
||||
* It may in fact end up on the wrong free list for its size.
|
||||
* (Hence adding it to a free list is silly. But this path is hopefully
|
||||
* rare enough that it doesn't matter. The code is cleaner this way.)
|
||||
*/
|
||||
void GC_split_block(struct hblk *h, hdr *hhdr, struct hblk *n,
|
||||
hdr *nhdr, int index /* Index of free list */)
|
||||
{
|
||||
word total_size = hhdr -> hb_sz;
|
||||
word h_size = (word)n - (word)h;
|
||||
struct hblk *prev = hhdr -> hb_prev;
|
||||
struct hblk *next = hhdr -> hb_next;
|
||||
|
||||
/* Replace h with n on its freelist */
|
||||
nhdr -> hb_prev = prev;
|
||||
nhdr -> hb_next = next;
|
||||
nhdr -> hb_sz = total_size - h_size;
|
||||
nhdr -> hb_flags = 0;
|
||||
if (0 != prev) {
|
||||
HDR(prev) -> hb_next = n;
|
||||
} else {
|
||||
GC_hblkfreelist[index] = n;
|
||||
}
|
||||
if (0 != next) {
|
||||
HDR(next) -> hb_prev = n;
|
||||
}
|
||||
INCR_FREE_BYTES(index, -(signed_word)h_size);
|
||||
FREE_ASSERT(GC_free_bytes[index] > 0);
|
||||
# ifdef GC_ASSERTIONS
|
||||
nhdr -> hb_flags &= ~FREE_BLK;
|
||||
/* Don't fail test for consecutive */
|
||||
/* free blocks in GC_add_to_fl. */
|
||||
# endif
|
||||
# ifdef USE_MUNMAP
|
||||
hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
|
||||
# endif
|
||||
hhdr -> hb_sz = h_size;
|
||||
GC_add_to_fl(h, hhdr);
|
||||
nhdr -> hb_flags |= FREE_BLK;
|
||||
}
|
||||
|
||||
struct hblk *
|
||||
GC_allochblk_nth(size_t sz/* bytes */, int kind, unsigned flags, int n);
|
||||
|
||||
/*
|
||||
* Allocate (and return pointer to) a heap block
|
||||
* for objects of size sz bytes, searching the nth free list.
|
||||
*
|
||||
* NOTE: We set obj_map field in header correctly.
|
||||
* Caller is responsible for building an object freelist in block.
|
||||
*
|
||||
* The client is responsible for clearing the block, if necessary.
|
||||
*/
|
||||
struct hblk *
|
||||
GC_allochblk(size_t sz, int kind, unsigned flags/* IGNORE_OFF_PAGE or 0 */)
|
||||
{
|
||||
word blocks;
|
||||
int start_list;
|
||||
int i;
|
||||
|
||||
GC_ASSERT((sz & (GRANULE_BYTES - 1)) == 0);
|
||||
blocks = OBJ_SZ_TO_BLOCKS(sz);
|
||||
start_list = GC_hblk_fl_from_blocks(blocks);
|
||||
for (i = start_list; i <= N_HBLK_FLS; ++i) {
|
||||
struct hblk * result = GC_allochblk_nth(sz, kind, flags, i);
|
||||
if (0 != result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
* The same, but with search restricted to nth free list.
|
||||
* Flags is IGNORE_OFF_PAGE or zero.
|
||||
* Unlike the above, sz is in bytes.
|
||||
*/
|
||||
struct hblk *
|
||||
GC_allochblk_nth(size_t sz, int kind, unsigned flags, int n)
|
||||
{
|
||||
struct hblk *hbp;
|
||||
hdr * hhdr; /* Header corr. to hbp */
|
||||
/* Initialized after loop if hbp !=0 */
|
||||
/* Gcc uninitialized use warning is bogus. */
|
||||
struct hblk *thishbp;
|
||||
hdr * thishdr; /* Header corr. to hbp */
|
||||
signed_word size_needed; /* number of bytes in requested objects */
|
||||
signed_word size_avail; /* bytes available in this block */
|
||||
|
||||
size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
|
||||
|
||||
/* search for a big enough block in free list */
|
||||
hbp = GC_hblkfreelist[n];
|
||||
for(; 0 != hbp; hbp = hhdr -> hb_next) {
|
||||
GET_HDR(hbp, hhdr);
|
||||
size_avail = hhdr->hb_sz;
|
||||
if (size_avail < size_needed) continue;
|
||||
if (size_avail != size_needed
|
||||
&& !GC_use_entire_heap
|
||||
&& !GC_dont_gc
|
||||
&& USED_HEAP_SIZE >= GC_requested_heapsize
|
||||
&& !TRUE_INCREMENTAL && GC_should_collect()) {
|
||||
# ifdef USE_MUNMAP
|
||||
continue;
|
||||
# else
|
||||
/* If we have enough large blocks left to cover any */
|
||||
/* previous request for large blocks, we go ahead */
|
||||
/* and split. Assuming a steady state, that should */
|
||||
/* be safe. It means that we can use the full */
|
||||
/* heap if we allocate only small objects. */
|
||||
if (!GC_enough_large_bytes_left(GC_large_allocd_bytes, n)) {
|
||||
continue;
|
||||
}
|
||||
/* If we are deallocating lots of memory from */
|
||||
/* finalizers, fail and collect sooner rather */
|
||||
/* than later. */
|
||||
if (GC_finalizer_bytes_freed > (GC_heapsize >> 4)) {
|
||||
continue;
|
||||
}
|
||||
# endif /* !USE_MUNMAP */
|
||||
}
|
||||
/* If the next heap block is obviously better, go on. */
|
||||
/* This prevents us from disassembling a single large block */
|
||||
/* to get tiny blocks. */
|
||||
{
|
||||
signed_word next_size;
|
||||
|
||||
thishbp = hhdr -> hb_next;
|
||||
if (thishbp != 0) {
|
||||
GET_HDR(thishbp, thishdr);
|
||||
next_size = (signed_word)(thishdr -> hb_sz);
|
||||
if (next_size < size_avail
|
||||
&& next_size >= size_needed
|
||||
&& !GC_is_black_listed(thishbp, (word)size_needed)) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( !IS_UNCOLLECTABLE(kind) &&
|
||||
(kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC)) {
|
||||
struct hblk * lasthbp = hbp;
|
||||
ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
|
||||
signed_word orig_avail = size_avail;
|
||||
signed_word eff_size_needed = ((flags & IGNORE_OFF_PAGE)?
|
||||
HBLKSIZE
|
||||
: size_needed);
|
||||
|
||||
|
||||
while ((ptr_t)lasthbp <= search_end
|
||||
&& (thishbp = GC_is_black_listed(lasthbp,
|
||||
(word)eff_size_needed))
|
||||
!= 0) {
|
||||
lasthbp = thishbp;
|
||||
}
|
||||
size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
|
||||
thishbp = lasthbp;
|
||||
if (size_avail >= size_needed) {
|
||||
if (thishbp != hbp &&
|
||||
0 != (thishdr = GC_install_header(thishbp))) {
|
||||
/* Make sure it's mapped before we mangle it. */
|
||||
# ifdef USE_MUNMAP
|
||||
if (!IS_MAPPED(hhdr)) {
|
||||
GC_remap((ptr_t)hbp, hhdr -> hb_sz);
|
||||
hhdr -> hb_flags &= ~WAS_UNMAPPED;
|
||||
}
|
||||
# endif
|
||||
/* Split the block at thishbp */
|
||||
GC_split_block(hbp, hhdr, thishbp, thishdr, n);
|
||||
/* Advance to thishbp */
|
||||
hbp = thishbp;
|
||||
hhdr = thishdr;
|
||||
/* We must now allocate thishbp, since it may */
|
||||
/* be on the wrong free list. */
|
||||
}
|
||||
} else if (size_needed > (signed_word)BL_LIMIT
|
||||
&& orig_avail - size_needed
|
||||
> (signed_word)BL_LIMIT) {
|
||||
/* Punt, since anything else risks unreasonable heap growth. */
|
||||
if (++GC_large_alloc_warn_suppressed
|
||||
>= GC_large_alloc_warn_interval) {
|
||||
WARN("Repeated allocation of very large block "
|
||||
"(appr. size %ld):\n"
|
||||
"\tMay lead to memory leak and poor performance.\n",
|
||||
size_needed);
|
||||
GC_large_alloc_warn_suppressed = 0;
|
||||
}
|
||||
size_avail = orig_avail;
|
||||
} else if (size_avail == 0 && size_needed == HBLKSIZE
|
||||
&& IS_MAPPED(hhdr)) {
|
||||
if (!GC_find_leak) {
|
||||
static unsigned count = 0;
|
||||
|
||||
/* The block is completely blacklisted. We need */
|
||||
/* to drop some such blocks, since otherwise we spend */
|
||||
/* all our time traversing them if pointerfree */
|
||||
/* blocks are unpopular. */
|
||||
/* A dropped block will be reconsidered at next GC. */
|
||||
if ((++count & 3) == 0) {
|
||||
/* Allocate and drop the block in small chunks, to */
|
||||
/* maximize the chance that we will recover some */
|
||||
/* later. */
|
||||
word total_size = hhdr -> hb_sz;
|
||||
struct hblk * limit = hbp + divHBLKSZ(total_size);
|
||||
struct hblk * h;
|
||||
struct hblk * prev = hhdr -> hb_prev;
|
||||
|
||||
GC_large_free_bytes -= total_size;
|
||||
GC_remove_from_fl(hhdr, n);
|
||||
for (h = hbp; h < limit; h++) {
|
||||
if (h == hbp || 0 != (hhdr = GC_install_header(h))) {
|
||||
(void) setup_header(
|
||||
hhdr, h,
|
||||
HBLKSIZE,
|
||||
PTRFREE, 0); /* Cant fail */
|
||||
if (GC_debugging_started) {
|
||||
BZERO(h, HBLKSIZE);
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Restore hbp to point at free block */
|
||||
hbp = prev;
|
||||
if (0 == hbp) {
|
||||
return GC_allochblk_nth(sz, kind, flags, n);
|
||||
}
|
||||
hhdr = HDR(hbp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if( size_avail >= size_needed ) {
|
||||
# ifdef USE_MUNMAP
|
||||
if (!IS_MAPPED(hhdr)) {
|
||||
GC_remap((ptr_t)hbp, hhdr -> hb_sz);
|
||||
hhdr -> hb_flags &= ~WAS_UNMAPPED;
|
||||
}
|
||||
# endif
|
||||
/* hbp may be on the wrong freelist; the parameter n */
|
||||
/* is important. */
|
||||
hbp = GC_get_first_part(hbp, hhdr, size_needed, n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == hbp) return 0;
|
||||
|
||||
/* Add it to map of valid blocks */
|
||||
if (!GC_install_counts(hbp, (word)size_needed)) return(0);
|
||||
/* This leaks memory under very rare conditions. */
|
||||
|
||||
/* Set up header */
|
||||
if (!setup_header(hhdr, hbp, sz, kind, flags)) {
|
||||
GC_remove_counts(hbp, (word)size_needed);
|
||||
return(0); /* ditto */
|
||||
}
|
||||
|
||||
/* Notify virtual dirty bit implementation that we are about to write. */
|
||||
/* Ensure that pointerfree objects are not protected if it's avoidable. */
|
||||
GC_remove_protection(hbp, divHBLKSZ(size_needed),
|
||||
(hhdr -> hb_descr == 0) /* pointer-free */);
|
||||
|
||||
/* We just successfully allocated a block. Restart count of */
|
||||
/* consecutive failures. */
|
||||
{
|
||||
extern unsigned GC_fail_count;
|
||||
|
||||
GC_fail_count = 0;
|
||||
}
|
||||
|
||||
GC_large_free_bytes -= size_needed;
|
||||
|
||||
GC_ASSERT(IS_MAPPED(hhdr));
|
||||
return( hbp );
|
||||
}
|
||||
|
||||
struct hblk * GC_freehblk_ptr = 0; /* Search position hint for GC_freehblk */
|
||||
|
||||
/*
|
||||
* Free a heap block.
|
||||
*
|
||||
* Coalesce the block with its neighbors if possible.
|
||||
*
|
||||
* All mark words are assumed to be cleared.
|
||||
*/
|
||||
void
|
||||
GC_freehblk(struct hblk *hbp)
|
||||
{
|
||||
struct hblk *next, *prev;
|
||||
hdr *hhdr, *prevhdr, *nexthdr;
|
||||
signed_word size;
|
||||
|
||||
|
||||
GET_HDR(hbp, hhdr);
|
||||
size = hhdr->hb_sz;
|
||||
size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
|
||||
GC_remove_counts(hbp, (word)size);
|
||||
hhdr->hb_sz = size;
|
||||
# ifdef USE_MUNMAP
|
||||
hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
|
||||
# endif
|
||||
|
||||
/* Check for duplicate deallocation in the easy case */
|
||||
if (HBLK_IS_FREE(hhdr)) {
|
||||
GC_printf("Duplicate large block deallocation of %p\n", hbp);
|
||||
ABORT("Duplicate large block deallocation");
|
||||
}
|
||||
|
||||
GC_ASSERT(IS_MAPPED(hhdr));
|
||||
hhdr -> hb_flags |= FREE_BLK;
|
||||
next = (struct hblk *)((word)hbp + size);
|
||||
GET_HDR(next, nexthdr);
|
||||
prev = GC_free_block_ending_at(hbp);
|
||||
/* Coalesce with successor, if possible */
|
||||
if(0 != nexthdr && HBLK_IS_FREE(nexthdr) && IS_MAPPED(nexthdr)) {
|
||||
GC_remove_from_fl(nexthdr, FL_UNKNOWN);
|
||||
hhdr -> hb_sz += nexthdr -> hb_sz;
|
||||
GC_remove_header(next);
|
||||
}
|
||||
/* Coalesce with predecessor, if possible. */
|
||||
if (0 != prev) {
|
||||
prevhdr = HDR(prev);
|
||||
if (IS_MAPPED(prevhdr)) {
|
||||
GC_remove_from_fl(prevhdr, FL_UNKNOWN);
|
||||
prevhdr -> hb_sz += hhdr -> hb_sz;
|
||||
# ifdef USE_MUNMAP
|
||||
prevhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
|
||||
# endif
|
||||
GC_remove_header(hbp);
|
||||
hbp = prev;
|
||||
hhdr = prevhdr;
|
||||
}
|
||||
}
|
||||
/* FIXME: It is not clear we really always want to do these merges */
|
||||
/* with -DUSE_MUNMAP, since it updates ages and hence prevents */
|
||||
/* unmapping. */
|
||||
|
||||
GC_large_free_bytes += size;
|
||||
GC_add_to_fl(hbp, hhdr);
|
||||
}
|
||||
|
||||
1023
src/engine/boehm_gc/alloc.c
Normal file
1023
src/engine/boehm_gc/alloc.c
Normal file
File diff suppressed because it is too large
Load Diff
86
src/engine/boehm_gc/alpha_mach_dep.S
Normal file
86
src/engine/boehm_gc/alpha_mach_dep.S
Normal file
@@ -0,0 +1,86 @@
|
||||
.arch ev6
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.globl GC_push_regs
|
||||
.ent GC_push_regs 2
|
||||
GC_push_regs:
|
||||
ldgp $gp, 0($27)
|
||||
lda $sp, -16($sp)
|
||||
stq $26, 0($sp)
|
||||
.mask 0x04000000, 0
|
||||
.frame $sp, 16, $26, 0
|
||||
|
||||
/* $0 integer result */
|
||||
/* $1-$8 temp regs - not preserved cross calls */
|
||||
/* $9-$15 call saved regs */
|
||||
/* $16-$21 argument regs - not preserved cross calls */
|
||||
/* $22-$28 temp regs - not preserved cross calls */
|
||||
/* $29 global pointer - not preserved cross calls */
|
||||
/* $30 stack pointer */
|
||||
|
||||
# define call_push(x) \
|
||||
mov x, $16; \
|
||||
jsr $26, GC_push_one; \
|
||||
ldgp $gp, 0($26)
|
||||
|
||||
call_push($9)
|
||||
call_push($10)
|
||||
call_push($11)
|
||||
call_push($12)
|
||||
call_push($13)
|
||||
call_push($14)
|
||||
call_push($15)
|
||||
|
||||
/* $f0-$f1 floating point results */
|
||||
/* $f2-$f9 call saved regs */
|
||||
/* $f10-$f30 temp regs - not preserved cross calls */
|
||||
|
||||
/* Use the most efficient transfer method for this hardware. */
|
||||
/* Bit 1 detects the FIX extension, which includes ftoit. */
|
||||
amask 2, $0
|
||||
bne $0, $use_stack
|
||||
|
||||
#undef call_push
|
||||
#define call_push(x) \
|
||||
ftoit x, $16; \
|
||||
jsr $26, GC_push_one; \
|
||||
ldgp $gp, 0($26)
|
||||
|
||||
call_push($f2)
|
||||
call_push($f3)
|
||||
call_push($f4)
|
||||
call_push($f5)
|
||||
call_push($f6)
|
||||
call_push($f7)
|
||||
call_push($f8)
|
||||
call_push($f9)
|
||||
|
||||
ldq $26, 0($sp)
|
||||
lda $sp, 16($sp)
|
||||
ret $31, ($26), 1
|
||||
|
||||
.align 4
|
||||
$use_stack:
|
||||
|
||||
#undef call_push
|
||||
#define call_push(x) \
|
||||
stt x, 8($sp); \
|
||||
ldq $16, 8($sp); \
|
||||
jsr $26, GC_push_one; \
|
||||
ldgp $gp, 0($26)
|
||||
|
||||
call_push($f2)
|
||||
call_push($f3)
|
||||
call_push($f4)
|
||||
call_push($f5)
|
||||
call_push($f6)
|
||||
call_push($f7)
|
||||
call_push($f8)
|
||||
call_push($f9)
|
||||
|
||||
ldq $26, 0($sp)
|
||||
lda $sp, 16($sp)
|
||||
ret $31, ($26), 1
|
||||
|
||||
.end GC_push_regs
|
||||
469
src/engine/boehm_gc/backgraph.c
Normal file
469
src/engine/boehm_gc/backgraph.c
Normal file
@@ -0,0 +1,469 @@
|
||||
/*
|
||||
* Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* This implements a full, though not well-tuned, representation of the
|
||||
* backwards points-to graph. This is used to test for non-GC-robust
|
||||
* data structures; the code is not used during normal garbage collection.
|
||||
*
|
||||
* One restriction is that we drop all back-edges from nodes with very
|
||||
* high in-degree, and simply add them add them to a list of such
|
||||
* nodes. They are then treated as permanent roots. Id this by itself
|
||||
* doesn't introduce a space leak, then such nodes can't contribute to
|
||||
* a growing space leak.
|
||||
*/
|
||||
|
||||
#ifdef MAKE_BACK_GRAPH
|
||||
|
||||
#define MAX_IN 10 /* Maximum in-degree we handle directly */
|
||||
|
||||
#include "private/dbg_mlc.h"
|
||||
#include <unistd.h>
|
||||
|
||||
#if !defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) || !defined(UNIX_LIKE)
|
||||
# error Configuration doesnt support MAKE_BACK_GRAPH
|
||||
#endif
|
||||
|
||||
/* We store single back pointers directly in the object's oh_bg_ptr field. */
|
||||
/* If there is more than one ptr to an object, we store q | FLAG_MANY, */
|
||||
/* where q is a pointer to a back_edges object. */
|
||||
/* Every once in a while we use a back_edges object even for a single */
|
||||
/* pointer, since we need the other fields in the back_edges structure to */
|
||||
/* be present in some fraction of the objects. Otherwise we get serious */
|
||||
/* performance issues. */
|
||||
#define FLAG_MANY 2
|
||||
|
||||
typedef struct back_edges_struct {
|
||||
word n_edges; /* Number of edges, including those in continuation */
|
||||
/* structures. */
|
||||
unsigned short flags;
|
||||
# define RETAIN 1 /* Directly points to a reachable object; */
|
||||
/* retain for next GC. */
|
||||
unsigned short height_gc_no;
|
||||
/* If height > 0, then the GC_gc_no value when it */
|
||||
/* was computed. If it was computed this cycle, then */
|
||||
/* it is current. If it was computed during the */
|
||||
/* last cycle, then it represents the old height, */
|
||||
/* which is only saved for live objects referenced by */
|
||||
/* dead ones. This may grow due to refs from newly */
|
||||
/* dead objects. */
|
||||
signed_word height;
|
||||
/* Longest path through unreachable nodes to this node */
|
||||
/* that we found using depth first search. */
|
||||
|
||||
# define HEIGHT_UNKNOWN ((signed_word)(-2))
|
||||
# define HEIGHT_IN_PROGRESS ((signed_word)(-1))
|
||||
ptr_t edges[MAX_IN];
|
||||
struct back_edges_struct *cont;
|
||||
/* Pointer to continuation structure; we use only the */
|
||||
/* edges field in the continuation. */
|
||||
/* also used as free list link. */
|
||||
} back_edges;
|
||||
|
||||
/* Allocate a new back edge structure. Should be more sophisticated */
|
||||
/* if this were production code. */
|
||||
#define MAX_BACK_EDGE_STRUCTS 100000
|
||||
static back_edges *back_edge_space = 0;
|
||||
int GC_n_back_edge_structs = 0; /* Serves as pointer to never used */
|
||||
/* back_edges space. */
|
||||
static back_edges *avail_back_edges = 0;
|
||||
/* Pointer to free list of deallocated */
|
||||
/* back_edges structures. */
|
||||
|
||||
static back_edges * new_back_edges(void)
|
||||
{
|
||||
if (0 == back_edge_space) {
|
||||
back_edge_space = (back_edges *)
|
||||
GET_MEM(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
|
||||
}
|
||||
if (0 != avail_back_edges) {
|
||||
back_edges * result = avail_back_edges;
|
||||
avail_back_edges = result -> cont;
|
||||
result -> cont = 0;
|
||||
return result;
|
||||
}
|
||||
if (GC_n_back_edge_structs >= MAX_BACK_EDGE_STRUCTS - 1) {
|
||||
ABORT("needed too much space for back edges: adjust "
|
||||
"MAX_BACK_EDGE_STRUCTS");
|
||||
}
|
||||
return back_edge_space + (GC_n_back_edge_structs++);
|
||||
}
|
||||
|
||||
/* Deallocate p and its associated continuation structures. */
|
||||
static void deallocate_back_edges(back_edges *p)
|
||||
{
|
||||
back_edges *last = p;
|
||||
|
||||
while (0 != last -> cont) last = last -> cont;
|
||||
last -> cont = avail_back_edges;
|
||||
avail_back_edges = p;
|
||||
}
|
||||
|
||||
/* Table of objects that are currently on the depth-first search */
|
||||
/* stack. Only objects with in-degree one are in this table. */
|
||||
/* Other objects are identified using HEIGHT_IN_PROGRESS. */
|
||||
/* FIXME: This data structure NEEDS IMPROVEMENT. */
|
||||
#define INITIAL_IN_PROGRESS 10000
|
||||
static ptr_t * in_progress_space = 0;
|
||||
static size_t in_progress_size = 0;
|
||||
static size_t n_in_progress = 0;
|
||||
|
||||
static void push_in_progress(ptr_t p)
|
||||
{
|
||||
if (n_in_progress >= in_progress_size)
|
||||
if (in_progress_size == 0) {
|
||||
in_progress_size = INITIAL_IN_PROGRESS;
|
||||
in_progress_space = (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
|
||||
} else {
|
||||
ptr_t * new_in_progress_space;
|
||||
in_progress_size *= 2;
|
||||
new_in_progress_space = (ptr_t *)
|
||||
GET_MEM(in_progress_size * sizeof(ptr_t));
|
||||
BCOPY(in_progress_space, new_in_progress_space,
|
||||
n_in_progress * sizeof(ptr_t));
|
||||
in_progress_space = new_in_progress_space;
|
||||
/* FIXME: This just drops the old space. */
|
||||
}
|
||||
if (in_progress_space == 0)
|
||||
ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
|
||||
"Huge linear data structure?");
|
||||
in_progress_space[n_in_progress++] = p;
|
||||
}
|
||||
|
||||
static GC_bool is_in_progress(ptr_t p)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < n_in_progress; ++i) {
|
||||
if (in_progress_space[i] == p) return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void pop_in_progress(ptr_t p)
|
||||
{
|
||||
--n_in_progress;
|
||||
GC_ASSERT(in_progress_space[n_in_progress] == p);
|
||||
}
|
||||
|
||||
#define GET_OH_BG_PTR(p) \
|
||||
(ptr_t)REVEAL_POINTER(((oh *)(p)) -> oh_bg_ptr)
|
||||
#define SET_OH_BG_PTR(p,q) (((oh *)(p)) -> oh_bg_ptr) = HIDE_POINTER(q)
|
||||
|
||||
/* Execute s once for each predecessor q of p in the points-to graph. */
|
||||
/* s should be a bracketed statement. We declare q. */
|
||||
#define FOR_EACH_PRED(q, p, s) \
|
||||
{ \
|
||||
ptr_t q = GET_OH_BG_PTR(p); \
|
||||
if (!((word)q & FLAG_MANY)) { \
|
||||
if (q && !((word)q & 1)) s \
|
||||
/* !((word)q & 1) checks for a misnterpreted freelist link */ \
|
||||
} else { \
|
||||
back_edges *orig_be_ = (back_edges *)((word)q & ~FLAG_MANY); \
|
||||
back_edges *be_ = orig_be_; \
|
||||
int total_, local_; \
|
||||
int n_edges_ = be_ -> n_edges; \
|
||||
for (total_ = 0, local_ = 0; total_ < n_edges_; ++local_, ++total_) { \
|
||||
if (local_ == MAX_IN) { \
|
||||
be_ = be_ -> cont; \
|
||||
local_ = 0; \
|
||||
} \
|
||||
q = be_ -> edges[local_]; s \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
/* Ensure that p has a back_edges structure associated with it. */
|
||||
static void ensure_struct(ptr_t p)
|
||||
{
|
||||
ptr_t old_back_ptr = GET_OH_BG_PTR(p);
|
||||
|
||||
if (!((word)old_back_ptr & FLAG_MANY)) {
|
||||
back_edges *be = new_back_edges();
|
||||
be -> flags = 0;
|
||||
if (0 == old_back_ptr) {
|
||||
be -> n_edges = 0;
|
||||
} else {
|
||||
be -> n_edges = 1;
|
||||
be -> edges[0] = old_back_ptr;
|
||||
}
|
||||
be -> height = HEIGHT_UNKNOWN;
|
||||
be -> height_gc_no = GC_gc_no - 1;
|
||||
GC_ASSERT(be >= back_edge_space);
|
||||
SET_OH_BG_PTR(p, (word)be | FLAG_MANY);
|
||||
}
|
||||
}
|
||||
|
||||
/* Add the (forward) edge from p to q to the backward graph. Both p */
|
||||
/* q are pointers to the object base, i.e. pointers to an oh. */
|
||||
static void add_edge(ptr_t p, ptr_t q)
|
||||
{
|
||||
ptr_t old_back_ptr = GET_OH_BG_PTR(q);
|
||||
back_edges * be, *be_cont;
|
||||
word i;
|
||||
static unsigned random_number = 13;
|
||||
# define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0)
|
||||
/* A not very random number we use to occasionally allocate a */
|
||||
/* back_edges structure even for a single backward edge. This */
|
||||
/* prevents us from repeatedly tracing back through very long */
|
||||
/* chains, since we will have some place to store height and */
|
||||
/* in_progress flags along the way. */
|
||||
|
||||
GC_ASSERT(p == GC_base(p) && q == GC_base(q));
|
||||
if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) {
|
||||
/* This is really a misinterpreted free list link, since we saw */
|
||||
/* a pointer to a free list. Dont overwrite it! */
|
||||
return;
|
||||
}
|
||||
if (0 == old_back_ptr) {
|
||||
SET_OH_BG_PTR(q, p);
|
||||
if (GOT_LUCKY_NUMBER) ensure_struct(q);
|
||||
return;
|
||||
}
|
||||
/* Check whether it was already in the list of predecessors. */
|
||||
FOR_EACH_PRED(pred, q, { if (p == pred) return; });
|
||||
ensure_struct(q);
|
||||
old_back_ptr = GET_OH_BG_PTR(q);
|
||||
be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
|
||||
for (i = be -> n_edges, be_cont = be; i > MAX_IN;
|
||||
be_cont = be_cont -> cont, i -= MAX_IN) {}
|
||||
if (i == MAX_IN) {
|
||||
be_cont -> cont = new_back_edges();
|
||||
be_cont = be_cont -> cont;
|
||||
i = 0;
|
||||
}
|
||||
be_cont -> edges[i] = p;
|
||||
be -> n_edges++;
|
||||
if (be -> n_edges == 100) {
|
||||
# if 0
|
||||
if (GC_print_stats) {
|
||||
GC_err_printf("The following object has in-degree >= 100:\n");
|
||||
GC_print_heap_obj(q);
|
||||
}
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
typedef void (*per_object_func)(ptr_t p, size_t n_bytes, word gc_descr);
|
||||
|
||||
static void per_object_helper(struct hblk *h, word fn)
|
||||
{
|
||||
hdr * hhdr = HDR(h);
|
||||
size_t sz = hhdr -> hb_sz;
|
||||
word descr = hhdr -> hb_descr;
|
||||
per_object_func f = (per_object_func)fn;
|
||||
int i = 0;
|
||||
|
||||
do {
|
||||
f((ptr_t)(h -> hb_body + i), sz, descr);
|
||||
i += sz;
|
||||
} while (i + sz <= BYTES_TO_WORDS(HBLKSIZE));
|
||||
}
|
||||
|
||||
void GC_apply_to_each_object(per_object_func f)
|
||||
{
|
||||
GC_apply_to_all_blocks(per_object_helper, (word)f);
|
||||
}
|
||||
|
||||
static void reset_back_edge(ptr_t p, size_t n_bytes, word gc_descr)
|
||||
{
|
||||
/* Skip any free list links, or dropped blocks */
|
||||
if (GC_HAS_DEBUG_INFO(p)) {
|
||||
ptr_t old_back_ptr = GET_OH_BG_PTR(p);
|
||||
if ((word)old_back_ptr & FLAG_MANY) {
|
||||
back_edges *be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
|
||||
if (!(be -> flags & RETAIN)) {
|
||||
deallocate_back_edges(be);
|
||||
SET_OH_BG_PTR(p, 0);
|
||||
} else {
|
||||
word *currentp;
|
||||
|
||||
GC_ASSERT(GC_is_marked(p));
|
||||
|
||||
/* Back edges may point to objects that will not be retained. */
|
||||
/* Delete them for now, but remember the height. */
|
||||
/* Some will be added back at next GC. */
|
||||
be -> n_edges = 0;
|
||||
if (0 != be -> cont) {
|
||||
deallocate_back_edges(be -> cont);
|
||||
be -> cont = 0;
|
||||
}
|
||||
|
||||
GC_ASSERT(GC_is_marked(p));
|
||||
|
||||
/* We only retain things for one GC cycle at a time. */
|
||||
be -> flags &= ~RETAIN;
|
||||
}
|
||||
} else /* Simple back pointer */ {
|
||||
/* Clear to avoid dangling pointer. */
|
||||
SET_OH_BG_PTR(p, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void add_back_edges(ptr_t p, size_t n_bytes, word gc_descr)
|
||||
{
|
||||
word *currentp = (word *)(p + sizeof(oh));
|
||||
|
||||
/* For now, fix up non-length descriptors conservatively. */
|
||||
if((gc_descr & GC_DS_TAGS) != GC_DS_LENGTH) {
|
||||
gc_descr = n_bytes;
|
||||
}
|
||||
while (currentp < (word *)(p + gc_descr)) {
|
||||
word current = *currentp++;
|
||||
FIXUP_POINTER(current);
|
||||
if (current >= (word)GC_least_plausible_heap_addr &&
|
||||
current <= (word)GC_greatest_plausible_heap_addr) {
|
||||
ptr_t target = GC_base((void *)current);
|
||||
if (0 != target) {
|
||||
add_edge(p, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Rebuild the representation of the backward reachability graph. */
|
||||
/* Does not examine mark bits. Can be called before GC. */
|
||||
void GC_build_back_graph(void)
|
||||
{
|
||||
GC_apply_to_each_object(add_back_edges);
|
||||
}
|
||||
|
||||
/* Return an approximation to the length of the longest simple path */
|
||||
/* through unreachable objects to p. We refer to this as the height */
|
||||
/* of p. */
|
||||
static word backwards_height(ptr_t p)
|
||||
{
|
||||
word result;
|
||||
ptr_t back_ptr = GET_OH_BG_PTR(p);
|
||||
back_edges *be;
|
||||
|
||||
if (0 == back_ptr) return 1;
|
||||
if (!((word)back_ptr & FLAG_MANY)) {
|
||||
if (is_in_progress(p)) return 0; /* DFS back edge, i.e. we followed */
|
||||
/* an edge to an object already */
|
||||
/* on our stack: ignore */
|
||||
push_in_progress(p);
|
||||
result = backwards_height(back_ptr)+1;
|
||||
pop_in_progress(p);
|
||||
return result;
|
||||
}
|
||||
be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
|
||||
if (be -> height >= 0 && be -> height_gc_no == GC_gc_no)
|
||||
return be -> height;
|
||||
/* Ignore back edges in DFS */
|
||||
if (be -> height == HEIGHT_IN_PROGRESS) return 0;
|
||||
result = (be -> height > 0? be -> height : 1);
|
||||
be -> height = HEIGHT_IN_PROGRESS;
|
||||
FOR_EACH_PRED(q, p, {
|
||||
word this_height;
|
||||
if (GC_is_marked(q) && !(FLAG_MANY & (word)GET_OH_BG_PTR(p))) {
|
||||
if (GC_print_stats)
|
||||
GC_log_printf("Found bogus pointer from 0x%lx to 0x%lx\n", q, p);
|
||||
/* Reachable object "points to" unreachable one. */
|
||||
/* Could be caused by our lax treatment of GC descriptors. */
|
||||
this_height = 1;
|
||||
} else {
|
||||
this_height = backwards_height(q);
|
||||
}
|
||||
if (this_height >= result) result = this_height + 1;
|
||||
});
|
||||
be -> height = result;
|
||||
be -> height_gc_no = GC_gc_no;
|
||||
return result;
|
||||
}
|
||||
|
||||
word GC_max_height;
|
||||
ptr_t GC_deepest_obj;
|
||||
|
||||
/* Compute the maximum height of every unreachable predecessor p of a */
|
||||
/* reachable object. Arrange to save the heights of all such objects p */
|
||||
/* so that they can be used in calculating the height of objects in the */
|
||||
/* next GC. */
|
||||
/* Set GC_max_height to be the maximum height we encounter, and */
|
||||
/* GC_deepest_obj to be the corresponding object. */
|
||||
static void update_max_height(ptr_t p, size_t n_bytes, word gc_descr)
|
||||
{
|
||||
if (GC_is_marked(p) && GC_HAS_DEBUG_INFO(p)) {
|
||||
int i;
|
||||
word p_height = 0;
|
||||
ptr_t p_deepest_obj = 0;
|
||||
ptr_t back_ptr;
|
||||
back_edges *be = 0;
|
||||
|
||||
/* If we remembered a height last time, use it as a minimum. */
|
||||
/* It may have increased due to newly unreachable chains pointing */
|
||||
/* to p, but it can't have decreased. */
|
||||
back_ptr = GET_OH_BG_PTR(p);
|
||||
if (0 != back_ptr && ((word)back_ptr & FLAG_MANY)) {
|
||||
be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
|
||||
if (be -> height != HEIGHT_UNKNOWN) p_height = be -> height;
|
||||
}
|
||||
FOR_EACH_PRED(q, p, {
|
||||
if (!GC_is_marked(q) && GC_HAS_DEBUG_INFO(q)) {
|
||||
word q_height;
|
||||
|
||||
q_height = backwards_height(q);
|
||||
if (q_height > p_height) {
|
||||
p_height = q_height;
|
||||
p_deepest_obj = q;
|
||||
}
|
||||
}
|
||||
});
|
||||
if (p_height > 0) {
|
||||
/* Remember the height for next time. */
|
||||
if (be == 0) {
|
||||
ensure_struct(p);
|
||||
back_ptr = GET_OH_BG_PTR(p);
|
||||
be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
|
||||
}
|
||||
be -> flags |= RETAIN;
|
||||
be -> height = p_height;
|
||||
be -> height_gc_no = GC_gc_no;
|
||||
}
|
||||
if (p_height > GC_max_height) {
|
||||
GC_max_height = p_height;
|
||||
GC_deepest_obj = p_deepest_obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
word GC_max_max_height = 0;
|
||||
|
||||
void GC_traverse_back_graph(void)
|
||||
{
|
||||
GC_max_height = 0;
|
||||
GC_apply_to_each_object(update_max_height);
|
||||
if (0 != GC_deepest_obj)
|
||||
GC_set_mark_bit(GC_deepest_obj); /* Keep it until we can print it. */
|
||||
}
|
||||
|
||||
void GC_print_back_graph_stats(void)
|
||||
{
|
||||
GC_printf("Maximum backwards height of reachable objects at GC %lu is %ld\n",
|
||||
(unsigned long) GC_gc_no, (unsigned long)GC_max_height);
|
||||
if (GC_max_height > GC_max_max_height) {
|
||||
GC_max_max_height = GC_max_height;
|
||||
GC_printf("The following unreachable object is last in a longest chain "
|
||||
"of unreachable objects:\n");
|
||||
GC_print_heap_obj(GC_deepest_obj);
|
||||
}
|
||||
if (GC_print_stats) {
|
||||
GC_log_printf("Needed max total of %ld back-edge structs\n",
|
||||
GC_n_back_edge_structs);
|
||||
}
|
||||
GC_apply_to_each_object(reset_back_edge);
|
||||
GC_deepest_obj = 0;
|
||||
}
|
||||
|
||||
#endif /* MAKE_BACK_GRAPH */
|
||||
10
src/engine/boehm_gc/bdw-gc.pc
Normal file
10
src/engine/boehm_gc/bdw-gc.pc
Normal file
@@ -0,0 +1,10 @@
|
||||
prefix=/usr/local
|
||||
exec_prefix=${prefix}
|
||||
libdir=${exec_prefix}/lib
|
||||
includedir=${prefix}/include
|
||||
|
||||
Name: Boehm-Demers-Weiser Conservative Garbage Collector
|
||||
Description: A garbage collector for C and C++
|
||||
Version: 7.0
|
||||
Libs: -L${libdir} -lgc
|
||||
Cflags: -I${includedir}
|
||||
10
src/engine/boehm_gc/bdw-gc.pc.in
Normal file
10
src/engine/boehm_gc/bdw-gc.pc.in
Normal file
@@ -0,0 +1,10 @@
|
||||
prefix=@prefix@
|
||||
exec_prefix=@exec_prefix@
|
||||
libdir=@libdir@
|
||||
includedir=@includedir@
|
||||
|
||||
Name: Boehm-Demers-Weiser Conservative Garbage Collector
|
||||
Description: A garbage collector for C and C++
|
||||
Version: @PACKAGE_VERSION@
|
||||
Libs: -L${libdir} -lgc
|
||||
Cflags: -I${includedir}
|
||||
285
src/engine/boehm_gc/blacklst.c
Normal file
285
src/engine/boehm_gc/blacklst.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
||||
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
/* Boehm, August 9, 1995 6:09 pm PDT */
|
||||
# include "private/gc_priv.h"
|
||||
|
||||
/*
|
||||
* We maintain several hash tables of hblks that have had false hits.
|
||||
* Each contains one bit per hash bucket; If any page in the bucket
|
||||
* has had a false hit, we assume that all of them have.
|
||||
* See the definition of page_hash_table in gc_private.h.
|
||||
* False hits from the stack(s) are much more dangerous than false hits
|
||||
* from elsewhere, since the former can pin a large object that spans the
|
||||
* block, eventhough it does not start on the dangerous block.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Externally callable routines are:
|
||||
|
||||
* GC_add_to_black_list_normal
|
||||
* GC_add_to_black_list_stack
|
||||
* GC_promote_black_lists
|
||||
* GC_is_black_listed
|
||||
*
|
||||
* All require that the allocator lock is held.
|
||||
*/
|
||||
|
||||
/* Pointers to individual tables. We replace one table by another by */
|
||||
/* switching these pointers. */
|
||||
word * GC_old_normal_bl;
|
||||
/* Nonstack false references seen at last full */
|
||||
/* collection. */
|
||||
word * GC_incomplete_normal_bl;
|
||||
/* Nonstack false references seen since last */
|
||||
/* full collection. */
|
||||
word * GC_old_stack_bl;
|
||||
word * GC_incomplete_stack_bl;
|
||||
|
||||
word GC_total_stack_black_listed;
|
||||
|
||||
word GC_black_list_spacing = MINHINCR*HBLKSIZE; /* Initial rough guess */
|
||||
|
||||
void GC_clear_bl(word *);
|
||||
|
||||
void GC_default_print_heap_obj_proc(ptr_t p)
|
||||
{
|
||||
ptr_t base = GC_base(p);
|
||||
|
||||
GC_err_printf("start: %p, appr. length: %ld", base,
|
||||
(unsigned long)GC_size(base));
|
||||
}
|
||||
|
||||
void (*GC_print_heap_obj) (ptr_t p) = GC_default_print_heap_obj_proc;
|
||||
|
||||
void GC_print_source_ptr(ptr_t p)
|
||||
{
|
||||
ptr_t base = GC_base(p);
|
||||
if (0 == base) {
|
||||
if (0 == p) {
|
||||
GC_err_printf("in register");
|
||||
} else {
|
||||
GC_err_printf("in root set");
|
||||
}
|
||||
} else {
|
||||
GC_err_printf("in object at ");
|
||||
(*GC_print_heap_obj)(base);
|
||||
}
|
||||
}
|
||||
|
||||
void GC_bl_init(void)
|
||||
{
|
||||
if (!GC_all_interior_pointers) {
|
||||
GC_old_normal_bl = (word *)
|
||||
GC_scratch_alloc((word)(sizeof (page_hash_table)));
|
||||
GC_incomplete_normal_bl = (word *)GC_scratch_alloc
|
||||
((word)(sizeof(page_hash_table)));
|
||||
if (GC_old_normal_bl == 0 || GC_incomplete_normal_bl == 0) {
|
||||
GC_err_printf("Insufficient memory for black list\n");
|
||||
EXIT();
|
||||
}
|
||||
GC_clear_bl(GC_old_normal_bl);
|
||||
GC_clear_bl(GC_incomplete_normal_bl);
|
||||
}
|
||||
GC_old_stack_bl = (word *)GC_scratch_alloc((word)(sizeof(page_hash_table)));
|
||||
GC_incomplete_stack_bl = (word *)GC_scratch_alloc
|
||||
((word)(sizeof(page_hash_table)));
|
||||
if (GC_old_stack_bl == 0 || GC_incomplete_stack_bl == 0) {
|
||||
GC_err_printf("Insufficient memory for black list\n");
|
||||
EXIT();
|
||||
}
|
||||
GC_clear_bl(GC_old_stack_bl);
|
||||
GC_clear_bl(GC_incomplete_stack_bl);
|
||||
}
|
||||
|
||||
void GC_clear_bl(word *doomed)
|
||||
{
|
||||
BZERO(doomed, sizeof(page_hash_table));
|
||||
}
|
||||
|
||||
void GC_copy_bl(word *old, word *new)
|
||||
{
|
||||
BCOPY(old, new, sizeof(page_hash_table));
|
||||
}
|
||||
|
||||
static word total_stack_black_listed(void);
|
||||
|
||||
/* Signal the completion of a collection. Turn the incomplete black */
|
||||
/* lists into new black lists, etc. */
|
||||
void GC_promote_black_lists(void)
|
||||
{
|
||||
word * very_old_normal_bl = GC_old_normal_bl;
|
||||
word * very_old_stack_bl = GC_old_stack_bl;
|
||||
|
||||
GC_old_normal_bl = GC_incomplete_normal_bl;
|
||||
GC_old_stack_bl = GC_incomplete_stack_bl;
|
||||
if (!GC_all_interior_pointers) {
|
||||
GC_clear_bl(very_old_normal_bl);
|
||||
}
|
||||
GC_clear_bl(very_old_stack_bl);
|
||||
GC_incomplete_normal_bl = very_old_normal_bl;
|
||||
GC_incomplete_stack_bl = very_old_stack_bl;
|
||||
GC_total_stack_black_listed = total_stack_black_listed();
|
||||
if (GC_print_stats == VERBOSE)
|
||||
GC_log_printf("%ld bytes in heap blacklisted for interior pointers\n",
|
||||
(unsigned long)GC_total_stack_black_listed);
|
||||
if (GC_total_stack_black_listed != 0) {
|
||||
GC_black_list_spacing =
|
||||
HBLKSIZE*(GC_heapsize/GC_total_stack_black_listed);
|
||||
}
|
||||
if (GC_black_list_spacing < 3 * HBLKSIZE) {
|
||||
GC_black_list_spacing = 3 * HBLKSIZE;
|
||||
}
|
||||
if (GC_black_list_spacing > MAXHINCR * HBLKSIZE) {
|
||||
GC_black_list_spacing = MAXHINCR * HBLKSIZE;
|
||||
/* Makes it easier to allocate really huge blocks, which otherwise */
|
||||
/* may have problems with nonuniform blacklist distributions. */
|
||||
/* This way we should always succeed immediately after growing the */
|
||||
/* heap. */
|
||||
}
|
||||
}
|
||||
|
||||
void GC_unpromote_black_lists(void)
|
||||
{
|
||||
if (!GC_all_interior_pointers) {
|
||||
GC_copy_bl(GC_old_normal_bl, GC_incomplete_normal_bl);
|
||||
}
|
||||
GC_copy_bl(GC_old_stack_bl, GC_incomplete_stack_bl);
|
||||
}
|
||||
|
||||
/* P is not a valid pointer reference, but it falls inside */
|
||||
/* the plausible heap bounds. */
|
||||
/* Add it to the normal incomplete black list if appropriate. */
|
||||
#ifdef PRINT_BLACK_LIST
|
||||
void GC_add_to_black_list_normal(word p, ptr_t source)
|
||||
#else
|
||||
void GC_add_to_black_list_normal(word p)
|
||||
#endif
|
||||
{
|
||||
if (!(GC_modws_valid_offsets[p & (sizeof(word)-1)])) return;
|
||||
{
|
||||
word index = PHT_HASH((word)p);
|
||||
|
||||
if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_normal_bl, index)) {
|
||||
# ifdef PRINT_BLACK_LIST
|
||||
if (!get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
|
||||
GC_err_printf(
|
||||
"Black listing (normal) %p referenced from %p ",
|
||||
(ptr_t) p, source);
|
||||
GC_print_source_ptr(source);
|
||||
GC_err_puts("\n");
|
||||
}
|
||||
# endif
|
||||
set_pht_entry_from_index(GC_incomplete_normal_bl, index);
|
||||
} /* else this is probably just an interior pointer to an allocated */
|
||||
/* object, and isn't worth black listing. */
|
||||
}
|
||||
}
|
||||
|
||||
/* And the same for false pointers from the stack. */
|
||||
#ifdef PRINT_BLACK_LIST
|
||||
void GC_add_to_black_list_stack(word p, ptr_t source)
|
||||
ptr_t source;
|
||||
#else
|
||||
void GC_add_to_black_list_stack(word p)
|
||||
#endif
|
||||
{
|
||||
word index = PHT_HASH((word)p);
|
||||
|
||||
if (HDR(p) == 0 || get_pht_entry_from_index(GC_old_stack_bl, index)) {
|
||||
# ifdef PRINT_BLACK_LIST
|
||||
if (!get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
|
||||
GC_err_printf(
|
||||
"Black listing (stack) %p referenced from %p ",
|
||||
(ptr_t)p, source);
|
||||
GC_print_source_ptr(source);
|
||||
GC_err_puts("\n");
|
||||
}
|
||||
# endif
|
||||
set_pht_entry_from_index(GC_incomplete_stack_bl, index);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Is the block starting at h of size len bytes black listed? If so,
|
||||
* return the address of the next plausible r such that (r, len) might not
|
||||
* be black listed. (R may not actually be in the heap. We guarantee only
|
||||
* that every smaller value of r after h is also black listed.)
|
||||
* If (h,len) is not black listed, return 0.
|
||||
* Knows about the structure of the black list hash tables.
|
||||
*/
|
||||
struct hblk * GC_is_black_listed(struct hblk *h, word len)
|
||||
{
|
||||
word index = PHT_HASH((word)h);
|
||||
word i;
|
||||
word nblocks = divHBLKSZ(len);
|
||||
|
||||
if (!GC_all_interior_pointers) {
|
||||
if (get_pht_entry_from_index(GC_old_normal_bl, index)
|
||||
|| get_pht_entry_from_index(GC_incomplete_normal_bl, index)) {
|
||||
return(h+1);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; ; ) {
|
||||
if (GC_old_stack_bl[divWORDSZ(index)] == 0
|
||||
&& GC_incomplete_stack_bl[divWORDSZ(index)] == 0) {
|
||||
/* An easy case */
|
||||
i += WORDSZ - modWORDSZ(index);
|
||||
} else {
|
||||
if (get_pht_entry_from_index(GC_old_stack_bl, index)
|
||||
|| get_pht_entry_from_index(GC_incomplete_stack_bl, index)) {
|
||||
return(h+i+1);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (i >= nblocks) break;
|
||||
index = PHT_HASH((word)(h+i));
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
/* Return the number of blacklisted blocks in a given range. */
|
||||
/* Used only for statistical purposes. */
|
||||
/* Looks only at the GC_incomplete_stack_bl. */
|
||||
word GC_number_stack_black_listed(struct hblk *start, struct hblk *endp1)
|
||||
{
|
||||
register struct hblk * h;
|
||||
word result = 0;
|
||||
|
||||
for (h = start; h < endp1; h++) {
|
||||
word index = PHT_HASH((word)h);
|
||||
|
||||
if (get_pht_entry_from_index(GC_old_stack_bl, index)) result++;
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
/* Return the total number of (stack) black-listed bytes. */
|
||||
static word total_stack_black_listed(void)
|
||||
{
|
||||
register unsigned i;
|
||||
word total = 0;
|
||||
|
||||
for (i = 0; i < GC_n_heap_sects; i++) {
|
||||
struct hblk * start = (struct hblk *) GC_heap_sects[i].hs_start;
|
||||
size_t len = (word) GC_heap_sects[i].hs_bytes;
|
||||
struct hblk * endp1 = start + len/HBLKSIZE;
|
||||
|
||||
total += GC_number_stack_black_listed(start, endp1);
|
||||
}
|
||||
return(total * HBLKSIZE);
|
||||
}
|
||||
|
||||
4
src/engine/boehm_gc/callprocs
Executable file
4
src/engine/boehm_gc/callprocs
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
GC_DEBUG=1
|
||||
export GC_DEBUG
|
||||
$* 2>&1 | awk '{print "0x3e=c\""$0"\""};/^\t##PC##=/ {if ($2 != 0) {print $2"?i"}}' | adb $1 | sed "s/^ >/>/"
|
||||
196
src/engine/boehm_gc/checksums.c
Normal file
196
src/engine/boehm_gc/checksums.c
Normal file
@@ -0,0 +1,196 @@
|
||||
/*
|
||||
* Copyright (c) 1992-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
/* Boehm, March 29, 1995 12:51 pm PST */
|
||||
# ifdef CHECKSUMS
|
||||
|
||||
# include "private/gc_priv.h"
|
||||
|
||||
/* This is debugging code intended to verify the results of dirty bit */
|
||||
/* computations. Works only in a single threaded environment. */
|
||||
/* We assume that stubborn objects are changed only when they are */
|
||||
/* enabled for writing. (Certain kinds of writing are actually */
|
||||
/* safe under other conditions.) */
|
||||
# define NSUMS 10000
|
||||
|
||||
# define OFFSET 0x10000
|
||||
|
||||
typedef struct {
|
||||
GC_bool new_valid;
|
||||
word old_sum;
|
||||
word new_sum;
|
||||
struct hblk * block; /* Block to which this refers + OFFSET */
|
||||
/* to hide it from collector. */
|
||||
} page_entry;
|
||||
|
||||
page_entry GC_sums [NSUMS];
|
||||
|
||||
word GC_checksum(h)
|
||||
struct hblk *h;
|
||||
{
|
||||
register word *p = (word *)h;
|
||||
register word *lim = (word *)(h+1);
|
||||
register word result = 0;
|
||||
|
||||
while (p < lim) {
|
||||
result += *p++;
|
||||
}
|
||||
return(result | 0x80000000 /* doesn't look like pointer */);
|
||||
}
|
||||
|
||||
# ifdef STUBBORN_ALLOC
|
||||
/* Check whether a stubborn object from the given block appears on */
|
||||
/* the appropriate free list. */
|
||||
GC_bool GC_on_free_list(struct hblk *h)
|
||||
struct hblk *h;
|
||||
{
|
||||
hdr * hhdr = HDR(h);
|
||||
int sz = BYTES_TO_WORDS(hhdr -> hb_sz);
|
||||
ptr_t p;
|
||||
|
||||
if (sz > MAXOBJWORDS) return(FALSE);
|
||||
for (p = GC_sobjfreelist[sz]; p != 0; p = obj_link(p)) {
|
||||
if (HBLKPTR(p) == h) return(TRUE);
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
# endif
|
||||
|
||||
int GC_n_dirty_errors;
|
||||
int GC_n_changed_errors;
|
||||
int GC_n_clean;
|
||||
int GC_n_dirty;
|
||||
|
||||
void GC_update_check_page(struct hblk *h, int index)
|
||||
{
|
||||
page_entry *pe = GC_sums + index;
|
||||
register hdr * hhdr = HDR(h);
|
||||
struct hblk *b;
|
||||
|
||||
if (pe -> block != 0 && pe -> block != h + OFFSET) ABORT("goofed");
|
||||
pe -> old_sum = pe -> new_sum;
|
||||
pe -> new_sum = GC_checksum(h);
|
||||
# if !defined(MSWIN32) && !defined(MSWINCE)
|
||||
if (pe -> new_sum != 0x80000000 && !GC_page_was_ever_dirty(h)) {
|
||||
GC_printf("GC_page_was_ever_dirty(%p) is wrong\n", h);
|
||||
}
|
||||
# endif
|
||||
if (GC_page_was_dirty(h)) {
|
||||
GC_n_dirty++;
|
||||
} else {
|
||||
GC_n_clean++;
|
||||
}
|
||||
b = h;
|
||||
while (IS_FORWARDING_ADDR_OR_NIL(hhdr) && hhdr != 0) {
|
||||
b -= (word)hhdr;
|
||||
hhdr = HDR(b);
|
||||
}
|
||||
if (pe -> new_valid
|
||||
&& hhdr != 0 && hhdr -> hb_descr != 0 /* may contain pointers */
|
||||
&& pe -> old_sum != pe -> new_sum) {
|
||||
if (!GC_page_was_dirty(h) || !GC_page_was_ever_dirty(h)) {
|
||||
/* Set breakpoint here */GC_n_dirty_errors++;
|
||||
}
|
||||
# ifdef STUBBORN_ALLOC
|
||||
if (!HBLK_IS_FREE(hhdr)
|
||||
&& hhdr -> hb_obj_kind == STUBBORN
|
||||
&& !GC_page_was_changed(h)
|
||||
&& !GC_on_free_list(h)) {
|
||||
/* if GC_on_free_list(h) then reclaim may have touched it */
|
||||
/* without any allocations taking place. */
|
||||
/* Set breakpoint here */GC_n_changed_errors++;
|
||||
}
|
||||
# endif
|
||||
}
|
||||
pe -> new_valid = TRUE;
|
||||
pe -> block = h + OFFSET;
|
||||
}
|
||||
|
||||
unsigned long GC_bytes_in_used_blocks;
|
||||
|
||||
void GC_add_block(h, dummy)
|
||||
struct hblk *h;
|
||||
word dummy;
|
||||
{
|
||||
hdr * hhdr = HDR(h);
|
||||
bytes = hhdr -> hb_sz;
|
||||
|
||||
bytes += HBLKSIZE-1;
|
||||
bytes &= ~(HBLKSIZE-1);
|
||||
GC_bytes_in_used_blocks += bytes;
|
||||
}
|
||||
|
||||
void GC_check_blocks()
|
||||
{
|
||||
unsigned long bytes_in_free_blocks = GC_large_free_bytes;
|
||||
|
||||
GC_bytes_in_used_blocks = 0;
|
||||
GC_apply_to_all_blocks(GC_add_block, (word)0);
|
||||
GC_printf("GC_bytes_in_used_blocks = %lu, bytes_in_free_blocks = %lu ",
|
||||
GC_bytes_in_used_blocks, bytes_in_free_blocks);
|
||||
GC_printf("GC_heapsize = %lu\n", (unsigned long)GC_heapsize);
|
||||
if (GC_bytes_in_used_blocks + bytes_in_free_blocks != GC_heapsize) {
|
||||
GC_printf("LOST SOME BLOCKS!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Should be called immediately after GC_read_dirty and GC_read_changed. */
|
||||
void GC_check_dirty()
|
||||
{
|
||||
register int index;
|
||||
register unsigned i;
|
||||
register struct hblk *h;
|
||||
register ptr_t start;
|
||||
|
||||
GC_check_blocks();
|
||||
|
||||
GC_n_dirty_errors = 0;
|
||||
GC_n_changed_errors = 0;
|
||||
GC_n_clean = 0;
|
||||
GC_n_dirty = 0;
|
||||
|
||||
index = 0;
|
||||
for (i = 0; i < GC_n_heap_sects; i++) {
|
||||
start = GC_heap_sects[i].hs_start;
|
||||
for (h = (struct hblk *)start;
|
||||
h < (struct hblk *)(start + GC_heap_sects[i].hs_bytes);
|
||||
h++) {
|
||||
GC_update_check_page(h, index);
|
||||
index++;
|
||||
if (index >= NSUMS) goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
GC_printf("Checked %lu clean and %lu dirty pages\n",
|
||||
(unsigned long) GC_n_clean, (unsigned long) GC_n_dirty);
|
||||
if (GC_n_dirty_errors > 0) {
|
||||
GC_printf("Found %lu dirty bit errors\n",
|
||||
(unsigned long)GC_n_dirty_errors);
|
||||
}
|
||||
if (GC_n_changed_errors > 0) {
|
||||
GC_printf("Found %lu changed bit errors\n",
|
||||
(unsigned long)GC_n_changed_errors);
|
||||
GC_printf("These may be benign (provoked by nonpointer changes)\n");
|
||||
# ifdef THREADS
|
||||
GC_printf(
|
||||
"Also expect 1 per thread currently allocating a stubborn obj.\n");
|
||||
# endif
|
||||
}
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
extern int GC_quiet;
|
||||
/* ANSI C doesn't allow translation units to be empty. */
|
||||
/* So we guarantee this one is nonempty. */
|
||||
|
||||
# endif /* CHECKSUMS */
|
||||
142
src/engine/boehm_gc/compile
Executable file
142
src/engine/boehm_gc/compile
Executable file
@@ -0,0 +1,142 @@
|
||||
#! /bin/sh
|
||||
# Wrapper for compilers which do not understand `-c -o'.
|
||||
|
||||
scriptversion=2004-10-12.08
|
||||
|
||||
# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
|
||||
# Written by Tom Tromey <tromey@cygnus.com>.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# This file is maintained in Automake, please report
|
||||
# bugs to <bug-automake@gnu.org> or send patches to
|
||||
# <automake-patches@gnu.org>.
|
||||
|
||||
case $1 in
|
||||
'')
|
||||
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
|
||||
exit 1;
|
||||
;;
|
||||
-h | --h*)
|
||||
cat <<\EOF
|
||||
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
||||
|
||||
Wrapper for compilers which do not understand `-c -o'.
|
||||
Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
|
||||
arguments, and rename the output as expected.
|
||||
|
||||
If you are trying to build a whole package this is not the
|
||||
right script to run: please start by reading the file `INSTALL'.
|
||||
|
||||
Report bugs to <bug-automake@gnu.org>.
|
||||
EOF
|
||||
exit 0
|
||||
;;
|
||||
-v | --v*)
|
||||
echo "compile $scriptversion"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
ofile=
|
||||
cfile=
|
||||
eat=
|
||||
|
||||
for arg
|
||||
do
|
||||
if test -n "$eat"; then
|
||||
eat=
|
||||
else
|
||||
case $1 in
|
||||
-o)
|
||||
# configure might choose to run compile as `compile cc -o foo foo.c'.
|
||||
# So we strip `-o arg' only if arg is an object.
|
||||
eat=1
|
||||
case $2 in
|
||||
*.o | *.obj)
|
||||
ofile=$2
|
||||
;;
|
||||
*)
|
||||
set x "$@" -o "$2"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
*.c)
|
||||
cfile=$1
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set x "$@" "$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
shift
|
||||
done
|
||||
|
||||
if test -z "$ofile" || test -z "$cfile"; then
|
||||
# If no `-o' option was seen then we might have been invoked from a
|
||||
# pattern rule where we don't need one. That is ok -- this is a
|
||||
# normal compilation that the losing compiler can handle. If no
|
||||
# `.c' file was seen then we are probably linking. That is also
|
||||
# ok.
|
||||
exec "$@"
|
||||
fi
|
||||
|
||||
# Name of file we expect compiler to create.
|
||||
cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
|
||||
|
||||
# Create the lock directory.
|
||||
# Note: use `[/.-]' here to ensure that we don't use the same name
|
||||
# that we are using for the .o file. Also, base the name on the expected
|
||||
# object file name, since that is what matters with a parallel build.
|
||||
lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
|
||||
while true; do
|
||||
if mkdir "$lockdir" >/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
# FIXME: race condition here if user kills between mkdir and trap.
|
||||
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
||||
|
||||
# Run the compile.
|
||||
"$@"
|
||||
ret=$?
|
||||
|
||||
if test -f "$cofile"; then
|
||||
mv "$cofile" "$ofile"
|
||||
elif test -f "${cofile}bj"; then
|
||||
mv "${cofile}bj" "$ofile"
|
||||
fi
|
||||
|
||||
rmdir "$lockdir"
|
||||
exit $ret
|
||||
|
||||
# Local Variables:
|
||||
# mode: shell-script
|
||||
# sh-indentation: 2
|
||||
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
||||
# time-stamp-start: "scriptversion="
|
||||
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
||||
# time-stamp-end: "$"
|
||||
# End:
|
||||
1500
src/engine/boehm_gc/config.guess
vendored
Executable file
1500
src/engine/boehm_gc/config.guess
vendored
Executable file
File diff suppressed because it is too large
Load Diff
1608
src/engine/boehm_gc/config.sub
vendored
Executable file
1608
src/engine/boehm_gc/config.sub
vendored
Executable file
File diff suppressed because it is too large
Load Diff
23503
src/engine/boehm_gc/configure
vendored
Executable file
23503
src/engine/boehm_gc/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
658
src/engine/boehm_gc/configure.ac
Normal file
658
src/engine/boehm_gc/configure.ac
Normal file
@@ -0,0 +1,658 @@
|
||||
# Copyright (c) 1999-2001 by Red Hat, Inc. All rights reserved.
|
||||
#
|
||||
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
#
|
||||
# Permission is hereby granted to use or copy this program
|
||||
# for any purpose, provided the above notices are retained on all copies.
|
||||
# Permission to modify the code and to distribute modified code is granted,
|
||||
# provided the above notices are retained, and a notice that the code was
|
||||
# modified is included with the above copyright notice.
|
||||
#
|
||||
# Original author: Tom Tromey
|
||||
# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
|
||||
|
||||
dnl Process this file with autoconf to produce configure.
|
||||
|
||||
# Initialization
|
||||
# ==============
|
||||
|
||||
AC_INIT(gc,7.0,Hans.Boehm@hp.com)
|
||||
## version must conform to [0-9]+[.][0-9]+(alpha[0-9]+)?
|
||||
AC_CONFIG_SRCDIR(gcj_mlc.c)
|
||||
AC_CANONICAL_TARGET
|
||||
AC_PREREQ(2.53)
|
||||
AC_REVISION($Revision: 1.25 $)
|
||||
GC_SET_VERSION
|
||||
AM_INIT_AUTOMAKE([foreign dist-bzip2 subdir-objects nostdinc])
|
||||
AM_MAINTAINER_MODE
|
||||
|
||||
AC_SUBST(PACKAGE)
|
||||
AC_SUBST(GC_VERSION)
|
||||
|
||||
AM_PROG_CC_C_O
|
||||
AC_PROG_CXX
|
||||
|
||||
AM_PROG_AS
|
||||
## FIXME: really needed? (AC_LIBTOOL already provides this)
|
||||
AC_CHECK_TOOL(AR, ar)
|
||||
AC_CHECK_TOOL(RANLIB, ranlib, :) # :)
|
||||
|
||||
AC_PROG_INSTALL
|
||||
|
||||
. ${srcdir}/configure.host
|
||||
|
||||
GC_CFLAGS=${gc_cflags}
|
||||
AC_SUBST(GC_CFLAGS)
|
||||
|
||||
AC_ARG_ENABLE(threads,
|
||||
[AC_HELP_STRING([--enable-threads=TYPE], [choose threading package])],
|
||||
THREADS=$enableval,
|
||||
[ AC_MSG_CHECKING([for thread model used by GCC])
|
||||
THREADS=`$CC -v 2>&1 | sed -n 's/^Thread model: //p'`
|
||||
if test -z "$THREADS"; then
|
||||
THREADS=no
|
||||
fi
|
||||
AC_MSG_RESULT([$THREADS]) ])
|
||||
|
||||
AC_ARG_ENABLE(parallel-mark,
|
||||
[AC_HELP_STRING([--enable-parallel-mark],
|
||||
[parallelize marking and free list construction])],
|
||||
[case "$THREADS" in
|
||||
no | none | single)
|
||||
AC_MSG_ERROR([Parallel mark requires --enable-threads=x spec])
|
||||
;;
|
||||
esac ]
|
||||
)
|
||||
|
||||
AC_ARG_ENABLE(cplusplus,
|
||||
[AC_HELP_STRING([--enable-cplusplus], [install C++ support])])
|
||||
|
||||
INCLUDES=-I${srcdir}/include
|
||||
THREADDLLIBS=
|
||||
need_atomic_ops_asm=false
|
||||
## Libraries needed to support dynamic loading and/or threads.
|
||||
case "$THREADS" in
|
||||
no | none | single)
|
||||
THREADS=none
|
||||
;;
|
||||
posix | pthreads)
|
||||
THREADS=posix
|
||||
THREADDLLIBS=-lpthread
|
||||
case "$host" in
|
||||
x86-*-linux* | ia64-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* | alpha-*-linux*)
|
||||
AC_DEFINE(GC_LINUX_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
if test "${enable_parallel_mark}" = yes; then
|
||||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explict GC_INIT() calls may be required.");
|
||||
;;
|
||||
*-*-linux*)
|
||||
AC_DEFINE(GC_LINUX_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
;;
|
||||
*-*-aix*)
|
||||
AC_DEFINE(GC_AIX_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
;;
|
||||
*-*-hpux11*)
|
||||
AC_MSG_WARN("Only HP/UX 11 POSIX threads are supported.")
|
||||
AC_DEFINE(GC_HPUX_THREADS)
|
||||
AC_DEFINE(_POSIX_C_SOURCE,199506L)
|
||||
if test "${enable_parallel_mark}" = yes; then
|
||||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explict GC_INIT() calls may be required.");
|
||||
THREADDLLIBS="-lpthread -lrt"
|
||||
# HPUX needs REENTRANT for the _r calls.
|
||||
AC_DEFINE(_REENTRANT, 1, [Required define if using POSIX threads])
|
||||
;;
|
||||
*-*-hpux10*)
|
||||
AC_MSG_WARN("Only HP-UX 11 POSIX threads are supported.")
|
||||
;;
|
||||
*-*-freebsd*)
|
||||
AC_MSG_WARN("FreeBSD does not yet fully support threads with Boehm GC.")
|
||||
AC_DEFINE(GC_FREEBSD_THREADS)
|
||||
INCLUDES="$INCLUDES -pthread"
|
||||
;;
|
||||
*-*-kfreebsd*-gnu)
|
||||
AC_DEFINE(GC_FREEBSD_THREADS)
|
||||
INCLUDES="$INCLUDES -pthread"
|
||||
THREADDLLIBS=-pthread
|
||||
AC_DEFINE(_REENTRANT)
|
||||
if test "${enable_parallel_mark}" = yes; then
|
||||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_DEFINE(USE_COMPILER_TLS)
|
||||
;;
|
||||
*-*-gnu*)
|
||||
AC_DEFINE(GC_GNU_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
;;
|
||||
*-*-netbsd*)
|
||||
AC_MSG_WARN("Only on NetBSD 2.0 or later.")
|
||||
AC_DEFINE(GC_NETBSD_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
AC_DEFINE(_PTHREADS)
|
||||
THREADDLLIBS="-lpthread -lrt"
|
||||
;;
|
||||
*-*-solaris*)
|
||||
AC_DEFINE(GC_SOLARIS_THREADS)
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
THREADDLLIBS="-lpthread -lrt"
|
||||
if test "$GCC" != yes; then
|
||||
CFLAGS="$CFLAGS -O"
|
||||
need_atomic_ops_asm=true
|
||||
fi
|
||||
;;
|
||||
*-*-irix*)
|
||||
AC_DEFINE(GC_IRIX_THREADS)
|
||||
;;
|
||||
*-*-cygwin*)
|
||||
AC_DEFINE(GC_WIN32_THREADS)
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
win32_threads=true
|
||||
;;
|
||||
*-*-darwin*)
|
||||
AC_DEFINE(GC_DARWIN_THREADS)
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explict GC_INIT() calls may be required.");
|
||||
if test "${enable_parallel_mark}" = yes; then
|
||||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
darwin_threads=true
|
||||
;;
|
||||
*-*-osf*)
|
||||
AC_DEFINE(GC_OSF1_THREADS)
|
||||
if test "${enable_parallel_mark}" = yes; then
|
||||
AC_DEFINE(PARALLEL_MARK)
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explict GC_INIT() calls may be required.");
|
||||
# May want to enable it in other cases, too.
|
||||
# Measurements havent yet been done.
|
||||
fi
|
||||
INCLUDES="$INCLUDES -pthread"
|
||||
THREADDLLIBS="-lpthread -lrt"
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR("Pthreads not supported by the GC on this platform.")
|
||||
;;
|
||||
esac
|
||||
;;
|
||||
win32)
|
||||
AC_DEFINE(GC_WIN32_THREADS)
|
||||
dnl Wine getenv may not return NULL for missing entry
|
||||
AC_DEFINE(NO_GETENV)
|
||||
;;
|
||||
dgux386)
|
||||
THREADS=dgux386
|
||||
AC_MSG_RESULT($THREADDLLIBS)
|
||||
# Use pthread GCC switch
|
||||
THREADDLLIBS=-pthread
|
||||
if test "${enable_parallel_mark}" = yes; then
|
||||
AC_DEFINE(PARALLEL_MARK)
|
||||
fi
|
||||
AC_DEFINE(THREAD_LOCAL_ALLOC)
|
||||
AC_MSG_WARN("Explict GC_INIT() calls may be required.");
|
||||
AC_DEFINE(GC_DGUX386_THREADS)
|
||||
AC_DEFINE(DGUX_THREADS)
|
||||
# Enable _POSIX4A_DRAFT10_SOURCE with flag -pthread
|
||||
INCLUDES="-pthread $INCLUDES"
|
||||
;;
|
||||
aix)
|
||||
THREADS=posix
|
||||
THREADDLLIBS=-lpthread
|
||||
AC_DEFINE(GC_AIX_THREADS)
|
||||
AC_DEFINE(_REENTRANT)
|
||||
;;
|
||||
decosf1 | irix | mach | os2 | solaris | dce | vxworks)
|
||||
AC_MSG_ERROR(thread package $THREADS not yet supported)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_ERROR($THREADS is an unknown thread package)
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(THREADDLLIBS)
|
||||
AM_CONDITIONAL(THREADS, test x$THREADS != xnone)
|
||||
AM_CONDITIONAL(PTHREADS, test x$THREADS = xposix)
|
||||
AM_CONDITIONAL(DARWIN_THREADS, test x$darwin_threads = xtrue)
|
||||
AM_CONDITIONAL(WIN32_THREADS, test x$win32_threads = xtrue)
|
||||
|
||||
case "$host" in
|
||||
powerpc-*-darwin*)
|
||||
powerpc_darwin=true
|
||||
;;
|
||||
esac
|
||||
|
||||
# Darwin needs a few extra special tests to deal with variation in the
|
||||
# system headers.
|
||||
case "$host" in
|
||||
powerpc*-*-darwin*)
|
||||
AC_CHECK_MEMBER(ppc_thread_state_t.r0,
|
||||
AC_DEFINE(HAS_PPC_THREAD_STATE_R0,1,
|
||||
[ppc_thread_state_t has field r0]),,
|
||||
[#include <mach/thread_status.h>])
|
||||
AC_CHECK_MEMBER(ppc_thread_state_t.__r0,
|
||||
AC_DEFINE(HAS_PPC_THREAD_STATE___R0,1,dnl
|
||||
[ppc_thread_state_t has field __r0]),,
|
||||
[#include <mach/thread_status.h>])
|
||||
AC_CHECK_MEMBER(ppc_thread_state64_t.r0,
|
||||
AC_DEFINE(HAS_PPC_THREAD_STATE64_R0,1,dnl
|
||||
[ppc_thread_state64_t has field r0]),,
|
||||
[#include <mach/thread_status.h>])
|
||||
AC_CHECK_MEMBER(ppc_thread_state64_t.__r0,
|
||||
AC_DEFINE(HAS_PPC_THREAD_STATE64___R0,1,dnl
|
||||
[ppc_thread_state64_t has field __r0]),,
|
||||
[#include <mach/thread_status.h>])
|
||||
;;
|
||||
i?86*-*-darwin*)
|
||||
AC_CHECK_MEMBER(x86_thread_state32_t.eax,
|
||||
AC_DEFINE(HAS_X86_THREAD_STATE32_EAX,1,dnl
|
||||
[x86_thread_state32_t has field eax]),,
|
||||
[#include <sys/cdefs.h>
|
||||
#include <mach/thread_status.h>])
|
||||
AC_CHECK_MEMBER(x86_thread_state32_t.__eax,
|
||||
AC_DEFINE(HAS_X86_THREAD_STATE32___EAX,1,dnl
|
||||
[x86_thread_state32_t has field __eax]),,
|
||||
[#include <sys/cdefs.h>
|
||||
#include <mach/thread_status.h>])
|
||||
;;
|
||||
x86_64-*-darwin*)
|
||||
AC_CHECK_MEMBER(x86_thread_state64_t.rax,
|
||||
AC_DEFINE(HAS_X86_THREAD_STATE64_RAX,1,dnl
|
||||
[x86_thread_state64_t has field rax]),,
|
||||
[#include <sys/cdefs.h>
|
||||
#include <mach/thread_status.h>])
|
||||
AC_CHECK_MEMBER(x86_thread_state64_t.__rax,
|
||||
AC_DEFINE(HAS_X86_THREAD_STATE64___RAX,1,dnl
|
||||
[x86_thread_state64_t has field __rax]),,
|
||||
[#include <sys/cdefs.h>
|
||||
#include <mach/thread_status.h>])
|
||||
;;
|
||||
*) ;;
|
||||
esac
|
||||
|
||||
AC_MSG_CHECKING(for xlc)
|
||||
AC_TRY_COMPILE([],[
|
||||
#ifndef __xlC__
|
||||
# error
|
||||
#endif
|
||||
], [compiler_xlc=yes], [compiler_xlc=no])
|
||||
AC_MSG_RESULT($compiler_xlc)
|
||||
AM_CONDITIONAL(COMPILER_XLC,test $compiler_xlc = yes)
|
||||
if test $compiler_xlc = yes -a "$powerpc_darwin" = true; then
|
||||
# the darwin stack-frame-walking code is completely broken on xlc
|
||||
AC_DEFINE(DARWIN_DONT_PARSE_STACK)
|
||||
fi
|
||||
|
||||
# We never want libdl on darwin. It is a fake libdl that just ends up making
|
||||
# dyld calls anyway
|
||||
case "$host" in
|
||||
*-*-darwin*) ;;
|
||||
*)
|
||||
AC_CHECK_LIB(dl, dlopen, THREADDLLIBS="$THREADDLLIBS -ldl")
|
||||
;;
|
||||
esac
|
||||
|
||||
# extra LD Flags which are required for targets
|
||||
case "${host}" in
|
||||
*-*-darwin*)
|
||||
extra_ldflags_libgc=-Wl,-single_module
|
||||
;;
|
||||
esac
|
||||
AC_SUBST(extra_ldflags_libgc)
|
||||
|
||||
AC_SUBST(EXTRA_TEST_LIBS)
|
||||
|
||||
target_all=libgc.la
|
||||
AC_SUBST(target_all)
|
||||
|
||||
dnl If the target is an eCos system, use the appropriate eCos
|
||||
dnl I/O routines.
|
||||
dnl FIXME: this should not be a local option but a global target
|
||||
dnl system; at present there is no eCos target.
|
||||
TARGET_ECOS="no"
|
||||
AC_ARG_WITH(ecos,
|
||||
[ --with-ecos enable runtime eCos target support],
|
||||
TARGET_ECOS="$with_ecos"
|
||||
)
|
||||
|
||||
addobjs=
|
||||
addlibs=
|
||||
CXXINCLUDES=
|
||||
case "$TARGET_ECOS" in
|
||||
no)
|
||||
;;
|
||||
*)
|
||||
AC_DEFINE(ECOS)
|
||||
CXXINCLUDES="-I${TARGET_ECOS}/include"
|
||||
addobjs="$addobjs ecos.lo"
|
||||
;;
|
||||
esac
|
||||
|
||||
AM_CONDITIONAL(CPLUSPLUS, test "${enable_cplusplus}" = yes)
|
||||
|
||||
AC_SUBST(CXX)
|
||||
|
||||
AC_SUBST(INCLUDES)
|
||||
AC_SUBST(CXXINCLUDES)
|
||||
|
||||
# Configuration of shared libraries
|
||||
#
|
||||
AC_MSG_CHECKING(whether to build shared libraries)
|
||||
AC_ENABLE_SHARED
|
||||
|
||||
case "$host" in
|
||||
alpha-*-openbsd*)
|
||||
enable_shared=no
|
||||
AC_MSG_RESULT(no)
|
||||
;;
|
||||
*)
|
||||
AC_MSG_RESULT(yes)
|
||||
;;
|
||||
esac
|
||||
|
||||
# Configuration of machine-dependent code
|
||||
#
|
||||
AC_MSG_CHECKING(which machine-dependent code should be used)
|
||||
machdep=
|
||||
case "$host" in
|
||||
alpha-*-openbsd*)
|
||||
machdep="mach_dep.lo"
|
||||
if test x"${ac_cv_lib_dl_dlopen}" != xyes ; then
|
||||
AC_MSG_WARN(OpenBSD/Alpha without dlopen(). Shared library support is disabled)
|
||||
fi
|
||||
;;
|
||||
alpha*-*-linux*)
|
||||
machdep="mach_dep.lo"
|
||||
;;
|
||||
i?86-*-solaris2.[[89]] | i?86-*-solaris2.1?)
|
||||
AC_DEFINE(SOLARIS25_PROC_VDB_BUG_FIXED)
|
||||
;;
|
||||
mipstx39-*-elf*)
|
||||
machdep="mach_dep.lo"
|
||||
AC_DEFINE(STACKBASE, __stackbase)
|
||||
AC_DEFINE(DATASTART_IS_ETEXT)
|
||||
;;
|
||||
mips-dec-ultrix*)
|
||||
machdep="mach-dep.lo"
|
||||
;;
|
||||
mips-nec-sysv*|mips-unknown-sysv*)
|
||||
;;
|
||||
mips*-*-linux*)
|
||||
;;
|
||||
mips-*-*)
|
||||
machdep="mach_dep.lo"
|
||||
dnl AC_DEFINE(NO_EXECUTE_PERMISSION)
|
||||
dnl This is now redundant, but it is also important for incremental GC
|
||||
dnl performance under Irix.
|
||||
;;
|
||||
sparc-*-netbsd*)
|
||||
machdep="mach_dep.lo sparc_netbsd_mach_dep.lo"
|
||||
;;
|
||||
sparc-sun-solaris2.3)
|
||||
machdep="mach_dep.lo sparc_mach_dep.lo"
|
||||
AC_DEFINE(SUNOS53_SHARED_LIB)
|
||||
;;
|
||||
sparc*-sun-solaris2.*)
|
||||
machdep="mach_dep.lo sparc_mach_dep.lo"
|
||||
;;
|
||||
ia64-*-*)
|
||||
machdep="mach_dep.lo ia64_save_regs_in_stack.lo"
|
||||
;;
|
||||
esac
|
||||
if test x"$machdep" = x; then
|
||||
AC_MSG_RESULT($machdep)
|
||||
machdep="mach_dep.lo"
|
||||
fi
|
||||
addobjs="$addobjs $machdep"
|
||||
AC_SUBST(addobjs)
|
||||
AC_SUBST(addlibs)
|
||||
|
||||
AC_PROG_LIBTOOL
|
||||
|
||||
#
|
||||
# Check for AViiON Machines running DGUX
|
||||
#
|
||||
ac_is_dgux=no
|
||||
AC_CHECK_HEADER(sys/dg_sys_info.h,
|
||||
[ac_is_dgux=yes;])
|
||||
|
||||
## :GOTCHA: we do not check anything but sys/dg_sys_info.h
|
||||
if test $ac_is_dgux = yes; then
|
||||
if test "$enable_full_debug" = "yes"; then
|
||||
CFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
|
||||
CXXFLAGS="-g -mstandard -DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
|
||||
else
|
||||
CFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
|
||||
CXXFLAGS="-DDGUX -D_DGUX_SOURCE -Di386 -mno-legend -O2"
|
||||
fi
|
||||
AC_SUBST(CFLAGS)
|
||||
AC_SUBST(CXXFLAGS)
|
||||
fi
|
||||
|
||||
dnl We use these options to decide which functions to include.
|
||||
AC_ARG_WITH(target-subdir,
|
||||
[ --with-target-subdir=SUBDIR
|
||||
configuring with a cross compiler])
|
||||
AC_ARG_WITH(cross-host,
|
||||
[ --with-cross-host=HOST configuring with a cross compiler])
|
||||
|
||||
# automake wants to see AC_EXEEXT. But we don't need it. And having
|
||||
# it is actually a problem, because the compiler we're passed can't
|
||||
# necessarily do a full link. So we fool automake here.
|
||||
if false; then
|
||||
# autoconf 2.50 runs AC_EXEEXT by default, and the macro expands
|
||||
# to nothing, so nothing would remain between `then' and `fi' if it
|
||||
# were not for the `:' below.
|
||||
:
|
||||
AC_EXEEXT
|
||||
fi
|
||||
|
||||
dnl As of 4.13a2, the collector will not properly work on Solaris when
|
||||
dnl built with gcc and -O. So we remove -O in the appropriate case.
|
||||
dnl Not needed anymore on Solaris.
|
||||
AC_MSG_CHECKING(whether Solaris gcc optimization fix is necessary)
|
||||
case "$host" in
|
||||
*aix*)
|
||||
if test "$GCC" = yes; then
|
||||
AC_MSG_RESULT(yes)
|
||||
new_CFLAGS=
|
||||
for i in $CFLAGS; do
|
||||
case "$i" in
|
||||
-O*)
|
||||
;;
|
||||
*)
|
||||
new_CFLAGS="$new_CFLAGS $i"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
CFLAGS="$new_CFLAGS"
|
||||
else
|
||||
AC_MSG_RESULT(no)
|
||||
fi
|
||||
;;
|
||||
*) AC_MSG_RESULT(no) ;;
|
||||
esac
|
||||
|
||||
dnl Include defines that have become de facto standard.
|
||||
dnl ALL_INTERIOR_POINTERS can be overridden in startup code.
|
||||
AC_DEFINE(NO_EXECUTE_PERMISSION)
|
||||
AC_DEFINE(ALL_INTERIOR_POINTERS)
|
||||
|
||||
|
||||
dnl Interface Selection
|
||||
dnl -------------------
|
||||
dnl
|
||||
dnl By default, make the library as general as possible.
|
||||
dnl enable_gcj_support=no
|
||||
AC_ARG_ENABLE(gcj-support,
|
||||
[AC_HELP_STRING([--disable-gcj-support],
|
||||
[Disable support for gcj.])])
|
||||
AM_CONDITIONAL(ENABLE_GCJ_SUPPORT,
|
||||
[test x"$enable_gcj_support" != xno])
|
||||
if test x"$enable_gcj_support" != xno; then
|
||||
AC_DEFINE(GC_GCJ_SUPPORT, 1, [Define to include support for gcj])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(java-finalization,
|
||||
[AC_HELP_STRING([--disable-java-finalization],
|
||||
[Disable support for java finalization.])])
|
||||
if test x"$enable_java_finalization" != xno; then
|
||||
AC_DEFINE(JAVA_FINALIZATION)
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(atomic-uncollectable,
|
||||
[AC_HELP_STRING([--disable-atomic-uncollectible],
|
||||
[Disable support for atomic uncollectible allocation.])])
|
||||
if test x"$enable_atomic_uncollectible" != x"no"; then
|
||||
AC_DEFINE(ATOMIC_UNCOLLECTABLE, 1,
|
||||
[Define to enable atomic uncollectible allocation.])
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(redirect-malloc,
|
||||
[AC_HELP_STRING([--enable-redirect-malloc],
|
||||
[Redirect malloc and friends to GC routines])])
|
||||
|
||||
if test "${enable_redirect_malloc}" = yes; then
|
||||
if test "${enable_full_debug}" = yes; then
|
||||
AC_DEFINE(REDIRECT_MALLOC, GC_debug_malloc_replacement)
|
||||
AC_DEFINE(REDIRECT_REALLOC, GC_debug_realloc_replacement)
|
||||
AC_DEFINE(REDIRECT_FREE, GC_debug_free)
|
||||
else
|
||||
AC_DEFINE(REDIRECT_MALLOC, GC_malloc)
|
||||
fi
|
||||
fi
|
||||
|
||||
AC_ARG_ENABLE(large-config,
|
||||
[AC_HELP_STRING([--enable-large-config],
|
||||
[Optimize for large (> 100 MB) heap or root set])])
|
||||
|
||||
if test "${enable_large_config}" = yes; then
|
||||
AC_DEFINE(LARGE_CONFIG, 1, [Define to optimize for large heaps or root sets])
|
||||
fi
|
||||
|
||||
dnl This is something of a hack. When cross-compiling we turn off
|
||||
dnl some functionality. We also enable the "small" configuration.
|
||||
dnl These is only correct when targetting an embedded system. FIXME.
|
||||
if test -n "${with_cross_host}"; then
|
||||
AC_DEFINE(NO_CLOCK)
|
||||
AC_DEFINE(SMALL_CONFIG)
|
||||
AC_DEFINE(NO_DEBUGGING)
|
||||
fi
|
||||
|
||||
|
||||
dnl Debugging
|
||||
dnl ---------
|
||||
|
||||
UNWINDLIBS=
|
||||
AC_ARG_ENABLE(gc-debug,
|
||||
[AC_HELP_STRING([--enable-gc-debug],
|
||||
[include full support for pointer backtracing etc.])],
|
||||
[ if test "$enable_gc_debug" = "yes"; then
|
||||
AC_MSG_WARN("Should define GC_DEBUG and use debug alloc. in clients.")
|
||||
AC_DEFINE(KEEP_BACK_PTRS)
|
||||
AC_DEFINE(DBG_HDRS_ALL)
|
||||
case $host in
|
||||
ia64-*-linux* )
|
||||
AC_DEFINE(MAKE_BACK_GRAPH)
|
||||
AC_DEFINE(SAVE_CALL_COUNT, 8)
|
||||
AC_CHECK_LIB(unwind, backtrace, [
|
||||
AC_DEFINE(GC_HAVE_BUILTIN_BACKTRACE)
|
||||
UNWINDLIBS=-lunwind
|
||||
AC_MSG_WARN("Client code may need to link against libunwind.")
|
||||
])
|
||||
;;
|
||||
x86-*-linux* | i586-*-linux* | i686-*-linux* | x86_64-*-linux* )
|
||||
AC_DEFINE(MAKE_BACK_GRAPH)
|
||||
AC_MSG_WARN("Client must not use -fomit-frame-pointer.")
|
||||
AC_DEFINE(SAVE_CALL_COUNT, 8)
|
||||
;;
|
||||
i[3456]86-*-dgux*)
|
||||
AC_DEFINE(MAKE_BACK_GRAPH)
|
||||
;;
|
||||
esac ]
|
||||
fi)
|
||||
|
||||
AC_SUBST(UNWINDLIBS)
|
||||
|
||||
AC_ARG_ENABLE(gc-assertions,
|
||||
[AC_HELP_STRING([--enable-gc-assertions],
|
||||
[collector-internal assertion checking])])
|
||||
if test "${enable_gc_assertions}" = yes; then
|
||||
AC_DEFINE(GC_ASSERTIONS)
|
||||
fi
|
||||
|
||||
AM_CONDITIONAL(USE_LIBDIR, test -z "$with_cross_host")
|
||||
|
||||
|
||||
dnl Atomic Ops
|
||||
dnl ----------
|
||||
|
||||
atomic_ops_libs=-latomic_ops
|
||||
AC_CHECK_HEADER(atomic_ops.h,
|
||||
[ AC_MSG_NOTICE([Using pre-installed libatomic_ops]) ],
|
||||
[ ao_dir=
|
||||
for candidate in ${srcdir}/libatomic_ops*; do
|
||||
case $candidate in
|
||||
*.tar.gz)
|
||||
;;
|
||||
*install)
|
||||
dnl generated by alternate Makefile.
|
||||
;;
|
||||
*)
|
||||
if test -e "$candidate"; then
|
||||
ao_dir="$candidate"
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
done
|
||||
if test -z "$ao_dir"; then
|
||||
AC_MSG_ERROR([Missig libatomic_ops.])
|
||||
fi
|
||||
ao_version="${ao_dir#*libatomic_ops-}"
|
||||
AC_MSG_NOTICE([Using internal version of libatomic_ops])
|
||||
|
||||
dnl Automake does not accept shell variables in AC_CONFIG_SUBDIRS
|
||||
test -e ${srcdir}/libatomic_ops \
|
||||
|| ln -s ${ao_dir} ${srcdir}/libatomic_ops
|
||||
AC_CONFIG_SUBDIRS(libatomic_ops)
|
||||
|
||||
dnl Also copy the source files to be linked in.
|
||||
test -e ${srcdir}/atomic_ops.c \
|
||||
|| ln -s ${srcdir}/libatomic_ops/src/atomic_ops.c \
|
||||
${srcdir}/atomic_ops.c
|
||||
|
||||
test -e ${srcdir}/atomic_ops_sysdeps.S \
|
||||
|| ln -s ${srcdir}/libatomic_ops/src/atomic_ops_sysdeps.S \
|
||||
${srcdir}/atomic_ops_sysdeps.S
|
||||
|
||||
dnl This gets the source include files, which is often close enough.
|
||||
dnl It also makes atomic_ops_sysdeps.S assemble.
|
||||
GC_CFLAGS="${GC_CFLAGS} -I \$(top_srcdir)/libatomic_ops/src"
|
||||
maybe_libatomic_ops="libatomic_ops"
|
||||
])
|
||||
|
||||
AM_CONDITIONAL(USE_INTERNAL_LIBATOMIC_OPS,
|
||||
test -n "$maybe_libatomic_ops" -a "$THREADS" != "none")
|
||||
AM_CONDITIONAL(NEED_ATOMIC_OPS_ASM, test -n "$maybe_libatomic_ops" -a x$need_atomic_ops_asm = xtrue)
|
||||
AC_SUBST(atomic_ops_libs)
|
||||
|
||||
dnl Produce the Files
|
||||
dnl -----------------
|
||||
|
||||
AC_CONFIG_FILES([Makefile bdw-gc.pc])
|
||||
|
||||
AC_CONFIG_COMMANDS([default],,
|
||||
[ srcdir=${srcdir}
|
||||
host=${host}
|
||||
CONFIG_SHELL=${CONFIG_SHELL-/bin/sh}
|
||||
CC="${CC}"
|
||||
DEFS="$DEFS" ])
|
||||
|
||||
AC_OUTPUT
|
||||
61
src/engine/boehm_gc/configure.host
Normal file
61
src/engine/boehm_gc/configure.host
Normal file
@@ -0,0 +1,61 @@
|
||||
# configure.host
|
||||
|
||||
# This shell script handles all host based configuration for the garbage
|
||||
# collector.
|
||||
# It sets various shell variables based on the the host and the
|
||||
# configuration options. You can modify this shell script without
|
||||
# needing to rerun autoconf.
|
||||
|
||||
# This shell script should be invoked as
|
||||
# . configure.host
|
||||
# If it encounters an error, it will exit with a message.
|
||||
|
||||
# It uses the following shell variables:
|
||||
# host The configuration host
|
||||
# host_cpu The configuration host CPU
|
||||
# target_optspace --enable-target-optspace ("yes", "no", "")
|
||||
# GCC should be "yes" if using gcc
|
||||
|
||||
# It sets the following shell variables:
|
||||
# gc_cflags Special CFLAGS to use when building
|
||||
|
||||
gc_cflags=""
|
||||
|
||||
# We should set -fexceptions if we are using gcc and might be used
|
||||
# inside something like gcj. This is the zeroth approximation:
|
||||
if test :"$GCC": = :yes: ; then
|
||||
gc_cflags="${gc_cflags} -fexceptions"
|
||||
else
|
||||
case "$host" in
|
||||
hppa*-*-hpux* )
|
||||
if test :$GCC: != :"yes": ; then
|
||||
gc_cflags="${gc_flags} +ESdbgasm"
|
||||
fi
|
||||
# :TODO: actaully we should check using Autoconf if
|
||||
# the compiler supports this option.
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case "${target_optspace}:${host}" in
|
||||
yes:*)
|
||||
gc_cflags="${gc_cflags} -Os"
|
||||
;;
|
||||
:m32r-* | :d10v-* | :d30v-*)
|
||||
gc_cflags="${gc_cflags} -Os"
|
||||
;;
|
||||
no:* | :*)
|
||||
# Nothing.
|
||||
;;
|
||||
esac
|
||||
|
||||
# Set any host dependent compiler flags.
|
||||
# THIS TABLE IS SORTED. KEEP IT THAT WAY.
|
||||
|
||||
case "${host}" in
|
||||
mips-tx39-*|mipstx39-unknown-*)
|
||||
gc_cflags="${gc_cflags} -G 0"
|
||||
;;
|
||||
*)
|
||||
;;
|
||||
esac
|
||||
4
src/engine/boehm_gc/configure_atomic_ops.sh
Executable file
4
src/engine/boehm_gc/configure_atomic_ops.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/bin/sh
|
||||
P=`pwd`/libatomic_ops-install
|
||||
cd libatomic_ops-*[0-9]
|
||||
./configure --prefix=$P
|
||||
17
src/engine/boehm_gc/cord/cord.am
Normal file
17
src/engine/boehm_gc/cord/cord.am
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
lib_LTLIBRARIES += libcord.la
|
||||
|
||||
libcord_la_LIBADD = $(top_builddir)/libgc.la
|
||||
libcord_la_LDFLAGS = -version-info 1:3:0 -no-undefined
|
||||
|
||||
libcord_la_SOURCES = \
|
||||
cord/cordbscs.c \
|
||||
cord/cordprnt.c \
|
||||
cord/cordtest.c \
|
||||
cord/cordxtra.c
|
||||
|
||||
|
||||
EXTRA_DIST += \
|
||||
cord/cordbscs.c cord/cordtest.c cord/de.c \
|
||||
cord/cordprnt.c cord/cordxtra.c cord/de_cmds.h \
|
||||
cord/de_win.h cord/de_win.c cord/de_win.RC cord/de_win.ICO
|
||||
919
src/engine/boehm_gc/cord/cordbscs.c
Normal file
919
src/engine/boehm_gc/cord/cordbscs.c
Normal file
@@ -0,0 +1,919 @@
|
||||
/*
|
||||
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*
|
||||
* Author: Hans-J. Boehm (boehm@parc.xerox.com)
|
||||
*/
|
||||
/* Boehm, October 3, 1994 5:19 pm PDT */
|
||||
# include "gc.h"
|
||||
# include "cord.h"
|
||||
# include <stdlib.h>
|
||||
# include <stdio.h>
|
||||
# include <string.h>
|
||||
|
||||
/* An implementation of the cord primitives. These are the only */
|
||||
/* Functions that understand the representation. We perform only */
|
||||
/* minimal checks on arguments to these functions. Out of bounds */
|
||||
/* arguments to the iteration functions may result in client functions */
|
||||
/* invoked on garbage data. In most cases, client functions should be */
|
||||
/* programmed defensively enough that this does not result in memory */
|
||||
/* smashes. */
|
||||
|
||||
typedef void (* oom_fn)(void);
|
||||
|
||||
oom_fn CORD_oom_fn = (oom_fn) 0;
|
||||
|
||||
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
|
||||
ABORT("Out of memory\n"); }
|
||||
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
|
||||
|
||||
typedef unsigned long word;
|
||||
|
||||
typedef union {
|
||||
struct Concatenation {
|
||||
char null;
|
||||
char header;
|
||||
char depth; /* concatenation nesting depth. */
|
||||
unsigned char left_len;
|
||||
/* Length of left child if it is sufficiently */
|
||||
/* short; 0 otherwise. */
|
||||
# define MAX_LEFT_LEN 255
|
||||
word len;
|
||||
CORD left; /* length(left) > 0 */
|
||||
CORD right; /* length(right) > 0 */
|
||||
} concatenation;
|
||||
struct Function {
|
||||
char null;
|
||||
char header;
|
||||
char depth; /* always 0 */
|
||||
char left_len; /* always 0 */
|
||||
word len;
|
||||
CORD_fn fn;
|
||||
void * client_data;
|
||||
} function;
|
||||
struct Generic {
|
||||
char null;
|
||||
char header;
|
||||
char depth;
|
||||
char left_len;
|
||||
word len;
|
||||
} generic;
|
||||
char string[1];
|
||||
} CordRep;
|
||||
|
||||
# define CONCAT_HDR 1
|
||||
|
||||
# define FN_HDR 4
|
||||
# define SUBSTR_HDR 6
|
||||
/* Substring nodes are a special case of function nodes. */
|
||||
/* The client_data field is known to point to a substr_args */
|
||||
/* structure, and the function is either CORD_apply_access_fn */
|
||||
/* or CORD_index_access_fn. */
|
||||
|
||||
/* The following may be applied only to function and concatenation nodes: */
|
||||
#define IS_CONCATENATION(s) (((CordRep *)s)->generic.header == CONCAT_HDR)
|
||||
|
||||
#define IS_FUNCTION(s) ((((CordRep *)s)->generic.header & FN_HDR) != 0)
|
||||
|
||||
#define IS_SUBSTR(s) (((CordRep *)s)->generic.header == SUBSTR_HDR)
|
||||
|
||||
#define LEN(s) (((CordRep *)s) -> generic.len)
|
||||
#define DEPTH(s) (((CordRep *)s) -> generic.depth)
|
||||
#define GEN_LEN(s) (CORD_IS_STRING(s) ? strlen(s) : LEN(s))
|
||||
|
||||
#define LEFT_LEN(c) ((c) -> left_len != 0? \
|
||||
(c) -> left_len \
|
||||
: (CORD_IS_STRING((c) -> left) ? \
|
||||
(c) -> len - GEN_LEN((c) -> right) \
|
||||
: LEN((c) -> left)))
|
||||
|
||||
#define SHORT_LIMIT (sizeof(CordRep) - 1)
|
||||
/* Cords shorter than this are C strings */
|
||||
|
||||
|
||||
/* Dump the internal representation of x to stdout, with initial */
|
||||
/* indentation level n. */
|
||||
void CORD_dump_inner(CORD x, unsigned n)
|
||||
{
|
||||
register size_t i;
|
||||
|
||||
for (i = 0; i < (size_t)n; i++) {
|
||||
fputs(" ", stdout);
|
||||
}
|
||||
if (x == 0) {
|
||||
fputs("NIL\n", stdout);
|
||||
} else if (CORD_IS_STRING(x)) {
|
||||
for (i = 0; i <= SHORT_LIMIT; i++) {
|
||||
if (x[i] == '\0') break;
|
||||
putchar(x[i]);
|
||||
}
|
||||
if (x[i] != '\0') fputs("...", stdout);
|
||||
putchar('\n');
|
||||
} else if (IS_CONCATENATION(x)) {
|
||||
register struct Concatenation * conc =
|
||||
&(((CordRep *)x) -> concatenation);
|
||||
printf("Concatenation: %p (len: %d, depth: %d)\n",
|
||||
x, (int)(conc -> len), (int)(conc -> depth));
|
||||
CORD_dump_inner(conc -> left, n+1);
|
||||
CORD_dump_inner(conc -> right, n+1);
|
||||
} else /* function */{
|
||||
register struct Function * func =
|
||||
&(((CordRep *)x) -> function);
|
||||
if (IS_SUBSTR(x)) printf("(Substring) ");
|
||||
printf("Function: %p (len: %d): ", x, (int)(func -> len));
|
||||
for (i = 0; i < 20 && i < func -> len; i++) {
|
||||
putchar((*(func -> fn))(i, func -> client_data));
|
||||
}
|
||||
if (i < func -> len) fputs("...", stdout);
|
||||
putchar('\n');
|
||||
}
|
||||
}
|
||||
|
||||
/* Dump the internal representation of x to stdout */
|
||||
void CORD_dump(CORD x)
|
||||
{
|
||||
CORD_dump_inner(x, 0);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
CORD CORD_cat_char_star(CORD x, const char * y, size_t leny)
|
||||
{
|
||||
register size_t result_len;
|
||||
register size_t lenx;
|
||||
register int depth;
|
||||
|
||||
if (x == CORD_EMPTY) return(y);
|
||||
if (leny == 0) return(x);
|
||||
if (CORD_IS_STRING(x)) {
|
||||
lenx = strlen(x);
|
||||
result_len = lenx + leny;
|
||||
if (result_len <= SHORT_LIMIT) {
|
||||
register char * result = GC_MALLOC_ATOMIC(result_len+1);
|
||||
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
memcpy(result, x, lenx);
|
||||
memcpy(result + lenx, y, leny);
|
||||
result[result_len] = '\0';
|
||||
return((CORD) result);
|
||||
} else {
|
||||
depth = 1;
|
||||
}
|
||||
} else {
|
||||
register CORD right;
|
||||
register CORD left;
|
||||
register char * new_right;
|
||||
register size_t right_len;
|
||||
|
||||
lenx = LEN(x);
|
||||
|
||||
if (leny <= SHORT_LIMIT/2
|
||||
&& IS_CONCATENATION(x)
|
||||
&& CORD_IS_STRING(right = ((CordRep *)x) -> concatenation.right)) {
|
||||
/* Merge y into right part of x. */
|
||||
if (!CORD_IS_STRING(left = ((CordRep *)x) -> concatenation.left)) {
|
||||
right_len = lenx - LEN(left);
|
||||
} else if (((CordRep *)x) -> concatenation.left_len != 0) {
|
||||
right_len = lenx - ((CordRep *)x) -> concatenation.left_len;
|
||||
} else {
|
||||
right_len = strlen(right);
|
||||
}
|
||||
result_len = right_len + leny; /* length of new_right */
|
||||
if (result_len <= SHORT_LIMIT) {
|
||||
new_right = GC_MALLOC_ATOMIC(result_len + 1);
|
||||
memcpy(new_right, right, right_len);
|
||||
memcpy(new_right + right_len, y, leny);
|
||||
new_right[result_len] = '\0';
|
||||
y = new_right;
|
||||
leny = result_len;
|
||||
x = left;
|
||||
lenx -= right_len;
|
||||
/* Now fall through to concatenate the two pieces: */
|
||||
}
|
||||
if (CORD_IS_STRING(x)) {
|
||||
depth = 1;
|
||||
} else {
|
||||
depth = DEPTH(x) + 1;
|
||||
}
|
||||
} else {
|
||||
depth = DEPTH(x) + 1;
|
||||
}
|
||||
result_len = lenx + leny;
|
||||
}
|
||||
{
|
||||
/* The general case; lenx, result_len is known: */
|
||||
register struct Concatenation * result;
|
||||
|
||||
result = GC_NEW(struct Concatenation);
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
result->header = CONCAT_HDR;
|
||||
result->depth = depth;
|
||||
if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
|
||||
result->len = result_len;
|
||||
result->left = x;
|
||||
result->right = y;
|
||||
if (depth >= MAX_DEPTH) {
|
||||
return(CORD_balance((CORD)result));
|
||||
} else {
|
||||
return((CORD) result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CORD CORD_cat(CORD x, CORD y)
|
||||
{
|
||||
register size_t result_len;
|
||||
register int depth;
|
||||
register size_t lenx;
|
||||
|
||||
if (x == CORD_EMPTY) return(y);
|
||||
if (y == CORD_EMPTY) return(x);
|
||||
if (CORD_IS_STRING(y)) {
|
||||
return(CORD_cat_char_star(x, y, strlen(y)));
|
||||
} else if (CORD_IS_STRING(x)) {
|
||||
lenx = strlen(x);
|
||||
depth = DEPTH(y) + 1;
|
||||
} else {
|
||||
register int depthy = DEPTH(y);
|
||||
|
||||
lenx = LEN(x);
|
||||
depth = DEPTH(x) + 1;
|
||||
if (depthy >= depth) depth = depthy + 1;
|
||||
}
|
||||
result_len = lenx + LEN(y);
|
||||
{
|
||||
register struct Concatenation * result;
|
||||
|
||||
result = GC_NEW(struct Concatenation);
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
result->header = CONCAT_HDR;
|
||||
result->depth = depth;
|
||||
if (lenx <= MAX_LEFT_LEN) result->left_len = lenx;
|
||||
result->len = result_len;
|
||||
result->left = x;
|
||||
result->right = y;
|
||||
if (depth >= MAX_DEPTH) {
|
||||
return(CORD_balance((CORD)result));
|
||||
} else {
|
||||
return((CORD) result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
CORD CORD_from_fn(CORD_fn fn, void * client_data, size_t len)
|
||||
{
|
||||
if (len <= 0) return(0);
|
||||
if (len <= SHORT_LIMIT) {
|
||||
register char * result;
|
||||
register size_t i;
|
||||
char buf[SHORT_LIMIT+1];
|
||||
register char c;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
c = (*fn)(i, client_data);
|
||||
if (c == '\0') goto gen_case;
|
||||
buf[i] = c;
|
||||
}
|
||||
buf[i] = '\0';
|
||||
result = GC_MALLOC_ATOMIC(len+1);
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
strcpy(result, buf);
|
||||
result[len] = '\0';
|
||||
return((CORD) result);
|
||||
}
|
||||
gen_case:
|
||||
{
|
||||
register struct Function * result;
|
||||
|
||||
result = GC_NEW(struct Function);
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
result->header = FN_HDR;
|
||||
/* depth is already 0 */
|
||||
result->len = len;
|
||||
result->fn = fn;
|
||||
result->client_data = client_data;
|
||||
return((CORD) result);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CORD_len(CORD x)
|
||||
{
|
||||
if (x == 0) {
|
||||
return(0);
|
||||
} else {
|
||||
return(GEN_LEN(x));
|
||||
}
|
||||
}
|
||||
|
||||
struct substr_args {
|
||||
CordRep * sa_cord;
|
||||
size_t sa_index;
|
||||
};
|
||||
|
||||
char CORD_index_access_fn(size_t i, void * client_data)
|
||||
{
|
||||
register struct substr_args *descr = (struct substr_args *)client_data;
|
||||
|
||||
return(((char *)(descr->sa_cord))[i + descr->sa_index]);
|
||||
}
|
||||
|
||||
char CORD_apply_access_fn(size_t i, void * client_data)
|
||||
{
|
||||
register struct substr_args *descr = (struct substr_args *)client_data;
|
||||
register struct Function * fn_cord = &(descr->sa_cord->function);
|
||||
|
||||
return((*(fn_cord->fn))(i + descr->sa_index, fn_cord->client_data));
|
||||
}
|
||||
|
||||
/* A version of CORD_substr that simply returns a function node, thus */
|
||||
/* postponing its work. The fourth argument is a function that may */
|
||||
/* be used for efficient access to the ith character. */
|
||||
/* Assumes i >= 0 and i + n < length(x). */
|
||||
CORD CORD_substr_closure(CORD x, size_t i, size_t n, CORD_fn f)
|
||||
{
|
||||
register struct substr_args * sa = GC_NEW(struct substr_args);
|
||||
CORD result;
|
||||
|
||||
if (sa == 0) OUT_OF_MEMORY;
|
||||
sa->sa_cord = (CordRep *)x;
|
||||
sa->sa_index = i;
|
||||
result = CORD_from_fn(f, (void *)sa, n);
|
||||
((CordRep *)result) -> function.header = SUBSTR_HDR;
|
||||
return (result);
|
||||
}
|
||||
|
||||
# define SUBSTR_LIMIT (10 * SHORT_LIMIT)
|
||||
/* Substrings of function nodes and flat strings shorter than */
|
||||
/* this are flat strings. Othewise we use a functional */
|
||||
/* representation, which is significantly slower to access. */
|
||||
|
||||
/* A version of CORD_substr that assumes i >= 0, n > 0, and i + n < length(x).*/
|
||||
CORD CORD_substr_checked(CORD x, size_t i, size_t n)
|
||||
{
|
||||
if (CORD_IS_STRING(x)) {
|
||||
if (n > SUBSTR_LIMIT) {
|
||||
return(CORD_substr_closure(x, i, n, CORD_index_access_fn));
|
||||
} else {
|
||||
register char * result = GC_MALLOC_ATOMIC(n+1);
|
||||
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
strncpy(result, x+i, n);
|
||||
result[n] = '\0';
|
||||
return(result);
|
||||
}
|
||||
} else if (IS_CONCATENATION(x)) {
|
||||
register struct Concatenation * conc
|
||||
= &(((CordRep *)x) -> concatenation);
|
||||
register size_t left_len;
|
||||
register size_t right_len;
|
||||
|
||||
left_len = LEFT_LEN(conc);
|
||||
right_len = conc -> len - left_len;
|
||||
if (i >= left_len) {
|
||||
if (n == right_len) return(conc -> right);
|
||||
return(CORD_substr_checked(conc -> right, i - left_len, n));
|
||||
} else if (i+n <= left_len) {
|
||||
if (n == left_len) return(conc -> left);
|
||||
return(CORD_substr_checked(conc -> left, i, n));
|
||||
} else {
|
||||
/* Need at least one character from each side. */
|
||||
register CORD left_part;
|
||||
register CORD right_part;
|
||||
register size_t left_part_len = left_len - i;
|
||||
|
||||
if (i == 0) {
|
||||
left_part = conc -> left;
|
||||
} else {
|
||||
left_part = CORD_substr_checked(conc -> left, i, left_part_len);
|
||||
}
|
||||
if (i + n == right_len + left_len) {
|
||||
right_part = conc -> right;
|
||||
} else {
|
||||
right_part = CORD_substr_checked(conc -> right, 0,
|
||||
n - left_part_len);
|
||||
}
|
||||
return(CORD_cat(left_part, right_part));
|
||||
}
|
||||
} else /* function */ {
|
||||
if (n > SUBSTR_LIMIT) {
|
||||
if (IS_SUBSTR(x)) {
|
||||
/* Avoid nesting substring nodes. */
|
||||
register struct Function * f = &(((CordRep *)x) -> function);
|
||||
register struct substr_args *descr =
|
||||
(struct substr_args *)(f -> client_data);
|
||||
|
||||
return(CORD_substr_closure((CORD)descr->sa_cord,
|
||||
i + descr->sa_index,
|
||||
n, f -> fn));
|
||||
} else {
|
||||
return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
|
||||
}
|
||||
} else {
|
||||
char * result;
|
||||
register struct Function * f = &(((CordRep *)x) -> function);
|
||||
char buf[SUBSTR_LIMIT+1];
|
||||
register char * p = buf;
|
||||
register char c;
|
||||
register int j;
|
||||
register int lim = i + n;
|
||||
|
||||
for (j = i; j < lim; j++) {
|
||||
c = (*(f -> fn))(j, f -> client_data);
|
||||
if (c == '\0') {
|
||||
return(CORD_substr_closure(x, i, n, CORD_apply_access_fn));
|
||||
}
|
||||
*p++ = c;
|
||||
}
|
||||
*p = '\0';
|
||||
result = GC_MALLOC_ATOMIC(n+1);
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
strcpy(result, buf);
|
||||
return(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CORD CORD_substr(CORD x, size_t i, size_t n)
|
||||
{
|
||||
register size_t len = CORD_len(x);
|
||||
|
||||
if (i >= len || n <= 0) return(0);
|
||||
/* n < 0 is impossible in a correct C implementation, but */
|
||||
/* quite possible under SunOS 4.X. */
|
||||
if (i + n > len) n = len - i;
|
||||
# ifndef __STDC__
|
||||
if (i < 0) ABORT("CORD_substr: second arg. negative");
|
||||
/* Possible only if both client and C implementation are buggy. */
|
||||
/* But empirically this happens frequently. */
|
||||
# endif
|
||||
return(CORD_substr_checked(x, i, n));
|
||||
}
|
||||
|
||||
/* See cord.h for definition. We assume i is in range. */
|
||||
int CORD_iter5(CORD x, size_t i, CORD_iter_fn f1,
|
||||
CORD_batched_iter_fn f2, void * client_data)
|
||||
{
|
||||
if (x == 0) return(0);
|
||||
if (CORD_IS_STRING(x)) {
|
||||
register const char *p = x+i;
|
||||
|
||||
if (*p == '\0') ABORT("2nd arg to CORD_iter5 too big");
|
||||
if (f2 != CORD_NO_FN) {
|
||||
return((*f2)(p, client_data));
|
||||
} else {
|
||||
while (*p) {
|
||||
if ((*f1)(*p, client_data)) return(1);
|
||||
p++;
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
} else if (IS_CONCATENATION(x)) {
|
||||
register struct Concatenation * conc
|
||||
= &(((CordRep *)x) -> concatenation);
|
||||
|
||||
|
||||
if (i > 0) {
|
||||
register size_t left_len = LEFT_LEN(conc);
|
||||
|
||||
if (i >= left_len) {
|
||||
return(CORD_iter5(conc -> right, i - left_len, f1, f2,
|
||||
client_data));
|
||||
}
|
||||
}
|
||||
if (CORD_iter5(conc -> left, i, f1, f2, client_data)) {
|
||||
return(1);
|
||||
}
|
||||
return(CORD_iter5(conc -> right, 0, f1, f2, client_data));
|
||||
} else /* function */ {
|
||||
register struct Function * f = &(((CordRep *)x) -> function);
|
||||
register size_t j;
|
||||
register size_t lim = f -> len;
|
||||
|
||||
for (j = i; j < lim; j++) {
|
||||
if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
#undef CORD_iter
|
||||
int CORD_iter(CORD x, CORD_iter_fn f1, void * client_data)
|
||||
{
|
||||
return(CORD_iter5(x, 0, f1, CORD_NO_FN, client_data));
|
||||
}
|
||||
|
||||
int CORD_riter4(CORD x, size_t i, CORD_iter_fn f1, void * client_data)
|
||||
{
|
||||
if (x == 0) return(0);
|
||||
if (CORD_IS_STRING(x)) {
|
||||
register const char *p = x + i;
|
||||
register char c;
|
||||
|
||||
for(;;) {
|
||||
c = *p;
|
||||
if (c == '\0') ABORT("2nd arg to CORD_riter4 too big");
|
||||
if ((*f1)(c, client_data)) return(1);
|
||||
if (p == x) break;
|
||||
p--;
|
||||
}
|
||||
return(0);
|
||||
} else if (IS_CONCATENATION(x)) {
|
||||
register struct Concatenation * conc
|
||||
= &(((CordRep *)x) -> concatenation);
|
||||
register CORD left_part = conc -> left;
|
||||
register size_t left_len;
|
||||
|
||||
left_len = LEFT_LEN(conc);
|
||||
if (i >= left_len) {
|
||||
if (CORD_riter4(conc -> right, i - left_len, f1, client_data)) {
|
||||
return(1);
|
||||
}
|
||||
return(CORD_riter4(left_part, left_len - 1, f1, client_data));
|
||||
} else {
|
||||
return(CORD_riter4(left_part, i, f1, client_data));
|
||||
}
|
||||
} else /* function */ {
|
||||
register struct Function * f = &(((CordRep *)x) -> function);
|
||||
register size_t j;
|
||||
|
||||
for (j = i; ; j--) {
|
||||
if ((*f1)((*(f -> fn))(j, f -> client_data), client_data)) {
|
||||
return(1);
|
||||
}
|
||||
if (j == 0) return(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CORD_riter(CORD x, CORD_iter_fn f1, void * client_data)
|
||||
{
|
||||
return(CORD_riter4(x, CORD_len(x) - 1, f1, client_data));
|
||||
}
|
||||
|
||||
/*
|
||||
* The following functions are concerned with balancing cords.
|
||||
* Strategy:
|
||||
* Scan the cord from left to right, keeping the cord scanned so far
|
||||
* as a forest of balanced trees of exponentialy decreasing length.
|
||||
* When a new subtree needs to be added to the forest, we concatenate all
|
||||
* shorter ones to the new tree in the appropriate order, and then insert
|
||||
* the result into the forest.
|
||||
* Crucial invariants:
|
||||
* 1. The concatenation of the forest (in decreasing order) with the
|
||||
* unscanned part of the rope is equal to the rope being balanced.
|
||||
* 2. All trees in the forest are balanced.
|
||||
* 3. forest[i] has depth at most i.
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
CORD c;
|
||||
size_t len; /* Actual length of c */
|
||||
} ForestElement;
|
||||
|
||||
static size_t min_len [ MAX_DEPTH ];
|
||||
|
||||
static int min_len_init = 0;
|
||||
|
||||
int CORD_max_len;
|
||||
|
||||
typedef ForestElement Forest [ MAX_DEPTH ];
|
||||
/* forest[i].len >= fib(i+1) */
|
||||
/* The string is the concatenation */
|
||||
/* of the forest in order of DECREASING */
|
||||
/* indices. */
|
||||
|
||||
void CORD_init_min_len()
|
||||
{
|
||||
register int i;
|
||||
register size_t last, previous, current;
|
||||
|
||||
min_len[0] = previous = 1;
|
||||
min_len[1] = last = 2;
|
||||
for (i = 2; i < MAX_DEPTH; i++) {
|
||||
current = last + previous;
|
||||
if (current < last) /* overflow */ current = last;
|
||||
min_len[i] = current;
|
||||
previous = last;
|
||||
last = current;
|
||||
}
|
||||
CORD_max_len = last - 1;
|
||||
min_len_init = 1;
|
||||
}
|
||||
|
||||
|
||||
void CORD_init_forest(ForestElement * forest, size_t max_len)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < MAX_DEPTH; i++) {
|
||||
forest[i].c = 0;
|
||||
if (min_len[i] > max_len) return;
|
||||
}
|
||||
ABORT("Cord too long");
|
||||
}
|
||||
|
||||
/* Add a leaf to the appropriate level in the forest, cleaning */
|
||||
/* out lower levels as necessary. */
|
||||
/* Also works if x is a balanced tree of concatenations; however */
|
||||
/* in this case an extra concatenation node may be inserted above x; */
|
||||
/* This node should not be counted in the statement of the invariants. */
|
||||
void CORD_add_forest(ForestElement * forest, CORD x, size_t len)
|
||||
{
|
||||
register int i = 0;
|
||||
register CORD sum = CORD_EMPTY;
|
||||
register size_t sum_len = 0;
|
||||
|
||||
while (len > min_len[i + 1]) {
|
||||
if (forest[i].c != 0) {
|
||||
sum = CORD_cat(forest[i].c, sum);
|
||||
sum_len += forest[i].len;
|
||||
forest[i].c = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
/* Sum has depth at most 1 greter than what would be required */
|
||||
/* for balance. */
|
||||
sum = CORD_cat(sum, x);
|
||||
sum_len += len;
|
||||
/* If x was a leaf, then sum is now balanced. To see this */
|
||||
/* consider the two cases in which forest[i-1] either is or is */
|
||||
/* not empty. */
|
||||
while (sum_len >= min_len[i]) {
|
||||
if (forest[i].c != 0) {
|
||||
sum = CORD_cat(forest[i].c, sum);
|
||||
sum_len += forest[i].len;
|
||||
/* This is again balanced, since sum was balanced, and has */
|
||||
/* allowable depth that differs from i by at most 1. */
|
||||
forest[i].c = 0;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
i--;
|
||||
forest[i].c = sum;
|
||||
forest[i].len = sum_len;
|
||||
}
|
||||
|
||||
CORD CORD_concat_forest(ForestElement * forest, size_t expected_len)
|
||||
{
|
||||
register int i = 0;
|
||||
CORD sum = 0;
|
||||
size_t sum_len = 0;
|
||||
|
||||
while (sum_len != expected_len) {
|
||||
if (forest[i].c != 0) {
|
||||
sum = CORD_cat(forest[i].c, sum);
|
||||
sum_len += forest[i].len;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return(sum);
|
||||
}
|
||||
|
||||
/* Insert the frontier of x into forest. Balanced subtrees are */
|
||||
/* treated as leaves. This potentially adds one to the depth */
|
||||
/* of the final tree. */
|
||||
void CORD_balance_insert(CORD x, size_t len, ForestElement * forest)
|
||||
{
|
||||
register int depth;
|
||||
|
||||
if (CORD_IS_STRING(x)) {
|
||||
CORD_add_forest(forest, x, len);
|
||||
} else if (IS_CONCATENATION(x)
|
||||
&& ((depth = DEPTH(x)) >= MAX_DEPTH
|
||||
|| len < min_len[depth])) {
|
||||
register struct Concatenation * conc
|
||||
= &(((CordRep *)x) -> concatenation);
|
||||
size_t left_len = LEFT_LEN(conc);
|
||||
|
||||
CORD_balance_insert(conc -> left, left_len, forest);
|
||||
CORD_balance_insert(conc -> right, len - left_len, forest);
|
||||
} else /* function or balanced */ {
|
||||
CORD_add_forest(forest, x, len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
CORD CORD_balance(CORD x)
|
||||
{
|
||||
Forest forest;
|
||||
register size_t len;
|
||||
|
||||
if (x == 0) return(0);
|
||||
if (CORD_IS_STRING(x)) return(x);
|
||||
if (!min_len_init) CORD_init_min_len();
|
||||
len = LEN(x);
|
||||
CORD_init_forest(forest, len);
|
||||
CORD_balance_insert(x, len, forest);
|
||||
return(CORD_concat_forest(forest, len));
|
||||
}
|
||||
|
||||
|
||||
/* Position primitives */
|
||||
|
||||
/* Private routines to deal with the hard cases only: */
|
||||
|
||||
/* P contains a prefix of the path to cur_pos. Extend it to a full */
|
||||
/* path and set up leaf info. */
|
||||
/* Return 0 if past the end of cord, 1 o.w. */
|
||||
void CORD__extend_path(register CORD_pos p)
|
||||
{
|
||||
register struct CORD_pe * current_pe = &(p[0].path[p[0].path_len]);
|
||||
register CORD top = current_pe -> pe_cord;
|
||||
register size_t pos = p[0].cur_pos;
|
||||
register size_t top_pos = current_pe -> pe_start_pos;
|
||||
register size_t top_len = GEN_LEN(top);
|
||||
|
||||
/* Fill in the rest of the path. */
|
||||
while(!CORD_IS_STRING(top) && IS_CONCATENATION(top)) {
|
||||
register struct Concatenation * conc =
|
||||
&(((CordRep *)top) -> concatenation);
|
||||
register size_t left_len;
|
||||
|
||||
left_len = LEFT_LEN(conc);
|
||||
current_pe++;
|
||||
if (pos >= top_pos + left_len) {
|
||||
current_pe -> pe_cord = top = conc -> right;
|
||||
current_pe -> pe_start_pos = top_pos = top_pos + left_len;
|
||||
top_len -= left_len;
|
||||
} else {
|
||||
current_pe -> pe_cord = top = conc -> left;
|
||||
current_pe -> pe_start_pos = top_pos;
|
||||
top_len = left_len;
|
||||
}
|
||||
p[0].path_len++;
|
||||
}
|
||||
/* Fill in leaf description for fast access. */
|
||||
if (CORD_IS_STRING(top)) {
|
||||
p[0].cur_leaf = top;
|
||||
p[0].cur_start = top_pos;
|
||||
p[0].cur_end = top_pos + top_len;
|
||||
} else {
|
||||
p[0].cur_end = 0;
|
||||
}
|
||||
if (pos >= top_pos + top_len) p[0].path_len = CORD_POS_INVALID;
|
||||
}
|
||||
|
||||
char CORD__pos_fetch(register CORD_pos p)
|
||||
{
|
||||
/* Leaf is a function node */
|
||||
struct CORD_pe * pe = &((p)[0].path[(p)[0].path_len]);
|
||||
CORD leaf = pe -> pe_cord;
|
||||
register struct Function * f = &(((CordRep *)leaf) -> function);
|
||||
|
||||
if (!IS_FUNCTION(leaf)) ABORT("CORD_pos_fetch: bad leaf");
|
||||
return ((*(f -> fn))(p[0].cur_pos - pe -> pe_start_pos, f -> client_data));
|
||||
}
|
||||
|
||||
void CORD__next(register CORD_pos p)
|
||||
{
|
||||
register size_t cur_pos = p[0].cur_pos + 1;
|
||||
register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
|
||||
register CORD leaf = current_pe -> pe_cord;
|
||||
|
||||
/* Leaf is not a string or we're at end of leaf */
|
||||
p[0].cur_pos = cur_pos;
|
||||
if (!CORD_IS_STRING(leaf)) {
|
||||
/* Function leaf */
|
||||
register struct Function * f = &(((CordRep *)leaf) -> function);
|
||||
register size_t start_pos = current_pe -> pe_start_pos;
|
||||
register size_t end_pos = start_pos + f -> len;
|
||||
|
||||
if (cur_pos < end_pos) {
|
||||
/* Fill cache and return. */
|
||||
register size_t i;
|
||||
register size_t limit = cur_pos + FUNCTION_BUF_SZ;
|
||||
register CORD_fn fn = f -> fn;
|
||||
register void * client_data = f -> client_data;
|
||||
|
||||
if (limit > end_pos) {
|
||||
limit = end_pos;
|
||||
}
|
||||
for (i = cur_pos; i < limit; i++) {
|
||||
p[0].function_buf[i - cur_pos] =
|
||||
(*fn)(i - start_pos, client_data);
|
||||
}
|
||||
p[0].cur_start = cur_pos;
|
||||
p[0].cur_leaf = p[0].function_buf;
|
||||
p[0].cur_end = limit;
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* End of leaf */
|
||||
/* Pop the stack until we find two concatenation nodes with the */
|
||||
/* same start position: this implies we were in left part. */
|
||||
{
|
||||
while (p[0].path_len > 0
|
||||
&& current_pe[0].pe_start_pos != current_pe[-1].pe_start_pos) {
|
||||
p[0].path_len--;
|
||||
current_pe--;
|
||||
}
|
||||
if (p[0].path_len == 0) {
|
||||
p[0].path_len = CORD_POS_INVALID;
|
||||
return;
|
||||
}
|
||||
}
|
||||
p[0].path_len--;
|
||||
CORD__extend_path(p);
|
||||
}
|
||||
|
||||
void CORD__prev(register CORD_pos p)
|
||||
{
|
||||
register struct CORD_pe * pe = &(p[0].path[p[0].path_len]);
|
||||
|
||||
if (p[0].cur_pos == 0) {
|
||||
p[0].path_len = CORD_POS_INVALID;
|
||||
return;
|
||||
}
|
||||
p[0].cur_pos--;
|
||||
if (p[0].cur_pos >= pe -> pe_start_pos) return;
|
||||
|
||||
/* Beginning of leaf */
|
||||
|
||||
/* Pop the stack until we find two concatenation nodes with the */
|
||||
/* different start position: this implies we were in right part. */
|
||||
{
|
||||
register struct CORD_pe * current_pe = &((p)[0].path[(p)[0].path_len]);
|
||||
|
||||
while (p[0].path_len > 0
|
||||
&& current_pe[0].pe_start_pos == current_pe[-1].pe_start_pos) {
|
||||
p[0].path_len--;
|
||||
current_pe--;
|
||||
}
|
||||
}
|
||||
p[0].path_len--;
|
||||
CORD__extend_path(p);
|
||||
}
|
||||
|
||||
#undef CORD_pos_fetch
|
||||
#undef CORD_next
|
||||
#undef CORD_prev
|
||||
#undef CORD_pos_to_index
|
||||
#undef CORD_pos_to_cord
|
||||
#undef CORD_pos_valid
|
||||
|
||||
char CORD_pos_fetch(register CORD_pos p)
|
||||
{
|
||||
if (p[0].cur_start <= p[0].cur_pos && p[0].cur_pos < p[0].cur_end) {
|
||||
return(p[0].cur_leaf[p[0].cur_pos - p[0].cur_start]);
|
||||
} else {
|
||||
return(CORD__pos_fetch(p));
|
||||
}
|
||||
}
|
||||
|
||||
void CORD_next(CORD_pos p)
|
||||
{
|
||||
if (p[0].cur_pos < p[0].cur_end - 1) {
|
||||
p[0].cur_pos++;
|
||||
} else {
|
||||
CORD__next(p);
|
||||
}
|
||||
}
|
||||
|
||||
void CORD_prev(CORD_pos p)
|
||||
{
|
||||
if (p[0].cur_end != 0 && p[0].cur_pos > p[0].cur_start) {
|
||||
p[0].cur_pos--;
|
||||
} else {
|
||||
CORD__prev(p);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CORD_pos_to_index(CORD_pos p)
|
||||
{
|
||||
return(p[0].cur_pos);
|
||||
}
|
||||
|
||||
CORD CORD_pos_to_cord(CORD_pos p)
|
||||
{
|
||||
return(p[0].path[0].pe_cord);
|
||||
}
|
||||
|
||||
int CORD_pos_valid(CORD_pos p)
|
||||
{
|
||||
return(p[0].path_len != CORD_POS_INVALID);
|
||||
}
|
||||
|
||||
void CORD_set_pos(CORD_pos p, CORD x, size_t i)
|
||||
{
|
||||
if (x == CORD_EMPTY) {
|
||||
p[0].path_len = CORD_POS_INVALID;
|
||||
return;
|
||||
}
|
||||
p[0].path[0].pe_cord = x;
|
||||
p[0].path[0].pe_start_pos = 0;
|
||||
p[0].path_len = 0;
|
||||
p[0].cur_pos = i;
|
||||
CORD__extend_path(p);
|
||||
}
|
||||
396
src/engine/boehm_gc/cord/cordprnt.c
Normal file
396
src/engine/boehm_gc/cord/cordprnt.c
Normal file
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
/* An sprintf implementation that understands cords. This is probably */
|
||||
/* not terribly portable. It assumes an ANSI stdarg.h. It further */
|
||||
/* assumes that I can make copies of va_list variables, and read */
|
||||
/* arguments repeatedly by applyting va_arg to the copies. This */
|
||||
/* could be avoided at some performance cost. */
|
||||
/* We also assume that unsigned and signed integers of various kinds */
|
||||
/* have the same sizes, and can be cast back and forth. */
|
||||
/* We assume that void * and char * have the same size. */
|
||||
/* All this cruft is needed because we want to rely on the underlying */
|
||||
/* sprintf implementation whenever possible. */
|
||||
/* Boehm, September 21, 1995 6:00 pm PDT */
|
||||
|
||||
#include "cord.h"
|
||||
#include "ec.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include "gc.h"
|
||||
|
||||
#define CONV_SPEC_LEN 50 /* Maximum length of a single */
|
||||
/* conversion specification. */
|
||||
#define CONV_RESULT_LEN 50 /* Maximum length of any */
|
||||
/* conversion with default */
|
||||
/* width and prec. */
|
||||
|
||||
|
||||
static int ec_len(CORD_ec x)
|
||||
{
|
||||
return(CORD_len(x[0].ec_cord) + (x[0].ec_bufptr - x[0].ec_buf));
|
||||
}
|
||||
|
||||
/* Possible nonumeric precision values. */
|
||||
# define NONE -1
|
||||
# define VARIABLE -2
|
||||
/* Copy the conversion specification from CORD_pos into the buffer buf */
|
||||
/* Return negative on error. */
|
||||
/* Source initially points one past the leading %. */
|
||||
/* It is left pointing at the conversion type. */
|
||||
/* Assign field width and precision to *width and *prec. */
|
||||
/* If width or prec is *, VARIABLE is assigned. */
|
||||
/* Set *left to 1 if left adjustment flag is present. */
|
||||
/* Set *long_arg to 1 if long flag ('l' or 'L') is present, or to */
|
||||
/* -1 if 'h' is present. */
|
||||
static int extract_conv_spec(CORD_pos source, char *buf,
|
||||
int * width, int *prec, int *left, int * long_arg)
|
||||
{
|
||||
register int result = 0;
|
||||
register int current_number = 0;
|
||||
register int saw_period = 0;
|
||||
register int saw_number = 0;
|
||||
register int chars_so_far = 0;
|
||||
register char current;
|
||||
|
||||
*width = NONE;
|
||||
buf[chars_so_far++] = '%';
|
||||
while(CORD_pos_valid(source)) {
|
||||
if (chars_so_far >= CONV_SPEC_LEN) return(-1);
|
||||
current = CORD_pos_fetch(source);
|
||||
buf[chars_so_far++] = current;
|
||||
switch(current) {
|
||||
case '*':
|
||||
saw_number = 1;
|
||||
current_number = VARIABLE;
|
||||
break;
|
||||
case '0':
|
||||
if (!saw_number) {
|
||||
/* Zero fill flag; ignore */
|
||||
break;
|
||||
} /* otherwise fall through: */
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
saw_number = 1;
|
||||
current_number *= 10;
|
||||
current_number += current - '0';
|
||||
break;
|
||||
case '.':
|
||||
saw_period = 1;
|
||||
if(saw_number) {
|
||||
*width = current_number;
|
||||
saw_number = 0;
|
||||
}
|
||||
current_number = 0;
|
||||
break;
|
||||
case 'l':
|
||||
case 'L':
|
||||
*long_arg = 1;
|
||||
current_number = 0;
|
||||
break;
|
||||
case 'h':
|
||||
*long_arg = -1;
|
||||
current_number = 0;
|
||||
break;
|
||||
case ' ':
|
||||
case '+':
|
||||
case '#':
|
||||
current_number = 0;
|
||||
break;
|
||||
case '-':
|
||||
*left = 1;
|
||||
current_number = 0;
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'f':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
case 'c':
|
||||
case 'C':
|
||||
case 's':
|
||||
case 'S':
|
||||
case 'p':
|
||||
case 'n':
|
||||
case 'r':
|
||||
goto done;
|
||||
default:
|
||||
return(-1);
|
||||
}
|
||||
CORD_next(source);
|
||||
}
|
||||
return(-1);
|
||||
done:
|
||||
if (saw_number) {
|
||||
if (saw_period) {
|
||||
*prec = current_number;
|
||||
} else {
|
||||
*prec = NONE;
|
||||
*width = current_number;
|
||||
}
|
||||
} else {
|
||||
*prec = NONE;
|
||||
}
|
||||
buf[chars_so_far] = '\0';
|
||||
return(result);
|
||||
}
|
||||
|
||||
int CORD_vsprintf(CORD * out, CORD format, va_list args)
|
||||
{
|
||||
CORD_ec result;
|
||||
register int count;
|
||||
register char current;
|
||||
CORD_pos pos;
|
||||
char conv_spec[CONV_SPEC_LEN + 1];
|
||||
|
||||
CORD_ec_init(result);
|
||||
for (CORD_set_pos(pos, format, 0); CORD_pos_valid(pos); CORD_next(pos)) {
|
||||
current = CORD_pos_fetch(pos);
|
||||
if (current == '%') {
|
||||
CORD_next(pos);
|
||||
if (!CORD_pos_valid(pos)) return(-1);
|
||||
current = CORD_pos_fetch(pos);
|
||||
if (current == '%') {
|
||||
CORD_ec_append(result, current);
|
||||
} else {
|
||||
int width, prec;
|
||||
int left_adj = 0;
|
||||
int long_arg = 0;
|
||||
CORD arg;
|
||||
size_t len;
|
||||
|
||||
if (extract_conv_spec(pos, conv_spec,
|
||||
&width, &prec,
|
||||
&left_adj, &long_arg) < 0) {
|
||||
return(-1);
|
||||
}
|
||||
current = CORD_pos_fetch(pos);
|
||||
switch(current) {
|
||||
case 'n':
|
||||
/* Assign length to next arg */
|
||||
if (long_arg == 0) {
|
||||
int * pos_ptr;
|
||||
pos_ptr = va_arg(args, int *);
|
||||
*pos_ptr = ec_len(result);
|
||||
} else if (long_arg > 0) {
|
||||
long * pos_ptr;
|
||||
pos_ptr = va_arg(args, long *);
|
||||
*pos_ptr = ec_len(result);
|
||||
} else {
|
||||
short * pos_ptr;
|
||||
pos_ptr = va_arg(args, short *);
|
||||
*pos_ptr = ec_len(result);
|
||||
}
|
||||
goto done;
|
||||
case 'r':
|
||||
/* Append cord and any padding */
|
||||
if (width == VARIABLE) width = va_arg(args, int);
|
||||
if (prec == VARIABLE) prec = va_arg(args, int);
|
||||
arg = va_arg(args, CORD);
|
||||
len = CORD_len(arg);
|
||||
if (prec != NONE && len > prec) {
|
||||
if (prec < 0) return(-1);
|
||||
arg = CORD_substr(arg, 0, prec);
|
||||
len = prec;
|
||||
}
|
||||
if (width != NONE && len < width) {
|
||||
char * blanks = GC_MALLOC_ATOMIC(width-len+1);
|
||||
|
||||
memset(blanks, ' ', width-len);
|
||||
blanks[width-len] = '\0';
|
||||
if (left_adj) {
|
||||
arg = CORD_cat(arg, blanks);
|
||||
} else {
|
||||
arg = CORD_cat(blanks, arg);
|
||||
}
|
||||
}
|
||||
CORD_ec_append_cord(result, arg);
|
||||
goto done;
|
||||
case 'c':
|
||||
if (width == NONE && prec == NONE) {
|
||||
register char c;
|
||||
|
||||
c = (char)va_arg(args, int);
|
||||
CORD_ec_append(result, c);
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
if (width == NONE && prec == NONE) {
|
||||
char * str = va_arg(args, char *);
|
||||
register char c;
|
||||
|
||||
while ((c = *str++)) {
|
||||
CORD_ec_append(result, c);
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Use standard sprintf to perform conversion */
|
||||
{
|
||||
register char * buf;
|
||||
va_list vsprintf_args;
|
||||
int max_size = 0;
|
||||
int res;
|
||||
# ifdef __va_copy
|
||||
__va_copy(vsprintf_args, args);
|
||||
# else
|
||||
# if defined(__GNUC__) && !defined(__DJGPP__) /* and probably in other cases */
|
||||
va_copy(vsprintf_args, args);
|
||||
# else
|
||||
vsprintf_args = args;
|
||||
# endif
|
||||
# endif
|
||||
if (width == VARIABLE) width = va_arg(args, int);
|
||||
if (prec == VARIABLE) prec = va_arg(args, int);
|
||||
if (width != NONE) max_size = width;
|
||||
if (prec != NONE && prec > max_size) max_size = prec;
|
||||
max_size += CONV_RESULT_LEN;
|
||||
if (max_size >= CORD_BUFSZ) {
|
||||
buf = GC_MALLOC_ATOMIC(max_size + 1);
|
||||
} else {
|
||||
if (CORD_BUFSZ - (result[0].ec_bufptr-result[0].ec_buf)
|
||||
< max_size) {
|
||||
CORD_ec_flush_buf(result);
|
||||
}
|
||||
buf = result[0].ec_bufptr;
|
||||
}
|
||||
switch(current) {
|
||||
case 'd':
|
||||
case 'i':
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
case 'c':
|
||||
if (long_arg <= 0) {
|
||||
(void) va_arg(args, int);
|
||||
} else if (long_arg > 0) {
|
||||
(void) va_arg(args, long);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
case 'p':
|
||||
(void) va_arg(args, char *);
|
||||
break;
|
||||
case 'f':
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'g':
|
||||
case 'G':
|
||||
(void) va_arg(args, double);
|
||||
break;
|
||||
default:
|
||||
return(-1);
|
||||
}
|
||||
res = vsprintf(buf, conv_spec, vsprintf_args);
|
||||
len = (size_t)res;
|
||||
if ((char *)(GC_word)res == buf) {
|
||||
/* old style vsprintf */
|
||||
len = strlen(buf);
|
||||
} else if (res < 0) {
|
||||
return(-1);
|
||||
}
|
||||
if (buf != result[0].ec_bufptr) {
|
||||
register char c;
|
||||
|
||||
while ((c = *buf++)) {
|
||||
CORD_ec_append(result, c);
|
||||
}
|
||||
} else {
|
||||
result[0].ec_bufptr = buf + len;
|
||||
}
|
||||
}
|
||||
done:;
|
||||
}
|
||||
} else {
|
||||
CORD_ec_append(result, current);
|
||||
}
|
||||
}
|
||||
count = ec_len(result);
|
||||
*out = CORD_balance(CORD_ec_to_cord(result));
|
||||
return(count);
|
||||
}
|
||||
|
||||
int CORD_sprintf(CORD * out, CORD format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int result;
|
||||
|
||||
va_start(args, format);
|
||||
result = CORD_vsprintf(out, format, args);
|
||||
va_end(args);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int CORD_fprintf(FILE * f, CORD format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int result;
|
||||
CORD out;
|
||||
|
||||
va_start(args, format);
|
||||
result = CORD_vsprintf(&out, format, args);
|
||||
va_end(args);
|
||||
if (result > 0) CORD_put(out, f);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int CORD_vfprintf(FILE * f, CORD format, va_list args)
|
||||
{
|
||||
int result;
|
||||
CORD out;
|
||||
|
||||
result = CORD_vsprintf(&out, format, args);
|
||||
if (result > 0) CORD_put(out, f);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int CORD_printf(CORD format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int result;
|
||||
CORD out;
|
||||
|
||||
va_start(args, format);
|
||||
result = CORD_vsprintf(&out, format, args);
|
||||
va_end(args);
|
||||
if (result > 0) CORD_put(out, stdout);
|
||||
return(result);
|
||||
}
|
||||
|
||||
int CORD_vprintf(CORD format, va_list args)
|
||||
{
|
||||
int result;
|
||||
CORD out;
|
||||
|
||||
result = CORD_vsprintf(&out, format, args);
|
||||
if (result > 0) CORD_put(out, stdout);
|
||||
return(result);
|
||||
}
|
||||
235
src/engine/boehm_gc/cord/cordtest.c
Normal file
235
src/engine/boehm_gc/cord/cordtest.c
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
/* Boehm, August 24, 1994 11:58 am PDT */
|
||||
# include "gc.h" /* For GC_INIT() only */
|
||||
# include "cord.h"
|
||||
# include <string.h>
|
||||
# include <stdio.h>
|
||||
# include <stdlib.h>
|
||||
/* This is a very incomplete test of the cord package. It knows about */
|
||||
/* a few internals of the package (e.g. when C strings are returned) */
|
||||
/* that real clients shouldn't rely on. */
|
||||
|
||||
# define ABORT(string) \
|
||||
{ int x = 0; fprintf(stderr, "FAILED: %s\n", string); x = 1 / x; abort(); }
|
||||
|
||||
int count;
|
||||
|
||||
int test_fn(char c, void * client_data)
|
||||
{
|
||||
if (client_data != (void *)13) ABORT("bad client data");
|
||||
if (count < 64*1024+1) {
|
||||
if ((count & 1) == 0) {
|
||||
if (c != 'b') ABORT("bad char");
|
||||
} else {
|
||||
if (c != 'a') ABORT("bad char");
|
||||
}
|
||||
count++;
|
||||
return(0);
|
||||
} else {
|
||||
if (c != 'c') ABORT("bad char");
|
||||
count++;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
char id_cord_fn(size_t i, void * client_data)
|
||||
{
|
||||
return((char)i);
|
||||
}
|
||||
|
||||
void test_basics()
|
||||
{
|
||||
CORD x = CORD_from_char_star("ab");
|
||||
register int i;
|
||||
char c;
|
||||
CORD y;
|
||||
CORD_pos p;
|
||||
|
||||
x = CORD_cat(x,x);
|
||||
if (!CORD_IS_STRING(x)) ABORT("short cord should usually be a string");
|
||||
if (strcmp(x, "abab") != 0) ABORT("bad CORD_cat result");
|
||||
|
||||
for (i = 1; i < 16; i++) {
|
||||
x = CORD_cat(x,x);
|
||||
}
|
||||
x = CORD_cat(x,"c");
|
||||
if (CORD_len(x) != 128*1024+1) ABORT("bad length");
|
||||
|
||||
count = 0;
|
||||
if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
|
||||
ABORT("CORD_iter5 failed");
|
||||
}
|
||||
if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
|
||||
|
||||
count = 0;
|
||||
CORD_set_pos(p, x, 64*1024-1);
|
||||
while(CORD_pos_valid(p)) {
|
||||
(void) test_fn(CORD_pos_fetch(p), (void *)13);
|
||||
CORD_next(p);
|
||||
}
|
||||
if (count != 64*1024 + 2) ABORT("Position based iteration failed");
|
||||
|
||||
y = CORD_substr(x, 1023, 5);
|
||||
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
|
||||
if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
|
||||
|
||||
y = CORD_substr(x, 1024, 8);
|
||||
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
|
||||
if (strcmp(y, "abababab") != 0) ABORT("bad CORD_substr result");
|
||||
|
||||
y = CORD_substr(x, 128*1024-1, 8);
|
||||
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
|
||||
if (strcmp(y, "bc") != 0) ABORT("bad CORD_substr result");
|
||||
|
||||
x = CORD_balance(x);
|
||||
if (CORD_len(x) != 128*1024+1) ABORT("bad length");
|
||||
|
||||
count = 0;
|
||||
if (CORD_iter5(x, 64*1024-1, test_fn, CORD_NO_FN, (void *)13) == 0) {
|
||||
ABORT("CORD_iter5 failed");
|
||||
}
|
||||
if (count != 64*1024 + 2) ABORT("CORD_iter5 failed");
|
||||
|
||||
y = CORD_substr(x, 1023, 5);
|
||||
if (!CORD_IS_STRING(y)) ABORT("short cord should usually be a string");
|
||||
if (strcmp(y, "babab") != 0) ABORT("bad CORD_substr result");
|
||||
y = CORD_from_fn(id_cord_fn, 0, 13);
|
||||
i = 0;
|
||||
CORD_set_pos(p, y, i);
|
||||
while(CORD_pos_valid(p)) {
|
||||
c = CORD_pos_fetch(p);
|
||||
if(c != i) ABORT("Traversal of function node failed");
|
||||
CORD_next(p); i++;
|
||||
}
|
||||
if (i != 13) ABORT("Bad apparent length for function node");
|
||||
}
|
||||
|
||||
void test_extras()
|
||||
{
|
||||
# if defined(__OS2__) || defined(__DJGPP__)
|
||||
# define FNAME1 "tmp1"
|
||||
# define FNAME2 "tmp2"
|
||||
# elif defined(AMIGA)
|
||||
# define FNAME1 "T:tmp1"
|
||||
# define FNAME2 "T:tmp2"
|
||||
# else
|
||||
# define FNAME1 "/tmp/cord_test"
|
||||
# define FNAME2 "/tmp/cord_test2"
|
||||
# endif
|
||||
register int i;
|
||||
CORD y = "abcdefghijklmnopqrstuvwxyz0123456789";
|
||||
CORD x = "{}";
|
||||
CORD w, z;
|
||||
FILE *f;
|
||||
FILE *f1a, *f1b, *f2;
|
||||
|
||||
w = CORD_cat(CORD_cat(y,y),y);
|
||||
z = CORD_catn(3,y,y,y);
|
||||
if (CORD_cmp(w,z) != 0) ABORT("CORD_catn comparison wrong");
|
||||
for (i = 1; i < 100; i++) {
|
||||
x = CORD_cat(x, y);
|
||||
}
|
||||
z = CORD_balance(x);
|
||||
if (CORD_cmp(x,z) != 0) ABORT("balanced string comparison wrong");
|
||||
if (CORD_cmp(x,CORD_cat(z, CORD_nul(13))) >= 0) ABORT("comparison 2");
|
||||
if (CORD_cmp(CORD_cat(x, CORD_nul(13)), z) <= 0) ABORT("comparison 3");
|
||||
if (CORD_cmp(x,CORD_cat(z, "13")) >= 0) ABORT("comparison 4");
|
||||
if ((f = fopen(FNAME1, "w")) == 0) ABORT("open failed");
|
||||
if (CORD_put(z,f) == EOF) ABORT("CORD_put failed");
|
||||
if (fclose(f) == EOF) ABORT("fclose failed");
|
||||
w = CORD_from_file(f1a = fopen(FNAME1, "rb"));
|
||||
if (CORD_len(w) != CORD_len(z)) ABORT("file length wrong");
|
||||
if (CORD_cmp(w,z) != 0) ABORT("file comparison wrong");
|
||||
if (CORD_cmp(CORD_substr(w, 50*36+2, 36), y) != 0)
|
||||
ABORT("file substr wrong");
|
||||
z = CORD_from_file_lazy(f1b = fopen(FNAME1, "rb"));
|
||||
if (CORD_cmp(w,z) != 0) ABORT("File conversions differ");
|
||||
if (CORD_chr(w, 0, '9') != 37) ABORT("CORD_chr failed 1");
|
||||
if (CORD_chr(w, 3, 'a') != 38) ABORT("CORD_chr failed 2");
|
||||
if (CORD_rchr(w, CORD_len(w) - 1, '}') != 1) ABORT("CORD_rchr failed");
|
||||
x = y;
|
||||
for (i = 1; i < 14; i++) {
|
||||
x = CORD_cat(x,x);
|
||||
}
|
||||
if ((f = fopen(FNAME2, "w")) == 0) ABORT("2nd open failed");
|
||||
# ifdef __DJGPP__
|
||||
/* FIXME: DJGPP workaround. Why does this help? */
|
||||
if (fflush(f) != 0) ABORT("fflush failed");
|
||||
# endif
|
||||
if (CORD_put(x,f) == EOF) ABORT("CORD_put failed");
|
||||
if (fclose(f) == EOF) ABORT("fclose failed");
|
||||
w = CORD_from_file(f2 = fopen(FNAME2, "rb"));
|
||||
if (CORD_len(w) != CORD_len(x)) ABORT("file length wrong");
|
||||
if (CORD_cmp(w,x) != 0) ABORT("file comparison wrong");
|
||||
if (CORD_cmp(CORD_substr(w, 1000*36, 36), y) != 0)
|
||||
ABORT("file substr wrong");
|
||||
if (strcmp(CORD_to_char_star(CORD_substr(w, 1000*36, 36)), y) != 0)
|
||||
ABORT("char * file substr wrong");
|
||||
if (strcmp(CORD_substr(w, 1000*36, 2), "ab") != 0)
|
||||
ABORT("short file substr wrong");
|
||||
if (CORD_str(x,1,"9a") != 35) ABORT("CORD_str failed 1");
|
||||
if (CORD_str(x,0,"9abcdefghijk") != 35) ABORT("CORD_str failed 2");
|
||||
if (CORD_str(x,0,"9abcdefghijx") != CORD_NOT_FOUND)
|
||||
ABORT("CORD_str failed 3");
|
||||
if (CORD_str(x,0,"9>") != CORD_NOT_FOUND) ABORT("CORD_str failed 4");
|
||||
if (remove(FNAME1) != 0) {
|
||||
/* On some systems, e.g. OS2, this may fail if f1 is still open. */
|
||||
if ((fclose(f1a) == EOF) & (fclose(f1b) == EOF))
|
||||
ABORT("fclose(f1) failed");
|
||||
if (remove(FNAME1) != 0) ABORT("remove 1 failed");
|
||||
}
|
||||
if (remove(FNAME2) != 0) {
|
||||
if (fclose(f2) == EOF) ABORT("fclose(f2) failed");
|
||||
if (remove(FNAME2) != 0) ABORT("remove 2 failed");
|
||||
}
|
||||
}
|
||||
|
||||
void test_printf()
|
||||
{
|
||||
CORD result;
|
||||
char result2[200];
|
||||
long l;
|
||||
short s;
|
||||
CORD x;
|
||||
|
||||
if (CORD_sprintf(&result, "%7.2f%ln", 3.14159F, &l) != 7)
|
||||
ABORT("CORD_sprintf failed 1");
|
||||
if (CORD_cmp(result, " 3.14") != 0)ABORT("CORD_sprintf goofed 1");
|
||||
if (l != 7) ABORT("CORD_sprintf goofed 2");
|
||||
if (CORD_sprintf(&result, "%-7.2s%hn%c%s", "abcd", &s, 'x', "yz") != 10)
|
||||
ABORT("CORD_sprintf failed 2");
|
||||
if (CORD_cmp(result, "ab xyz") != 0)ABORT("CORD_sprintf goofed 3");
|
||||
if (s != 7) ABORT("CORD_sprintf goofed 4");
|
||||
x = "abcdefghij";
|
||||
x = CORD_cat(x,x);
|
||||
x = CORD_cat(x,x);
|
||||
x = CORD_cat(x,x);
|
||||
if (CORD_sprintf(&result, "->%-120.78r!\n", x) != 124)
|
||||
ABORT("CORD_sprintf failed 3");
|
||||
(void) sprintf(result2, "->%-120.78s!\n", CORD_to_char_star(x));
|
||||
if (CORD_cmp(result, result2) != 0)ABORT("CORD_sprintf goofed 5");
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
# ifdef THINK_C
|
||||
printf("cordtest:\n");
|
||||
# endif
|
||||
GC_INIT();
|
||||
test_basics();
|
||||
test_extras();
|
||||
test_printf();
|
||||
CORD_fprintf(stderr, "SUCCEEDED\n");
|
||||
return(0);
|
||||
}
|
||||
621
src/engine/boehm_gc/cord/cordxtra.c
Normal file
621
src/engine/boehm_gc/cord/cordxtra.c
Normal file
@@ -0,0 +1,621 @@
|
||||
/*
|
||||
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*
|
||||
* Author: Hans-J. Boehm (boehm@parc.xerox.com)
|
||||
*/
|
||||
/*
|
||||
* These are functions on cords that do not need to understand their
|
||||
* implementation. They serve also serve as example client code for
|
||||
* cord_basics.
|
||||
*/
|
||||
/* Boehm, December 8, 1995 1:53 pm PST */
|
||||
# include <stdio.h>
|
||||
# include <string.h>
|
||||
# include <stdlib.h>
|
||||
# include <stdarg.h>
|
||||
# include "cord.h"
|
||||
# include "ec.h"
|
||||
# define I_HIDE_POINTERS /* So we get access to allocation lock. */
|
||||
/* We use this for lazy file reading, */
|
||||
/* so that we remain independent */
|
||||
/* of the threads primitives. */
|
||||
# include "gc.h"
|
||||
|
||||
/* For now we assume that pointer reads and writes are atomic, */
|
||||
/* i.e. another thread always sees the state before or after */
|
||||
/* a write. This might be false on a Motorola M68K with */
|
||||
/* pointers that are not 32-bit aligned. But there probably */
|
||||
/* aren't too many threads packages running on those. */
|
||||
# define ATOMIC_WRITE(x,y) (x) = (y)
|
||||
# define ATOMIC_READ(x) (*(x))
|
||||
|
||||
/* The standard says these are in stdio.h, but they aren't always: */
|
||||
# ifndef SEEK_SET
|
||||
# define SEEK_SET 0
|
||||
# endif
|
||||
# ifndef SEEK_END
|
||||
# define SEEK_END 2
|
||||
# endif
|
||||
|
||||
# define BUFSZ 2048 /* Size of stack allocated buffers when */
|
||||
/* we want large buffers. */
|
||||
|
||||
typedef void (* oom_fn)(void);
|
||||
|
||||
# define OUT_OF_MEMORY { if (CORD_oom_fn != (oom_fn) 0) (*CORD_oom_fn)(); \
|
||||
ABORT("Out of memory\n"); }
|
||||
# define ABORT(msg) { fprintf(stderr, "%s\n", msg); abort(); }
|
||||
|
||||
CORD CORD_cat_char(CORD x, char c)
|
||||
{
|
||||
register char * string;
|
||||
|
||||
if (c == '\0') return(CORD_cat(x, CORD_nul(1)));
|
||||
string = GC_MALLOC_ATOMIC(2);
|
||||
if (string == 0) OUT_OF_MEMORY;
|
||||
string[0] = c;
|
||||
string[1] = '\0';
|
||||
return(CORD_cat_char_star(x, string, 1));
|
||||
}
|
||||
|
||||
CORD CORD_catn(int nargs, ...)
|
||||
{
|
||||
register CORD result = CORD_EMPTY;
|
||||
va_list args;
|
||||
register int i;
|
||||
|
||||
va_start(args, nargs);
|
||||
for (i = 0; i < nargs; i++) {
|
||||
register CORD next = va_arg(args, CORD);
|
||||
result = CORD_cat(result, next);
|
||||
}
|
||||
va_end(args);
|
||||
return(result);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t len;
|
||||
size_t count;
|
||||
char * buf;
|
||||
} CORD_fill_data;
|
||||
|
||||
int CORD_fill_proc(char c, void * client_data)
|
||||
{
|
||||
register CORD_fill_data * d = (CORD_fill_data *)client_data;
|
||||
register size_t count = d -> count;
|
||||
|
||||
(d -> buf)[count] = c;
|
||||
d -> count = ++count;
|
||||
if (count >= d -> len) {
|
||||
return(1);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
int CORD_batched_fill_proc(const char * s, void * client_data)
|
||||
{
|
||||
register CORD_fill_data * d = (CORD_fill_data *)client_data;
|
||||
register size_t count = d -> count;
|
||||
register size_t max = d -> len;
|
||||
register char * buf = d -> buf;
|
||||
register const char * t = s;
|
||||
|
||||
while((buf[count] = *t++) != '\0') {
|
||||
count++;
|
||||
if (count >= max) {
|
||||
d -> count = count;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
d -> count = count;
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Fill buf with len characters starting at i. */
|
||||
/* Assumes len characters are available. */
|
||||
void CORD_fill_buf(CORD x, size_t i, size_t len, char * buf)
|
||||
{
|
||||
CORD_fill_data fd;
|
||||
|
||||
fd.len = len;
|
||||
fd.buf = buf;
|
||||
fd.count = 0;
|
||||
(void)CORD_iter5(x, i, CORD_fill_proc, CORD_batched_fill_proc, &fd);
|
||||
}
|
||||
|
||||
int CORD_cmp(CORD x, CORD y)
|
||||
{
|
||||
CORD_pos xpos;
|
||||
CORD_pos ypos;
|
||||
register size_t avail, yavail;
|
||||
|
||||
if (y == CORD_EMPTY) return(x != CORD_EMPTY);
|
||||
if (x == CORD_EMPTY) return(-1);
|
||||
if (CORD_IS_STRING(y) && CORD_IS_STRING(x)) return(strcmp(x,y));
|
||||
CORD_set_pos(xpos, x, 0);
|
||||
CORD_set_pos(ypos, y, 0);
|
||||
for(;;) {
|
||||
if (!CORD_pos_valid(xpos)) {
|
||||
if (CORD_pos_valid(ypos)) {
|
||||
return(-1);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (!CORD_pos_valid(ypos)) {
|
||||
return(1);
|
||||
}
|
||||
if ((avail = CORD_pos_chars_left(xpos)) <= 0
|
||||
|| (yavail = CORD_pos_chars_left(ypos)) <= 0) {
|
||||
register char xcurrent = CORD_pos_fetch(xpos);
|
||||
register char ycurrent = CORD_pos_fetch(ypos);
|
||||
if (xcurrent != ycurrent) return(xcurrent - ycurrent);
|
||||
CORD_next(xpos);
|
||||
CORD_next(ypos);
|
||||
} else {
|
||||
/* process as many characters as we can */
|
||||
register int result;
|
||||
|
||||
if (avail > yavail) avail = yavail;
|
||||
result = strncmp(CORD_pos_cur_char_addr(xpos),
|
||||
CORD_pos_cur_char_addr(ypos), avail);
|
||||
if (result != 0) return(result);
|
||||
CORD_pos_advance(xpos, avail);
|
||||
CORD_pos_advance(ypos, avail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int CORD_ncmp(CORD x, size_t x_start, CORD y, size_t y_start, size_t len)
|
||||
{
|
||||
CORD_pos xpos;
|
||||
CORD_pos ypos;
|
||||
register size_t count;
|
||||
register long avail, yavail;
|
||||
|
||||
CORD_set_pos(xpos, x, x_start);
|
||||
CORD_set_pos(ypos, y, y_start);
|
||||
for(count = 0; count < len;) {
|
||||
if (!CORD_pos_valid(xpos)) {
|
||||
if (CORD_pos_valid(ypos)) {
|
||||
return(-1);
|
||||
} else {
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
if (!CORD_pos_valid(ypos)) {
|
||||
return(1);
|
||||
}
|
||||
if ((avail = CORD_pos_chars_left(xpos)) <= 0
|
||||
|| (yavail = CORD_pos_chars_left(ypos)) <= 0) {
|
||||
register char xcurrent = CORD_pos_fetch(xpos);
|
||||
register char ycurrent = CORD_pos_fetch(ypos);
|
||||
if (xcurrent != ycurrent) return(xcurrent - ycurrent);
|
||||
CORD_next(xpos);
|
||||
CORD_next(ypos);
|
||||
count++;
|
||||
} else {
|
||||
/* process as many characters as we can */
|
||||
register int result;
|
||||
|
||||
if (avail > yavail) avail = yavail;
|
||||
count += avail;
|
||||
if (count > len) avail -= (count - len);
|
||||
result = strncmp(CORD_pos_cur_char_addr(xpos),
|
||||
CORD_pos_cur_char_addr(ypos), (size_t)avail);
|
||||
if (result != 0) return(result);
|
||||
CORD_pos_advance(xpos, (size_t)avail);
|
||||
CORD_pos_advance(ypos, (size_t)avail);
|
||||
}
|
||||
}
|
||||
return(0);
|
||||
}
|
||||
|
||||
char * CORD_to_char_star(CORD x)
|
||||
{
|
||||
register size_t len = CORD_len(x);
|
||||
char * result = GC_MALLOC_ATOMIC(len + 1);
|
||||
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
CORD_fill_buf(x, 0, len, result);
|
||||
result[len] = '\0';
|
||||
return(result);
|
||||
}
|
||||
|
||||
CORD CORD_from_char_star(const char *s)
|
||||
{
|
||||
char * result;
|
||||
size_t len = strlen(s);
|
||||
|
||||
if (0 == len) return(CORD_EMPTY);
|
||||
result = GC_MALLOC_ATOMIC(len + 1);
|
||||
if (result == 0) OUT_OF_MEMORY;
|
||||
memcpy(result, s, len+1);
|
||||
return(result);
|
||||
}
|
||||
|
||||
const char * CORD_to_const_char_star(CORD x)
|
||||
{
|
||||
if (x == 0) return("");
|
||||
if (CORD_IS_STRING(x)) return((const char *)x);
|
||||
return(CORD_to_char_star(x));
|
||||
}
|
||||
|
||||
char CORD_fetch(CORD x, size_t i)
|
||||
{
|
||||
CORD_pos xpos;
|
||||
|
||||
CORD_set_pos(xpos, x, i);
|
||||
if (!CORD_pos_valid(xpos)) ABORT("bad index?");
|
||||
return(CORD_pos_fetch(xpos));
|
||||
}
|
||||
|
||||
|
||||
int CORD_put_proc(char c, void * client_data)
|
||||
{
|
||||
register FILE * f = (FILE *)client_data;
|
||||
|
||||
return(putc(c, f) == EOF);
|
||||
}
|
||||
|
||||
int CORD_batched_put_proc(const char * s, void * client_data)
|
||||
{
|
||||
register FILE * f = (FILE *)client_data;
|
||||
|
||||
return(fputs(s, f) == EOF);
|
||||
}
|
||||
|
||||
|
||||
int CORD_put(CORD x, FILE * f)
|
||||
{
|
||||
if (CORD_iter5(x, 0, CORD_put_proc, CORD_batched_put_proc, f)) {
|
||||
return(EOF);
|
||||
} else {
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
size_t pos; /* Current position in the cord */
|
||||
char target; /* Character we're looking for */
|
||||
} chr_data;
|
||||
|
||||
int CORD_chr_proc(char c, void * client_data)
|
||||
{
|
||||
register chr_data * d = (chr_data *)client_data;
|
||||
|
||||
if (c == d -> target) return(1);
|
||||
(d -> pos) ++;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int CORD_rchr_proc(char c, void * client_data)
|
||||
{
|
||||
register chr_data * d = (chr_data *)client_data;
|
||||
|
||||
if (c == d -> target) return(1);
|
||||
(d -> pos) --;
|
||||
return(0);
|
||||
}
|
||||
|
||||
int CORD_batched_chr_proc(const char *s, void * client_data)
|
||||
{
|
||||
register chr_data * d = (chr_data *)client_data;
|
||||
register char * occ = strchr(s, d -> target);
|
||||
|
||||
if (occ == 0) {
|
||||
d -> pos += strlen(s);
|
||||
return(0);
|
||||
} else {
|
||||
d -> pos += occ - s;
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CORD_chr(CORD x, size_t i, int c)
|
||||
{
|
||||
chr_data d;
|
||||
|
||||
d.pos = i;
|
||||
d.target = c;
|
||||
if (CORD_iter5(x, i, CORD_chr_proc, CORD_batched_chr_proc, &d)) {
|
||||
return(d.pos);
|
||||
} else {
|
||||
return(CORD_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
size_t CORD_rchr(CORD x, size_t i, int c)
|
||||
{
|
||||
chr_data d;
|
||||
|
||||
d.pos = i;
|
||||
d.target = c;
|
||||
if (CORD_riter4(x, i, CORD_rchr_proc, &d)) {
|
||||
return(d.pos);
|
||||
} else {
|
||||
return(CORD_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
/* Find the first occurrence of s in x at position start or later. */
|
||||
/* This uses an asymptotically poor algorithm, which should typically */
|
||||
/* perform acceptably. We compare the first few characters directly, */
|
||||
/* and call CORD_ncmp whenever there is a partial match. */
|
||||
/* This has the advantage that we allocate very little, or not at all. */
|
||||
/* It's very fast if there are few close misses. */
|
||||
size_t CORD_str(CORD x, size_t start, CORD s)
|
||||
{
|
||||
CORD_pos xpos;
|
||||
size_t xlen = CORD_len(x);
|
||||
size_t slen;
|
||||
register size_t start_len;
|
||||
const char * s_start;
|
||||
unsigned long s_buf = 0; /* The first few characters of s */
|
||||
unsigned long x_buf = 0; /* Start of candidate substring. */
|
||||
/* Initialized only to make compilers */
|
||||
/* happy. */
|
||||
unsigned long mask = 0;
|
||||
register size_t i;
|
||||
register size_t match_pos;
|
||||
|
||||
if (s == CORD_EMPTY) return(start);
|
||||
if (CORD_IS_STRING(s)) {
|
||||
s_start = s;
|
||||
slen = strlen(s);
|
||||
} else {
|
||||
s_start = CORD_to_char_star(CORD_substr(s, 0, sizeof(unsigned long)));
|
||||
slen = CORD_len(s);
|
||||
}
|
||||
if (xlen < start || xlen - start < slen) return(CORD_NOT_FOUND);
|
||||
start_len = slen;
|
||||
if (start_len > sizeof(unsigned long)) start_len = sizeof(unsigned long);
|
||||
CORD_set_pos(xpos, x, start);
|
||||
for (i = 0; i < start_len; i++) {
|
||||
mask <<= 8;
|
||||
mask |= 0xff;
|
||||
s_buf <<= 8;
|
||||
s_buf |= (unsigned char)s_start[i];
|
||||
x_buf <<= 8;
|
||||
x_buf |= (unsigned char)CORD_pos_fetch(xpos);
|
||||
CORD_next(xpos);
|
||||
}
|
||||
for (match_pos = start; ; match_pos++) {
|
||||
if ((x_buf & mask) == s_buf) {
|
||||
if (slen == start_len ||
|
||||
CORD_ncmp(x, match_pos + start_len,
|
||||
s, start_len, slen - start_len) == 0) {
|
||||
return(match_pos);
|
||||
}
|
||||
}
|
||||
if ( match_pos == xlen - slen ) {
|
||||
return(CORD_NOT_FOUND);
|
||||
}
|
||||
x_buf <<= 8;
|
||||
x_buf |= (unsigned char)CORD_pos_fetch(xpos);
|
||||
CORD_next(xpos);
|
||||
}
|
||||
}
|
||||
|
||||
void CORD_ec_flush_buf(CORD_ec x)
|
||||
{
|
||||
register size_t len = x[0].ec_bufptr - x[0].ec_buf;
|
||||
char * s;
|
||||
|
||||
if (len == 0) return;
|
||||
s = GC_MALLOC_ATOMIC(len+1);
|
||||
memcpy(s, x[0].ec_buf, len);
|
||||
s[len] = '\0';
|
||||
x[0].ec_cord = CORD_cat_char_star(x[0].ec_cord, s, len);
|
||||
x[0].ec_bufptr = x[0].ec_buf;
|
||||
}
|
||||
|
||||
void CORD_ec_append_cord(CORD_ec x, CORD s)
|
||||
{
|
||||
CORD_ec_flush_buf(x);
|
||||
x[0].ec_cord = CORD_cat(x[0].ec_cord, s);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
char CORD_nul_func(size_t i, void * client_data)
|
||||
{
|
||||
return((char)(unsigned long)client_data);
|
||||
}
|
||||
|
||||
|
||||
CORD CORD_chars(char c, size_t i)
|
||||
{
|
||||
return(CORD_from_fn(CORD_nul_func, (void *)(unsigned long)c, i));
|
||||
}
|
||||
|
||||
CORD CORD_from_file_eager(FILE * f)
|
||||
{
|
||||
register int c;
|
||||
CORD_ec ecord;
|
||||
|
||||
CORD_ec_init(ecord);
|
||||
for(;;) {
|
||||
c = getc(f);
|
||||
if (c == 0) {
|
||||
/* Append the right number of NULs */
|
||||
/* Note that any string of NULs is rpresented in 4 words, */
|
||||
/* independent of its length. */
|
||||
register size_t count = 1;
|
||||
|
||||
CORD_ec_flush_buf(ecord);
|
||||
while ((c = getc(f)) == 0) count++;
|
||||
ecord[0].ec_cord = CORD_cat(ecord[0].ec_cord, CORD_nul(count));
|
||||
}
|
||||
if (c == EOF) break;
|
||||
CORD_ec_append(ecord, c);
|
||||
}
|
||||
(void) fclose(f);
|
||||
return(CORD_balance(CORD_ec_to_cord(ecord)));
|
||||
}
|
||||
|
||||
/* The state maintained for a lazily read file consists primarily */
|
||||
/* of a large direct-mapped cache of previously read values. */
|
||||
/* We could rely more on stdio buffering. That would have 2 */
|
||||
/* disadvantages: */
|
||||
/* 1) Empirically, not all fseek implementations preserve the */
|
||||
/* buffer whenever they could. */
|
||||
/* 2) It would fail if 2 different sections of a long cord */
|
||||
/* were being read alternately. */
|
||||
/* We do use the stdio buffer for read ahead. */
|
||||
/* To guarantee thread safety in the presence of atomic pointer */
|
||||
/* writes, cache lines are always replaced, and never modified in */
|
||||
/* place. */
|
||||
|
||||
# define LOG_CACHE_SZ 14
|
||||
# define CACHE_SZ (1 << LOG_CACHE_SZ)
|
||||
# define LOG_LINE_SZ 9
|
||||
# define LINE_SZ (1 << LOG_LINE_SZ)
|
||||
|
||||
typedef struct {
|
||||
size_t tag;
|
||||
char data[LINE_SZ];
|
||||
/* data[i%LINE_SZ] = ith char in file if tag = i/LINE_SZ */
|
||||
} cache_line;
|
||||
|
||||
typedef struct {
|
||||
FILE * lf_file;
|
||||
size_t lf_current; /* Current file pointer value */
|
||||
cache_line * volatile lf_cache[CACHE_SZ/LINE_SZ];
|
||||
} lf_state;
|
||||
|
||||
# define MOD_CACHE_SZ(n) ((n) & (CACHE_SZ - 1))
|
||||
# define DIV_CACHE_SZ(n) ((n) >> LOG_CACHE_SZ)
|
||||
# define MOD_LINE_SZ(n) ((n) & (LINE_SZ - 1))
|
||||
# define DIV_LINE_SZ(n) ((n) >> LOG_LINE_SZ)
|
||||
# define LINE_START(n) ((n) & ~(LINE_SZ - 1))
|
||||
|
||||
typedef struct {
|
||||
lf_state * state;
|
||||
size_t file_pos; /* Position of needed character. */
|
||||
cache_line * new_cache;
|
||||
} refill_data;
|
||||
|
||||
/* Executed with allocation lock. */
|
||||
static char refill_cache(client_data)
|
||||
refill_data * client_data;
|
||||
{
|
||||
register lf_state * state = client_data -> state;
|
||||
register size_t file_pos = client_data -> file_pos;
|
||||
FILE *f = state -> lf_file;
|
||||
size_t line_start = LINE_START(file_pos);
|
||||
size_t line_no = DIV_LINE_SZ(MOD_CACHE_SZ(file_pos));
|
||||
cache_line * new_cache = client_data -> new_cache;
|
||||
|
||||
if (line_start != state -> lf_current
|
||||
&& fseek(f, line_start, SEEK_SET) != 0) {
|
||||
ABORT("fseek failed");
|
||||
}
|
||||
if (fread(new_cache -> data, sizeof(char), LINE_SZ, f)
|
||||
<= file_pos - line_start) {
|
||||
ABORT("fread failed");
|
||||
}
|
||||
new_cache -> tag = DIV_LINE_SZ(file_pos);
|
||||
/* Store barrier goes here. */
|
||||
ATOMIC_WRITE(state -> lf_cache[line_no], new_cache);
|
||||
state -> lf_current = line_start + LINE_SZ;
|
||||
return(new_cache->data[MOD_LINE_SZ(file_pos)]);
|
||||
}
|
||||
|
||||
char CORD_lf_func(size_t i, void * client_data)
|
||||
{
|
||||
register lf_state * state = (lf_state *)client_data;
|
||||
register cache_line * volatile * cl_addr =
|
||||
&(state -> lf_cache[DIV_LINE_SZ(MOD_CACHE_SZ(i))]);
|
||||
register cache_line * cl = (cache_line *)ATOMIC_READ(cl_addr);
|
||||
|
||||
if (cl == 0 || cl -> tag != DIV_LINE_SZ(i)) {
|
||||
/* Cache miss */
|
||||
refill_data rd;
|
||||
|
||||
rd.state = state;
|
||||
rd.file_pos = i;
|
||||
rd.new_cache = GC_NEW_ATOMIC(cache_line);
|
||||
if (rd.new_cache == 0) OUT_OF_MEMORY;
|
||||
return((char)(GC_word)
|
||||
GC_call_with_alloc_lock((GC_fn_type) refill_cache, &rd));
|
||||
}
|
||||
return(cl -> data[MOD_LINE_SZ(i)]);
|
||||
}
|
||||
|
||||
/*ARGSUSED*/
|
||||
void CORD_lf_close_proc(void * obj, void * client_data)
|
||||
{
|
||||
if (fclose(((lf_state *)obj) -> lf_file) != 0) {
|
||||
ABORT("CORD_lf_close_proc: fclose failed");
|
||||
}
|
||||
}
|
||||
|
||||
CORD CORD_from_file_lazy_inner(FILE * f, size_t len)
|
||||
{
|
||||
register lf_state * state = GC_NEW(lf_state);
|
||||
register int i;
|
||||
|
||||
if (state == 0) OUT_OF_MEMORY;
|
||||
if (len != 0) {
|
||||
/* Dummy read to force buffer allocation. */
|
||||
/* This greatly increases the probability */
|
||||
/* of avoiding deadlock if buffer allocation */
|
||||
/* is redirected to GC_malloc and the */
|
||||
/* world is multithreaded. */
|
||||
char buf[1];
|
||||
|
||||
(void) fread(buf, 1, 1, f);
|
||||
rewind(f);
|
||||
}
|
||||
state -> lf_file = f;
|
||||
for (i = 0; i < CACHE_SZ/LINE_SZ; i++) {
|
||||
state -> lf_cache[i] = 0;
|
||||
}
|
||||
state -> lf_current = 0;
|
||||
GC_REGISTER_FINALIZER(state, CORD_lf_close_proc, 0, 0, 0);
|
||||
return(CORD_from_fn(CORD_lf_func, state, len));
|
||||
}
|
||||
|
||||
CORD CORD_from_file_lazy(FILE * f)
|
||||
{
|
||||
register long len;
|
||||
|
||||
if (fseek(f, 0l, SEEK_END) != 0) {
|
||||
ABORT("Bad fd argument - fseek failed");
|
||||
}
|
||||
if ((len = ftell(f)) < 0) {
|
||||
ABORT("Bad fd argument - ftell failed");
|
||||
}
|
||||
rewind(f);
|
||||
return(CORD_from_file_lazy_inner(f, (size_t)len));
|
||||
}
|
||||
|
||||
# define LAZY_THRESHOLD (128*1024 + 1)
|
||||
|
||||
CORD CORD_from_file(FILE * f)
|
||||
{
|
||||
register long len;
|
||||
|
||||
if (fseek(f, 0l, SEEK_END) != 0) {
|
||||
ABORT("Bad fd argument - fseek failed");
|
||||
}
|
||||
if ((len = ftell(f)) < 0) {
|
||||
ABORT("Bad fd argument - ftell failed");
|
||||
}
|
||||
rewind(f);
|
||||
if (len < LAZY_THRESHOLD) {
|
||||
return(CORD_from_file_eager(f));
|
||||
} else {
|
||||
return(CORD_from_file_lazy_inner(f, (size_t)len));
|
||||
}
|
||||
}
|
||||
603
src/engine/boehm_gc/cord/de.c
Normal file
603
src/engine/boehm_gc/cord/de.c
Normal file
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*
|
||||
* Author: Hans-J. Boehm (boehm@parc.xerox.com)
|
||||
*/
|
||||
/*
|
||||
* A really simple-minded text editor based on cords.
|
||||
* Things it does right:
|
||||
* No size bounds.
|
||||
* Inbounded undo.
|
||||
* Shouldn't crash no matter what file you invoke it on (e.g. /vmunix)
|
||||
* (Make sure /vmunix is not writable before you try this.)
|
||||
* Scrolls horizontally.
|
||||
* Things it does wrong:
|
||||
* It doesn't handle tabs reasonably (use "expand" first).
|
||||
* The command set is MUCH too small.
|
||||
* The redisplay algorithm doesn't let curses do the scrolling.
|
||||
* The rule for moving the window over the file is suboptimal.
|
||||
*/
|
||||
/* Boehm, February 6, 1995 12:27 pm PST */
|
||||
|
||||
/* Boehm, May 19, 1994 2:20 pm PDT */
|
||||
#include <stdio.h>
|
||||
#include "gc.h"
|
||||
#include "cord.h"
|
||||
|
||||
#ifdef THINK_C
|
||||
#define MACINTOSH
|
||||
#include <ctype.h>
|
||||
#endif
|
||||
|
||||
#if defined(__BORLANDC__) && !defined(WIN32)
|
||||
/* If this is DOS or win16, we'll fail anyway. */
|
||||
/* Might as well assume win32. */
|
||||
# define WIN32
|
||||
#endif
|
||||
|
||||
#if defined(WIN32)
|
||||
# include <windows.h>
|
||||
# include "de_win.h"
|
||||
#elif defined(MACINTOSH)
|
||||
# include <console.h>
|
||||
/* curses emulation. */
|
||||
# define initscr()
|
||||
# define endwin()
|
||||
# define nonl()
|
||||
# define noecho() csetmode(C_NOECHO, stdout)
|
||||
# define cbreak() csetmode(C_CBREAK, stdout)
|
||||
# define refresh()
|
||||
# define addch(c) putchar(c)
|
||||
# define standout() cinverse(1, stdout)
|
||||
# define standend() cinverse(0, stdout)
|
||||
# define move(line,col) cgotoxy(col + 1, line + 1, stdout)
|
||||
# define clrtoeol() ccleol(stdout)
|
||||
# define de_error(s) { fprintf(stderr, s); getchar(); }
|
||||
# define LINES 25
|
||||
# define COLS 80
|
||||
#else
|
||||
# include <curses.h>
|
||||
# define de_error(s) { fprintf(stderr, s); sleep(2); }
|
||||
#endif
|
||||
#include "de_cmds.h"
|
||||
|
||||
/* List of line number to position mappings, in descending order. */
|
||||
/* There may be holes. */
|
||||
typedef struct LineMapRep {
|
||||
int line;
|
||||
size_t pos;
|
||||
struct LineMapRep * previous;
|
||||
} * line_map;
|
||||
|
||||
/* List of file versions, one per edit operation */
|
||||
typedef struct HistoryRep {
|
||||
CORD file_contents;
|
||||
struct HistoryRep * previous;
|
||||
line_map map; /* Invalid for first record "now" */
|
||||
} * history;
|
||||
|
||||
history now = 0;
|
||||
CORD current; /* == now -> file_contents. */
|
||||
size_t current_len; /* Current file length. */
|
||||
line_map current_map = 0; /* Current line no. to pos. map */
|
||||
size_t current_map_size = 0; /* Number of current_map entries. */
|
||||
/* Not always accurate, but reset */
|
||||
/* by prune_map. */
|
||||
# define MAX_MAP_SIZE 3000
|
||||
|
||||
/* Current display position */
|
||||
int dis_line = 0;
|
||||
int dis_col = 0;
|
||||
|
||||
# define ALL -1
|
||||
# define NONE - 2
|
||||
int need_redisplay = 0; /* Line that needs to be redisplayed. */
|
||||
|
||||
|
||||
/* Current cursor position. Always within file. */
|
||||
int line = 0;
|
||||
int col = 0;
|
||||
size_t file_pos = 0; /* Character position corresponding to cursor. */
|
||||
|
||||
/* Invalidate line map for lines > i */
|
||||
void invalidate_map(int i)
|
||||
{
|
||||
while(current_map -> line > i) {
|
||||
current_map = current_map -> previous;
|
||||
current_map_size--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Reduce the number of map entries to save space for huge files. */
|
||||
/* This also affects maps in histories. */
|
||||
void prune_map()
|
||||
{
|
||||
line_map map = current_map;
|
||||
int start_line = map -> line;
|
||||
|
||||
current_map_size = 0;
|
||||
for(; map != 0; map = map -> previous) {
|
||||
current_map_size++;
|
||||
if (map -> line < start_line - LINES && map -> previous != 0) {
|
||||
map -> previous = map -> previous -> previous;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Add mapping entry */
|
||||
void add_map(int line, size_t pos)
|
||||
{
|
||||
line_map new_map = GC_NEW(struct LineMapRep);
|
||||
|
||||
if (current_map_size >= MAX_MAP_SIZE) prune_map();
|
||||
new_map -> line = line;
|
||||
new_map -> pos = pos;
|
||||
new_map -> previous = current_map;
|
||||
current_map = new_map;
|
||||
current_map_size++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Return position of column *c of ith line in */
|
||||
/* current file. Adjust *c to be within the line.*/
|
||||
/* A 0 pointer is taken as 0 column. */
|
||||
/* Returns CORD_NOT_FOUND if i is too big. */
|
||||
/* Assumes i > dis_line. */
|
||||
size_t line_pos(int i, int *c)
|
||||
{
|
||||
int j;
|
||||
size_t cur;
|
||||
size_t next;
|
||||
line_map map = current_map;
|
||||
|
||||
while (map -> line > i) map = map -> previous;
|
||||
if (map -> line < i - 2) /* rebuild */ invalidate_map(i);
|
||||
for (j = map -> line, cur = map -> pos; j < i;) {
|
||||
cur = CORD_chr(current, cur, '\n');
|
||||
if (cur == current_len-1) return(CORD_NOT_FOUND);
|
||||
cur++;
|
||||
if (++j > current_map -> line) add_map(j, cur);
|
||||
}
|
||||
if (c != 0) {
|
||||
next = CORD_chr(current, cur, '\n');
|
||||
if (next == CORD_NOT_FOUND) next = current_len - 1;
|
||||
if (next < cur + *c) {
|
||||
*c = next - cur;
|
||||
}
|
||||
cur += *c;
|
||||
}
|
||||
return(cur);
|
||||
}
|
||||
|
||||
void add_hist(CORD s)
|
||||
{
|
||||
history new_file = GC_NEW(struct HistoryRep);
|
||||
|
||||
new_file -> file_contents = current = s;
|
||||
current_len = CORD_len(s);
|
||||
new_file -> previous = now;
|
||||
if (now != 0) now -> map = current_map;
|
||||
now = new_file;
|
||||
}
|
||||
|
||||
void del_hist(void)
|
||||
{
|
||||
now = now -> previous;
|
||||
current = now -> file_contents;
|
||||
current_map = now -> map;
|
||||
current_len = CORD_len(current);
|
||||
}
|
||||
|
||||
/* Current screen_contents; a dynamically allocated array of CORDs */
|
||||
CORD * screen = 0;
|
||||
int screen_size = 0;
|
||||
|
||||
# ifndef WIN32
|
||||
/* Replace a line in the curses stdscr. All control characters are */
|
||||
/* displayed as upper case characters in standout mode. This isn't */
|
||||
/* terribly appropriate for tabs. */
|
||||
void replace_line(int i, CORD s)
|
||||
{
|
||||
register int c;
|
||||
CORD_pos p;
|
||||
size_t len = CORD_len(s);
|
||||
|
||||
if (screen == 0 || LINES > screen_size) {
|
||||
screen_size = LINES;
|
||||
screen = (CORD *)GC_MALLOC(screen_size * sizeof(CORD));
|
||||
}
|
||||
# if !defined(MACINTOSH)
|
||||
/* A gross workaround for an apparent curses bug: */
|
||||
if (i == LINES-1 && len == COLS) {
|
||||
s = CORD_substr(s, 0, CORD_len(s) - 1);
|
||||
}
|
||||
# endif
|
||||
if (CORD_cmp(screen[i], s) != 0) {
|
||||
move(i, 0); clrtoeol(); move(i,0);
|
||||
|
||||
CORD_FOR (p, s) {
|
||||
c = CORD_pos_fetch(p) & 0x7f;
|
||||
if (iscntrl(c)) {
|
||||
standout(); addch(c + 0x40); standend();
|
||||
} else {
|
||||
addch(c);
|
||||
}
|
||||
}
|
||||
screen[i] = s;
|
||||
}
|
||||
}
|
||||
#else
|
||||
# define replace_line(i,s) invalidate_line(i)
|
||||
#endif
|
||||
|
||||
/* Return up to COLS characters of the line of s starting at pos, */
|
||||
/* returning only characters after the given column. */
|
||||
CORD retrieve_line(CORD s, size_t pos, unsigned column)
|
||||
{
|
||||
CORD candidate = CORD_substr(s, pos, column + COLS);
|
||||
/* avoids scanning very long lines */
|
||||
int eol = CORD_chr(candidate, 0, '\n');
|
||||
int len;
|
||||
|
||||
if (eol == CORD_NOT_FOUND) eol = CORD_len(candidate);
|
||||
len = (int)eol - (int)column;
|
||||
if (len < 0) len = 0;
|
||||
return(CORD_substr(s, pos + column, len));
|
||||
}
|
||||
|
||||
# ifdef WIN32
|
||||
# define refresh();
|
||||
|
||||
CORD retrieve_screen_line(int i)
|
||||
{
|
||||
register size_t pos;
|
||||
|
||||
invalidate_map(dis_line + LINES); /* Prune search */
|
||||
pos = line_pos(dis_line + i, 0);
|
||||
if (pos == CORD_NOT_FOUND) return(CORD_EMPTY);
|
||||
return(retrieve_line(current, pos, dis_col));
|
||||
}
|
||||
# endif
|
||||
|
||||
/* Display the visible section of the current file */
|
||||
void redisplay(void)
|
||||
{
|
||||
register int i;
|
||||
|
||||
invalidate_map(dis_line + LINES); /* Prune search */
|
||||
for (i = 0; i < LINES; i++) {
|
||||
if (need_redisplay == ALL || need_redisplay == i) {
|
||||
register size_t pos = line_pos(dis_line + i, 0);
|
||||
|
||||
if (pos == CORD_NOT_FOUND) break;
|
||||
replace_line(i, retrieve_line(current, pos, dis_col));
|
||||
if (need_redisplay == i) goto done;
|
||||
}
|
||||
}
|
||||
for (; i < LINES; i++) replace_line(i, CORD_EMPTY);
|
||||
done:
|
||||
refresh();
|
||||
need_redisplay = NONE;
|
||||
}
|
||||
|
||||
int dis_granularity;
|
||||
|
||||
/* Update dis_line, dis_col, and dis_pos to make cursor visible. */
|
||||
/* Assumes line, col, dis_line, dis_pos are in bounds. */
|
||||
void normalize_display()
|
||||
{
|
||||
int old_line = dis_line;
|
||||
int old_col = dis_col;
|
||||
|
||||
dis_granularity = 1;
|
||||
if (LINES > 15 && COLS > 15) dis_granularity = 2;
|
||||
while (dis_line > line) dis_line -= dis_granularity;
|
||||
while (dis_col > col) dis_col -= dis_granularity;
|
||||
while (line >= dis_line + LINES) dis_line += dis_granularity;
|
||||
while (col >= dis_col + COLS) dis_col += dis_granularity;
|
||||
if (old_line != dis_line || old_col != dis_col) {
|
||||
need_redisplay = ALL;
|
||||
}
|
||||
}
|
||||
|
||||
# if defined(WIN32)
|
||||
# elif defined(MACINTOSH)
|
||||
# define move_cursor(x,y) cgotoxy(x + 1, y + 1, stdout)
|
||||
# else
|
||||
# define move_cursor(x,y) move(y,x)
|
||||
# endif
|
||||
|
||||
/* Adjust display so that cursor is visible; move cursor into position */
|
||||
/* Update screen if necessary. */
|
||||
void fix_cursor(void)
|
||||
{
|
||||
normalize_display();
|
||||
if (need_redisplay != NONE) redisplay();
|
||||
move_cursor(col - dis_col, line - dis_line);
|
||||
refresh();
|
||||
# ifndef WIN32
|
||||
fflush(stdout);
|
||||
# endif
|
||||
}
|
||||
|
||||
/* Make sure line, col, and dis_pos are somewhere inside file. */
|
||||
/* Recompute file_pos. Assumes dis_pos is accurate or past eof */
|
||||
void fix_pos()
|
||||
{
|
||||
int my_col = col;
|
||||
|
||||
if ((size_t)line > current_len) line = current_len;
|
||||
file_pos = line_pos(line, &my_col);
|
||||
if (file_pos == CORD_NOT_FOUND) {
|
||||
for (line = current_map -> line, file_pos = current_map -> pos;
|
||||
file_pos < current_len;
|
||||
line++, file_pos = CORD_chr(current, file_pos, '\n') + 1);
|
||||
line--;
|
||||
file_pos = line_pos(line, &col);
|
||||
} else {
|
||||
col = my_col;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(WIN32)
|
||||
# define beep() Beep(1000 /* Hz */, 300 /* msecs */)
|
||||
#elif defined(MACINTOSH)
|
||||
# define beep() SysBeep(1)
|
||||
#else
|
||||
/*
|
||||
* beep() is part of some curses packages and not others.
|
||||
* We try to match the type of the builtin one, if any.
|
||||
*/
|
||||
#ifdef __STDC__
|
||||
int beep(void)
|
||||
#else
|
||||
int beep()
|
||||
#endif
|
||||
{
|
||||
putc('\007', stderr);
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
# define NO_PREFIX -1
|
||||
# define BARE_PREFIX -2
|
||||
int repeat_count = NO_PREFIX; /* Current command prefix. */
|
||||
|
||||
int locate_mode = 0; /* Currently between 2 ^Ls */
|
||||
CORD locate_string = CORD_EMPTY; /* Current search string. */
|
||||
|
||||
char * arg_file_name;
|
||||
|
||||
#ifdef WIN32
|
||||
/* Change the current position to whatever is currently displayed at */
|
||||
/* the given SCREEN coordinates. */
|
||||
void set_position(int c, int l)
|
||||
{
|
||||
line = l + dis_line;
|
||||
col = c + dis_col;
|
||||
fix_pos();
|
||||
move_cursor(col - dis_col, line - dis_line);
|
||||
}
|
||||
#endif /* WIN32 */
|
||||
|
||||
/* Perform the command associated with character c. C may be an */
|
||||
/* integer > 256 denoting a windows command, one of the above control */
|
||||
/* characters, or another ASCII character to be used as either a */
|
||||
/* character to be inserted, a repeat count, or a search string, */
|
||||
/* depending on the current state. */
|
||||
void do_command(int c)
|
||||
{
|
||||
int i;
|
||||
int need_fix_pos;
|
||||
FILE * out;
|
||||
|
||||
if ( c == '\r') c = '\n';
|
||||
if (locate_mode) {
|
||||
size_t new_pos;
|
||||
|
||||
if (c == LOCATE) {
|
||||
locate_mode = 0;
|
||||
locate_string = CORD_EMPTY;
|
||||
return;
|
||||
}
|
||||
locate_string = CORD_cat_char(locate_string, (char)c);
|
||||
new_pos = CORD_str(current, file_pos - CORD_len(locate_string) + 1,
|
||||
locate_string);
|
||||
if (new_pos != CORD_NOT_FOUND) {
|
||||
need_redisplay = ALL;
|
||||
new_pos += CORD_len(locate_string);
|
||||
for (;;) {
|
||||
file_pos = line_pos(line + 1, 0);
|
||||
if (file_pos > new_pos) break;
|
||||
line++;
|
||||
}
|
||||
col = new_pos - line_pos(line, 0);
|
||||
file_pos = new_pos;
|
||||
fix_cursor();
|
||||
} else {
|
||||
locate_string = CORD_substr(locate_string, 0,
|
||||
CORD_len(locate_string) - 1);
|
||||
beep();
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (c == REPEAT) {
|
||||
repeat_count = BARE_PREFIX; return;
|
||||
} else if (c < 0x100 && isdigit(c)){
|
||||
if (repeat_count == BARE_PREFIX) {
|
||||
repeat_count = c - '0'; return;
|
||||
} else if (repeat_count != NO_PREFIX) {
|
||||
repeat_count = 10 * repeat_count + c - '0'; return;
|
||||
}
|
||||
}
|
||||
if (repeat_count == NO_PREFIX) repeat_count = 1;
|
||||
if (repeat_count == BARE_PREFIX && (c == UP || c == DOWN)) {
|
||||
repeat_count = LINES - dis_granularity;
|
||||
}
|
||||
if (repeat_count == BARE_PREFIX) repeat_count = 8;
|
||||
need_fix_pos = 0;
|
||||
for (i = 0; i < repeat_count; i++) {
|
||||
switch(c) {
|
||||
case LOCATE:
|
||||
locate_mode = 1;
|
||||
break;
|
||||
case TOP:
|
||||
line = col = file_pos = 0;
|
||||
break;
|
||||
case UP:
|
||||
if (line != 0) {
|
||||
line--;
|
||||
need_fix_pos = 1;
|
||||
}
|
||||
break;
|
||||
case DOWN:
|
||||
line++;
|
||||
need_fix_pos = 1;
|
||||
break;
|
||||
case LEFT:
|
||||
if (col != 0) {
|
||||
col--; file_pos--;
|
||||
}
|
||||
break;
|
||||
case RIGHT:
|
||||
if (CORD_fetch(current, file_pos) == '\n') break;
|
||||
col++; file_pos++;
|
||||
break;
|
||||
case UNDO:
|
||||
del_hist();
|
||||
need_redisplay = ALL; need_fix_pos = 1;
|
||||
break;
|
||||
case BS:
|
||||
if (col == 0) {
|
||||
beep();
|
||||
break;
|
||||
}
|
||||
col--; file_pos--;
|
||||
/* fall through: */
|
||||
case DEL:
|
||||
if (file_pos == current_len-1) break;
|
||||
/* Can't delete trailing newline */
|
||||
if (CORD_fetch(current, file_pos) == '\n') {
|
||||
need_redisplay = ALL; need_fix_pos = 1;
|
||||
} else {
|
||||
need_redisplay = line - dis_line;
|
||||
}
|
||||
add_hist(CORD_cat(
|
||||
CORD_substr(current, 0, file_pos),
|
||||
CORD_substr(current, file_pos+1, current_len)));
|
||||
invalidate_map(line);
|
||||
break;
|
||||
case WRITE:
|
||||
{
|
||||
CORD name = CORD_cat(CORD_from_char_star(arg_file_name),
|
||||
".new");
|
||||
|
||||
if ((out = fopen(CORD_to_const_char_star(name), "wb")) == NULL
|
||||
|| CORD_put(current, out) == EOF) {
|
||||
de_error("Write failed\n");
|
||||
need_redisplay = ALL;
|
||||
} else {
|
||||
fclose(out);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
{
|
||||
CORD left_part = CORD_substr(current, 0, file_pos);
|
||||
CORD right_part = CORD_substr(current, file_pos, current_len);
|
||||
|
||||
add_hist(CORD_cat(CORD_cat_char(left_part, (char)c),
|
||||
right_part));
|
||||
invalidate_map(line);
|
||||
if (c == '\n') {
|
||||
col = 0; line++; file_pos++;
|
||||
need_redisplay = ALL;
|
||||
} else {
|
||||
col++; file_pos++;
|
||||
need_redisplay = line - dis_line;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (need_fix_pos) fix_pos();
|
||||
fix_cursor();
|
||||
repeat_count = NO_PREFIX;
|
||||
}
|
||||
|
||||
/* OS independent initialization */
|
||||
|
||||
void generic_init(void)
|
||||
{
|
||||
FILE * f;
|
||||
CORD initial;
|
||||
|
||||
if ((f = fopen(arg_file_name, "rb")) == NULL) {
|
||||
initial = "\n";
|
||||
} else {
|
||||
initial = CORD_from_file(f);
|
||||
if (initial == CORD_EMPTY
|
||||
|| CORD_fetch(initial, CORD_len(initial)-1) != '\n') {
|
||||
initial = CORD_cat(initial, "\n");
|
||||
}
|
||||
}
|
||||
add_map(0,0);
|
||||
add_hist(initial);
|
||||
now -> map = current_map;
|
||||
now -> previous = now; /* Can't back up further: beginning of the world */
|
||||
need_redisplay = ALL;
|
||||
fix_cursor();
|
||||
}
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
main(argc, argv)
|
||||
int argc;
|
||||
char ** argv;
|
||||
{
|
||||
int c;
|
||||
|
||||
#if defined(MACINTOSH)
|
||||
console_options.title = "\pDumb Editor";
|
||||
cshow(stdout);
|
||||
argc = ccommand(&argv);
|
||||
#endif
|
||||
GC_INIT();
|
||||
|
||||
if (argc != 2) goto usage;
|
||||
arg_file_name = argv[1];
|
||||
setvbuf(stdout, GC_MALLOC_ATOMIC(8192), _IOFBF, 8192);
|
||||
initscr();
|
||||
noecho(); nonl(); cbreak();
|
||||
generic_init();
|
||||
while ((c = getchar()) != QUIT) {
|
||||
if (c == EOF) break;
|
||||
do_command(c);
|
||||
}
|
||||
done:
|
||||
move(LINES-1, 0);
|
||||
clrtoeol();
|
||||
refresh();
|
||||
nl();
|
||||
echo();
|
||||
endwin();
|
||||
exit(0);
|
||||
usage:
|
||||
fprintf(stderr, "Usage: %s file\n", argv[0]);
|
||||
fprintf(stderr, "Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n");
|
||||
fprintf(stderr, "Undo: ^U Write to <file>.new: ^W");
|
||||
fprintf(stderr, "Quit:^D Repeat count: ^R[n]\n");
|
||||
fprintf(stderr, "Top: ^T Locate (search, find): ^L text ^L\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
#endif /* !WIN32 */
|
||||
33
src/engine/boehm_gc/cord/de_cmds.h
Normal file
33
src/engine/boehm_gc/cord/de_cmds.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
/* Boehm, May 19, 1994 2:24 pm PDT */
|
||||
|
||||
#ifndef DE_CMDS_H
|
||||
|
||||
# define DE_CMDS_H
|
||||
|
||||
# define UP 16 /* ^P */
|
||||
# define DOWN 14 /* ^N */
|
||||
# define LEFT 2 /* ^B */
|
||||
# define RIGHT 6 /* ^F */
|
||||
# define DEL 127 /* ^? */
|
||||
# define BS 8 /* ^H */
|
||||
# define UNDO 21 /* ^U */
|
||||
# define WRITE 23 /* ^W */
|
||||
# define QUIT 4 /* ^D */
|
||||
# define REPEAT 18 /* ^R */
|
||||
# define LOCATE 12 /* ^L */
|
||||
# define TOP 20 /* ^T */
|
||||
|
||||
#endif
|
||||
|
||||
BIN
src/engine/boehm_gc/cord/de_win.ICO
Executable file
BIN
src/engine/boehm_gc/cord/de_win.ICO
Executable file
Binary file not shown.
|
After Width: | Height: | Size: 766 B |
78
src/engine/boehm_gc/cord/de_win.RC
Normal file
78
src/engine/boehm_gc/cord/de_win.RC
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to copy this garbage collector for any purpose,
|
||||
* provided the above notices are retained on all copies.
|
||||
*/
|
||||
/* Boehm, May 13, 1994 9:50 am PDT */
|
||||
|
||||
#include "windows.h"
|
||||
#include "de_cmds.h"
|
||||
#include "de_win.h"
|
||||
|
||||
|
||||
|
||||
ABOUTBOX DIALOG 19, 21, 163, 47
|
||||
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
|
||||
CAPTION "About Demonstration Text Editor"
|
||||
BEGIN
|
||||
ICON "DE", -1, 8, 8, 13, 13, WS_CHILD | WS_VISIBLE
|
||||
LTEXT "Demonstration Text Editor", -1, 44, 8, 118, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
|
||||
LTEXT "Version 4.1", -1, 44, 16, 60, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
|
||||
PUSHBUTTON "OK", IDOK, 118, 27, 24, 14, WS_CHILD | WS_VISIBLE | WS_TABSTOP
|
||||
END
|
||||
|
||||
|
||||
DE MENU
|
||||
BEGIN
|
||||
POPUP "&File"
|
||||
BEGIN
|
||||
MENUITEM "&Save\t^W", IDM_FILESAVE
|
||||
MENUITEM "E&xit\t^D", IDM_FILEEXIT
|
||||
END
|
||||
|
||||
POPUP "&Edit"
|
||||
BEGIN
|
||||
MENUITEM "Page &Down\t^R^N", IDM_EDITPDOWN
|
||||
MENUITEM "Page &Up\t^R^P", IDM_EDITPUP
|
||||
MENUITEM "U&ndo\t^U", IDM_EDITUNDO
|
||||
MENUITEM "&Locate\t^L ... ^L", IDM_EDITLOCATE
|
||||
MENUITEM "D&own\t^N", IDM_EDITDOWN
|
||||
MENUITEM "U&p\t^P", IDM_EDITUP
|
||||
MENUITEM "Le&ft\t^B", IDM_EDITLEFT
|
||||
MENUITEM "&Right\t^F", IDM_EDITRIGHT
|
||||
MENUITEM "Delete &Backward\tBS", IDM_EDITBS
|
||||
MENUITEM "Delete F&orward\tDEL", IDM_EDITDEL
|
||||
MENUITEM "&Top\t^T", IDM_EDITTOP
|
||||
END
|
||||
|
||||
POPUP "&Help"
|
||||
BEGIN
|
||||
MENUITEM "&Contents", IDM_HELPCONTENTS
|
||||
MENUITEM "&About...", IDM_HELPABOUT
|
||||
END
|
||||
|
||||
MENUITEM "Page_&Down", IDM_EDITPDOWN
|
||||
MENUITEM "Page_&Up", IDM_EDITPUP
|
||||
END
|
||||
|
||||
|
||||
DE ACCELERATORS
|
||||
BEGIN
|
||||
"^R", IDM_EDITREPEAT
|
||||
"^N", IDM_EDITDOWN
|
||||
"^P", IDM_EDITUP
|
||||
"^L", IDM_EDITLOCATE
|
||||
"^B", IDM_EDITLEFT
|
||||
"^F", IDM_EDITRIGHT
|
||||
"^T", IDM_EDITTOP
|
||||
VK_DELETE, IDM_EDITDEL, VIRTKEY
|
||||
VK_BACK, IDM_EDITBS, VIRTKEY
|
||||
END
|
||||
|
||||
|
||||
DE ICON cord\de_win.ICO
|
||||
|
||||
370
src/engine/boehm_gc/cord/de_win.c
Normal file
370
src/engine/boehm_gc/cord/de_win.c
Normal file
@@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
/* Boehm, February 6, 1995 12:29 pm PST */
|
||||
|
||||
/*
|
||||
* The MS Windows specific part of de.
|
||||
* This started as the generic Windows application template
|
||||
* made available by Rob Haack (rhaack@polaris.unm.edu), but
|
||||
* significant parts didn't survive to the final version.
|
||||
*
|
||||
* This was written by a nonexpert windows programmer.
|
||||
*/
|
||||
|
||||
|
||||
#include "windows.h"
|
||||
#include "gc.h"
|
||||
#include "cord.h"
|
||||
#include "de_cmds.h"
|
||||
#include "de_win.h"
|
||||
|
||||
int LINES = 0;
|
||||
int COLS = 0;
|
||||
|
||||
char szAppName[] = "DE";
|
||||
char FullAppName[] = "Demonstration Editor";
|
||||
|
||||
HWND hwnd;
|
||||
|
||||
void de_error(char *s)
|
||||
{
|
||||
MessageBox( hwnd, (LPSTR) s,
|
||||
(LPSTR) FullAppName,
|
||||
MB_ICONINFORMATION | MB_OK );
|
||||
InvalidateRect(hwnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
|
||||
LPSTR command_line, int nCmdShow)
|
||||
{
|
||||
MSG msg;
|
||||
WNDCLASS wndclass;
|
||||
HANDLE hAccel;
|
||||
|
||||
# ifdef THREAD_LOCAL_ALLOC
|
||||
GC_INIT(); /* Required if GC is built with THREAD_LOCAL_ALLOC */
|
||||
/* Always safe, but this is used as a GC test. */
|
||||
# endif
|
||||
|
||||
if (!hPrevInstance)
|
||||
{
|
||||
wndclass.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wndclass.lpfnWndProc = WndProc;
|
||||
wndclass.cbClsExtra = 0;
|
||||
wndclass.cbWndExtra = DLGWINDOWEXTRA;
|
||||
wndclass.hInstance = hInstance;
|
||||
wndclass.hIcon = LoadIcon (hInstance, szAppName);
|
||||
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
|
||||
wndclass.hbrBackground = GetStockObject(WHITE_BRUSH);
|
||||
wndclass.lpszMenuName = "DE";
|
||||
wndclass.lpszClassName = szAppName;
|
||||
|
||||
if (RegisterClass (&wndclass) == 0) {
|
||||
char buf[50];
|
||||
|
||||
sprintf(buf, "RegisterClass: error code: 0x%X", GetLastError());
|
||||
de_error(buf);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* Empirically, the command line does not include the command name ...
|
||||
if (command_line != 0) {
|
||||
while (isspace(*command_line)) command_line++;
|
||||
while (*command_line != 0 && !isspace(*command_line)) command_line++;
|
||||
while (isspace(*command_line)) command_line++;
|
||||
} */
|
||||
|
||||
if (command_line == 0 || *command_line == 0) {
|
||||
de_error("File name argument required");
|
||||
return( 0 );
|
||||
} else {
|
||||
char *p = command_line;
|
||||
|
||||
while (*p != 0 && !isspace(*p)) p++;
|
||||
arg_file_name = CORD_to_char_star(
|
||||
CORD_substr(command_line, 0, p - command_line));
|
||||
}
|
||||
|
||||
hwnd = CreateWindow (szAppName,
|
||||
FullAppName,
|
||||
WS_OVERLAPPEDWINDOW | WS_CAPTION, /* Window style */
|
||||
CW_USEDEFAULT, 0, /* default pos. */
|
||||
CW_USEDEFAULT, 0, /* default width, height */
|
||||
NULL, /* No parent */
|
||||
NULL, /* Window class menu */
|
||||
hInstance, NULL);
|
||||
if (hwnd == NULL) {
|
||||
char buf[50];
|
||||
|
||||
sprintf(buf, "CreateWindow: error code: 0x%X", GetLastError());
|
||||
de_error(buf);
|
||||
return(0);
|
||||
}
|
||||
|
||||
ShowWindow (hwnd, nCmdShow);
|
||||
|
||||
hAccel = LoadAccelerators( hInstance, szAppName );
|
||||
|
||||
while (GetMessage (&msg, NULL, 0, 0))
|
||||
{
|
||||
if( !TranslateAccelerator( hwnd, hAccel, &msg ) )
|
||||
{
|
||||
TranslateMessage (&msg);
|
||||
DispatchMessage (&msg);
|
||||
}
|
||||
}
|
||||
return msg.wParam;
|
||||
}
|
||||
|
||||
/* Return the argument with all control characters replaced by blanks. */
|
||||
char * plain_chars(char * text, size_t len)
|
||||
{
|
||||
char * result = GC_MALLOC_ATOMIC(len + 1);
|
||||
register size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (iscntrl(text[i])) {
|
||||
result[i] = ' ';
|
||||
} else {
|
||||
result[i] = text[i];
|
||||
}
|
||||
}
|
||||
result[len] = '\0';
|
||||
return(result);
|
||||
}
|
||||
|
||||
/* Return the argument with all non-control-characters replaced by */
|
||||
/* blank, and all control characters c replaced by c + 32. */
|
||||
char * control_chars(char * text, size_t len)
|
||||
{
|
||||
char * result = GC_MALLOC_ATOMIC(len + 1);
|
||||
register size_t i;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
if (iscntrl(text[i])) {
|
||||
result[i] = text[i] + 0x40;
|
||||
} else {
|
||||
result[i] = ' ';
|
||||
}
|
||||
}
|
||||
result[len] = '\0';
|
||||
return(result);
|
||||
}
|
||||
|
||||
int char_width;
|
||||
int char_height;
|
||||
|
||||
void get_line_rect(int line, int win_width, RECT * rectp)
|
||||
{
|
||||
rectp -> top = line * char_height;
|
||||
rectp -> bottom = rectp->top + char_height;
|
||||
rectp -> left = 0;
|
||||
rectp -> right = win_width;
|
||||
}
|
||||
|
||||
int caret_visible = 0; /* Caret is currently visible. */
|
||||
|
||||
int screen_was_painted = 0;/* Screen has been painted at least once. */
|
||||
|
||||
void update_cursor(void);
|
||||
|
||||
INT_PTR CALLBACK AboutBoxCallback( HWND hDlg, UINT message,
|
||||
WPARAM wParam, LPARAM lParam )
|
||||
{
|
||||
switch( message )
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
SetFocus( GetDlgItem( hDlg, IDOK ) );
|
||||
break;
|
||||
|
||||
case WM_COMMAND:
|
||||
switch( wParam )
|
||||
{
|
||||
case IDOK:
|
||||
EndDialog( hDlg, TRUE );
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
EndDialog( hDlg, TRUE );
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
static HANDLE hInstance;
|
||||
HDC dc;
|
||||
PAINTSTRUCT ps;
|
||||
RECT client_area;
|
||||
RECT this_line;
|
||||
RECT dummy;
|
||||
TEXTMETRIC tm;
|
||||
register int i;
|
||||
int id;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_CREATE:
|
||||
hInstance = ( (LPCREATESTRUCT) lParam)->hInstance;
|
||||
dc = GetDC(hwnd);
|
||||
SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
|
||||
GetTextMetrics(dc, &tm);
|
||||
ReleaseDC(hwnd, dc);
|
||||
char_width = tm.tmAveCharWidth;
|
||||
char_height = tm.tmHeight + tm.tmExternalLeading;
|
||||
GetClientRect(hwnd, &client_area);
|
||||
COLS = (client_area.right - client_area.left)/char_width;
|
||||
LINES = (client_area.bottom - client_area.top)/char_height;
|
||||
generic_init();
|
||||
return(0);
|
||||
|
||||
case WM_CHAR:
|
||||
if (wParam == QUIT) {
|
||||
SendMessage( hwnd, WM_CLOSE, 0, 0L );
|
||||
} else {
|
||||
do_command((int)wParam);
|
||||
}
|
||||
return(0);
|
||||
|
||||
case WM_SETFOCUS:
|
||||
CreateCaret(hwnd, NULL, char_width, char_height);
|
||||
ShowCaret(hwnd);
|
||||
caret_visible = 1;
|
||||
update_cursor();
|
||||
return(0);
|
||||
|
||||
case WM_KILLFOCUS:
|
||||
HideCaret(hwnd);
|
||||
DestroyCaret();
|
||||
caret_visible = 0;
|
||||
return(0);
|
||||
|
||||
case WM_LBUTTONUP:
|
||||
{
|
||||
unsigned xpos = LOWORD(lParam); /* From left */
|
||||
unsigned ypos = HIWORD(lParam); /* from top */
|
||||
|
||||
set_position( xpos/char_width, ypos/char_height );
|
||||
return(0);
|
||||
}
|
||||
|
||||
case WM_COMMAND:
|
||||
id = LOWORD(wParam);
|
||||
if (id & EDIT_CMD_FLAG) {
|
||||
if (id & REPEAT_FLAG) do_command(REPEAT);
|
||||
do_command(CHAR_CMD(id));
|
||||
return( 0 );
|
||||
} else {
|
||||
switch(id) {
|
||||
case IDM_FILEEXIT:
|
||||
SendMessage( hwnd, WM_CLOSE, 0, 0L );
|
||||
return( 0 );
|
||||
|
||||
case IDM_HELPABOUT:
|
||||
if( DialogBox( hInstance, "ABOUTBOX",
|
||||
hwnd, AboutBoxCallback ) )
|
||||
InvalidateRect( hwnd, NULL, TRUE );
|
||||
return( 0 );
|
||||
case IDM_HELPCONTENTS:
|
||||
de_error(
|
||||
"Cursor keys: ^B(left) ^F(right) ^P(up) ^N(down)\n"
|
||||
"Undo: ^U Write: ^W Quit:^D Repeat count: ^R[n]\n"
|
||||
"Top: ^T Locate (search, find): ^L text ^L\n");
|
||||
return( 0 );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_CLOSE:
|
||||
DestroyWindow( hwnd );
|
||||
return 0;
|
||||
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage (0);
|
||||
GC_win32_free_heap();
|
||||
return 0;
|
||||
|
||||
case WM_PAINT:
|
||||
dc = BeginPaint(hwnd, &ps);
|
||||
GetClientRect(hwnd, &client_area);
|
||||
COLS = (client_area.right - client_area.left)/char_width;
|
||||
LINES = (client_area.bottom - client_area.top)/char_height;
|
||||
SelectObject(dc, GetStockObject(SYSTEM_FIXED_FONT));
|
||||
for (i = 0; i < LINES; i++) {
|
||||
get_line_rect(i, client_area.right, &this_line);
|
||||
if (IntersectRect(&dummy, &this_line, &ps.rcPaint)) {
|
||||
CORD raw_line = retrieve_screen_line(i);
|
||||
size_t len = CORD_len(raw_line);
|
||||
char * text = CORD_to_char_star(raw_line);
|
||||
/* May contain embedded NULLs */
|
||||
char * plain = plain_chars(text, len);
|
||||
char * blanks = CORD_to_char_star(CORD_chars(' ',
|
||||
COLS - len));
|
||||
char * control = control_chars(text, len);
|
||||
# define RED RGB(255,0,0)
|
||||
|
||||
SetBkMode(dc, OPAQUE);
|
||||
SetTextColor(dc, GetSysColor(COLOR_WINDOWTEXT));
|
||||
|
||||
TextOut(dc, this_line.left, this_line.top,
|
||||
plain, (int)len);
|
||||
TextOut(dc, this_line.left + (int)len * char_width,
|
||||
this_line.top,
|
||||
blanks, (int)(COLS - len));
|
||||
SetBkMode(dc, TRANSPARENT);
|
||||
SetTextColor(dc, RED);
|
||||
TextOut(dc, this_line.left, this_line.top,
|
||||
control, (int)strlen(control));
|
||||
}
|
||||
}
|
||||
EndPaint(hwnd, &ps);
|
||||
screen_was_painted = 1;
|
||||
return 0;
|
||||
}
|
||||
return DefWindowProc (hwnd, message, wParam, lParam);
|
||||
}
|
||||
|
||||
int last_col;
|
||||
int last_line;
|
||||
|
||||
void move_cursor(int c, int l)
|
||||
{
|
||||
last_col = c;
|
||||
last_line = l;
|
||||
|
||||
if (caret_visible) update_cursor();
|
||||
}
|
||||
|
||||
void update_cursor(void)
|
||||
{
|
||||
SetCaretPos(last_col * char_width, last_line * char_height);
|
||||
ShowCaret(hwnd);
|
||||
}
|
||||
|
||||
void invalidate_line(int i)
|
||||
{
|
||||
RECT line;
|
||||
|
||||
if (!screen_was_painted) return;
|
||||
/* Invalidating a rectangle before painting seems result in a */
|
||||
/* major performance problem. */
|
||||
get_line_rect(i, COLS*char_width, &line);
|
||||
InvalidateRect(hwnd, &line, FALSE);
|
||||
}
|
||||
|
||||
103
src/engine/boehm_gc/cord/de_win.h
Normal file
103
src/engine/boehm_gc/cord/de_win.h
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
||||
*
|
||||
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
*
|
||||
* Permission is hereby granted to use or copy this program
|
||||
* for any purpose, provided the above notices are retained on all copies.
|
||||
* Permission to modify the code and to distribute modified code is granted,
|
||||
* provided the above notices are retained, and a notice that the code was
|
||||
* modified is included with the above copyright notice.
|
||||
*/
|
||||
/* Boehm, May 19, 1994 2:25 pm PDT */
|
||||
|
||||
/* cord.h, de_cmds.h, and windows.h should be included before this. */
|
||||
|
||||
|
||||
# define OTHER_FLAG 0x100
|
||||
# define EDIT_CMD_FLAG 0x200
|
||||
# define REPEAT_FLAG 0x400
|
||||
|
||||
# define CHAR_CMD(i) ((i) & 0xff)
|
||||
|
||||
/* MENU: DE */
|
||||
#define IDM_FILESAVE (EDIT_CMD_FLAG + WRITE)
|
||||
#define IDM_FILEEXIT (OTHER_FLAG + 1)
|
||||
#define IDM_HELPABOUT (OTHER_FLAG + 2)
|
||||
#define IDM_HELPCONTENTS (OTHER_FLAG + 3)
|
||||
|
||||
#define IDM_EDITPDOWN (REPEAT_FLAG + EDIT_CMD_FLAG + DOWN)
|
||||
#define IDM_EDITPUP (REPEAT_FLAG + EDIT_CMD_FLAG + UP)
|
||||
#define IDM_EDITUNDO (EDIT_CMD_FLAG + UNDO)
|
||||
#define IDM_EDITLOCATE (EDIT_CMD_FLAG + LOCATE)
|
||||
#define IDM_EDITDOWN (EDIT_CMD_FLAG + DOWN)
|
||||
#define IDM_EDITUP (EDIT_CMD_FLAG + UP)
|
||||
#define IDM_EDITLEFT (EDIT_CMD_FLAG + LEFT)
|
||||
#define IDM_EDITRIGHT (EDIT_CMD_FLAG + RIGHT)
|
||||
#define IDM_EDITBS (EDIT_CMD_FLAG + BS)
|
||||
#define IDM_EDITDEL (EDIT_CMD_FLAG + DEL)
|
||||
#define IDM_EDITREPEAT (EDIT_CMD_FLAG + REPEAT)
|
||||
#define IDM_EDITTOP (EDIT_CMD_FLAG + TOP)
|
||||
|
||||
|
||||
|
||||
|
||||
/* Windows UI stuff */
|
||||
|
||||
LRESULT CALLBACK WndProc (HWND hwnd, UINT message,
|
||||
UINT wParam, LONG lParam);
|
||||
|
||||
LRESULT CALLBACK AboutBox( HWND hDlg, UINT message,
|
||||
UINT wParam, LONG lParam );
|
||||
|
||||
|
||||
/* Screen dimensions. Maintained by de_win.c. */
|
||||
extern int LINES;
|
||||
extern int COLS;
|
||||
|
||||
/* File being edited. */
|
||||
extern char * arg_file_name;
|
||||
|
||||
/* Current display position in file. Maintained by de.c */
|
||||
extern int dis_line;
|
||||
extern int dis_col;
|
||||
|
||||
/* Current cursor position in file. */
|
||||
extern int line;
|
||||
extern int col;
|
||||
|
||||
/*
|
||||
* Calls from de_win.c to de.c
|
||||
*/
|
||||
|
||||
CORD retrieve_screen_line(int i);
|
||||
/* Get the contents of i'th screen line. */
|
||||
/* Relies on COLS. */
|
||||
|
||||
void set_position(int x, int y);
|
||||
/* Set column, row. Upper left of window = (0,0). */
|
||||
|
||||
void do_command(int);
|
||||
/* Execute an editor command. */
|
||||
/* Agument is a command character or one */
|
||||
/* of the IDM_ commands. */
|
||||
|
||||
void generic_init(void);
|
||||
/* OS independent initialization */
|
||||
|
||||
|
||||
/*
|
||||
* Calls from de.c to de_win.c
|
||||
*/
|
||||
|
||||
void move_cursor(int column, int line);
|
||||
/* Physically move the cursor on the display, */
|
||||
/* so that it appears at */
|
||||
/* (column, line). */
|
||||
|
||||
void invalidate_line(int line);
|
||||
/* Invalidate line i on the screen. */
|
||||
|
||||
void de_error(char *s);
|
||||
/* Display error message. */
|
||||
599
src/engine/boehm_gc/darwin_stop_world.c
Normal file
599
src/engine/boehm_gc/darwin_stop_world.c
Normal file
@@ -0,0 +1,599 @@
|
||||
#include "private/pthread_support.h"
|
||||
|
||||
/* This probably needs more porting work to ppc64. */
|
||||
|
||||
# if defined(GC_DARWIN_THREADS)
|
||||
|
||||
/* From "Inside Mac OS X - Mach-O Runtime Architecture" published by Apple
|
||||
Page 49:
|
||||
"The space beneath the stack pointer, where a new stack frame would normally
|
||||
be allocated, is called the red zone. This area as shown in Figure 3-2 may
|
||||
be used for any purpose as long as a new stack frame does not need to be
|
||||
added to the stack."
|
||||
|
||||
Page 50: "If a leaf procedure's red zone usage would exceed 224 bytes, then
|
||||
it must set up a stack frame just like routines that call other routines."
|
||||
*/
|
||||
#ifdef POWERPC
|
||||
# if CPP_WORDSZ == 32
|
||||
# define PPC_RED_ZONE_SIZE 224
|
||||
# elif CPP_WORDSZ == 64
|
||||
# define PPC_RED_ZONE_SIZE 320
|
||||
# endif
|
||||
#endif
|
||||
|
||||
typedef struct StackFrame {
|
||||
unsigned long savedSP;
|
||||
unsigned long savedCR;
|
||||
unsigned long savedLR;
|
||||
unsigned long reserved[2];
|
||||
unsigned long savedRTOC;
|
||||
} StackFrame;
|
||||
|
||||
unsigned long FindTopOfStack(unsigned long stack_start)
|
||||
{
|
||||
StackFrame *frame;
|
||||
|
||||
if (stack_start == 0) {
|
||||
# ifdef POWERPC
|
||||
# if CPP_WORDSZ == 32
|
||||
__asm__ volatile("lwz %0,0(r1)" : "=r" (frame));
|
||||
# else
|
||||
__asm__ volatile("ld %0,0(r1)" : "=r" (frame));
|
||||
# endif
|
||||
# endif
|
||||
} else {
|
||||
frame = (StackFrame *)stack_start;
|
||||
}
|
||||
|
||||
# ifdef DEBUG_THREADS
|
||||
/* GC_printf("FindTopOfStack start at sp = %p\n", frame); */
|
||||
# endif
|
||||
do {
|
||||
if (frame->savedSP == 0)
|
||||
break;
|
||||
/* if there are no more stack frames, stop */
|
||||
|
||||
frame = (StackFrame*)frame->savedSP;
|
||||
|
||||
/* we do these next two checks after going to the next frame
|
||||
because the LR for the first stack frame in the loop
|
||||
is not set up on purpose, so we shouldn't check it. */
|
||||
if ((frame->savedLR & ~3) == 0)
|
||||
break; /* if the next LR is bogus, stop */
|
||||
if ((~(frame->savedLR) & ~3) == 0)
|
||||
break; /* ditto */
|
||||
} while (1);
|
||||
|
||||
# ifdef DEBUG_THREADS
|
||||
/* GC_printf("FindTopOfStack finish at sp = %p\n", frame); */
|
||||
# endif
|
||||
|
||||
return (unsigned long)frame;
|
||||
}
|
||||
|
||||
#ifdef DARWIN_DONT_PARSE_STACK
|
||||
void GC_push_all_stacks()
|
||||
{
|
||||
int i;
|
||||
kern_return_t r;
|
||||
GC_thread p;
|
||||
pthread_t me;
|
||||
ptr_t lo, hi;
|
||||
GC_THREAD_STATE_T state;
|
||||
/* MACHINE_THREAD_STATE_COUNT doesn't seem to be defined everywhere. */
|
||||
/* Hence we use our own version. */
|
||||
mach_msg_type_number_t thread_state_count = GC_MACH_THREAD_STATE_COUNT;
|
||||
|
||||
me = pthread_self();
|
||||
if (!GC_thr_initialized)
|
||||
GC_thr_init();
|
||||
|
||||
for(i = 0; i < THREAD_TABLE_SZ; i++) {
|
||||
for(p = GC_threads[i]; p != 0; p = p->next) {
|
||||
if(p->flags & FINISHED) continue;
|
||||
if(pthread_equal(p->id, me)) {
|
||||
lo = GC_approx_sp();
|
||||
} else {
|
||||
/* Get the thread state (registers, etc) */
|
||||
r = thread_get_state(p->stop_info.mach_thread, GC_MACH_THREAD_STATE,
|
||||
(natural_t*)&state, &thread_state_count);
|
||||
|
||||
# ifdef DEBUG_THREADS
|
||||
GC_printf("thread_get_state return value = %d\n", r);
|
||||
# endif
|
||||
|
||||
if(r != KERN_SUCCESS)
|
||||
ABORT("thread_get_state failed");
|
||||
|
||||
# if defined(I386)
|
||||
lo = (void*)state . THREAD_FLD (esp);
|
||||
GC_push_one(state . THREAD_FLD (eax));
|
||||
GC_push_one(state . THREAD_FLD (ebx));
|
||||
GC_push_one(state . THREAD_FLD (ecx));
|
||||
GC_push_one(state . THREAD_FLD (edx));
|
||||
GC_push_one(state . THREAD_FLD (edi));
|
||||
GC_push_one(state . THREAD_FLD (esi));
|
||||
GC_push_one(state . THREAD_FLD (ebp));
|
||||
|
||||
# elif defined(X86_64)
|
||||
lo = (void*)state . THREAD_FLD (rsp);
|
||||
GC_push_one(state . THREAD_FLD (rax));
|
||||
GC_push_one(state . THREAD_FLD (rbx));
|
||||
GC_push_one(state . THREAD_FLD (rcx));
|
||||
GC_push_one(state . THREAD_FLD (rdx));
|
||||
GC_push_one(state . THREAD_FLD (rdi));
|
||||
GC_push_one(state . THREAD_FLD (rsi));
|
||||
GC_push_one(state . THREAD_FLD (rbp));
|
||||
GC_push_one(state . THREAD_FLD (rsp));
|
||||
GC_push_one(state . THREAD_FLD (r8));
|
||||
GC_push_one(state . THREAD_FLD (r9));
|
||||
GC_push_one(state . THREAD_FLD (r10));
|
||||
GC_push_one(state . THREAD_FLD (r11));
|
||||
GC_push_one(state . THREAD_FLD (r12));
|
||||
GC_push_one(state . THREAD_FLD (r13));
|
||||
GC_push_one(state . THREAD_FLD (r14));
|
||||
GC_push_one(state . THREAD_FLD (r15));
|
||||
GC_push_one(state . THREAD_FLD (rip));
|
||||
GC_push_one(state . THREAD_FLD (rflags));
|
||||
GC_push_one(state . THREAD_FLD (cs));
|
||||
GC_push_one(state . THREAD_FLD (fs));
|
||||
GC_push_one(state . THREAD_FLD (gs));
|
||||
|
||||
# elif defined(POWERPC)
|
||||
lo = (void*)(state . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
|
||||
|
||||
GC_push_one(state . THREAD_FLD (r0));
|
||||
GC_push_one(state . THREAD_FLD (r2));
|
||||
GC_push_one(state . THREAD_FLD (r3));
|
||||
GC_push_one(state . THREAD_FLD (r4));
|
||||
GC_push_one(state . THREAD_FLD (r5));
|
||||
GC_push_one(state . THREAD_FLD (r6));
|
||||
GC_push_one(state . THREAD_FLD (r7));
|
||||
GC_push_one(state . THREAD_FLD (r8));
|
||||
GC_push_one(state . THREAD_FLD (r9));
|
||||
GC_push_one(state . THREAD_FLD (r10));
|
||||
GC_push_one(state . THREAD_FLD (r11));
|
||||
GC_push_one(state . THREAD_FLD (r12));
|
||||
GC_push_one(state . THREAD_FLD (r13));
|
||||
GC_push_one(state . THREAD_FLD (r14));
|
||||
GC_push_one(state . THREAD_FLD (r15));
|
||||
GC_push_one(state . THREAD_FLD (r16));
|
||||
GC_push_one(state . THREAD_FLD (r17));
|
||||
GC_push_one(state . THREAD_FLD (r18));
|
||||
GC_push_one(state . THREAD_FLD (r19));
|
||||
GC_push_one(state . THREAD_FLD (r20));
|
||||
GC_push_one(state . THREAD_FLD (r21));
|
||||
GC_push_one(state . THREAD_FLD (r22));
|
||||
GC_push_one(state . THREAD_FLD (r23));
|
||||
GC_push_one(state . THREAD_FLD (r24));
|
||||
GC_push_one(state . THREAD_FLD (r25));
|
||||
GC_push_one(state . THREAD_FLD (r26));
|
||||
GC_push_one(state . THREAD_FLD (r27));
|
||||
GC_push_one(state . THREAD_FLD (r28));
|
||||
GC_push_one(state . THREAD_FLD (r29));
|
||||
GC_push_one(state . THREAD_FLD (r30));
|
||||
GC_push_one(state . THREAD_FLD (r31));
|
||||
# else
|
||||
# error FIXME for non-x86 || ppc architectures
|
||||
# endif
|
||||
} /* p != me */
|
||||
if(p->flags & MAIN_THREAD)
|
||||
hi = GC_stackbottom;
|
||||
else
|
||||
hi = p->stack_end;
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Darwin: Stack for thread 0x%lx = [%lx,%lx)\n",
|
||||
(unsigned long) p -> id, (unsigned long) lo,
|
||||
(unsigned long) hi);
|
||||
# endif
|
||||
GC_push_all_stack(lo, hi);
|
||||
} /* for(p=GC_threads[i]...) */
|
||||
} /* for(i=0;i<THREAD_TABLE_SZ...) */
|
||||
}
|
||||
|
||||
#else /* !DARWIN_DONT_PARSE_STACK; Use FindTopOfStack() */
|
||||
|
||||
void GC_push_all_stacks()
|
||||
{
|
||||
unsigned int i;
|
||||
task_t my_task;
|
||||
kern_return_t r;
|
||||
mach_port_t me;
|
||||
ptr_t lo, hi;
|
||||
thread_act_array_t act_list = 0;
|
||||
mach_msg_type_number_t listcount = 0;
|
||||
|
||||
me = mach_thread_self();
|
||||
if (!GC_thr_initialized)
|
||||
GC_thr_init();
|
||||
|
||||
my_task = current_task();
|
||||
r = task_threads(my_task, &act_list, &listcount);
|
||||
if(r != KERN_SUCCESS)
|
||||
ABORT("task_threads failed");
|
||||
for(i = 0; i < listcount; i++) {
|
||||
thread_act_t thread = act_list[i];
|
||||
if (thread == me) {
|
||||
lo = GC_approx_sp();
|
||||
hi = (ptr_t)FindTopOfStack(0);
|
||||
} else {
|
||||
# if defined(POWERPC)
|
||||
GC_THREAD_STATE_T info;
|
||||
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
|
||||
r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
|
||||
&outCount);
|
||||
if(r != KERN_SUCCESS)
|
||||
ABORT("task_get_state failed");
|
||||
|
||||
lo = (void*)(info . THREAD_FLD (r1) - PPC_RED_ZONE_SIZE);
|
||||
hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (r1));
|
||||
|
||||
GC_push_one(info . THREAD_FLD (r0));
|
||||
GC_push_one(info . THREAD_FLD (r2));
|
||||
GC_push_one(info . THREAD_FLD (r3));
|
||||
GC_push_one(info . THREAD_FLD (r4));
|
||||
GC_push_one(info . THREAD_FLD (r5));
|
||||
GC_push_one(info . THREAD_FLD (r6));
|
||||
GC_push_one(info . THREAD_FLD (r7));
|
||||
GC_push_one(info . THREAD_FLD (r8));
|
||||
GC_push_one(info . THREAD_FLD (r9));
|
||||
GC_push_one(info . THREAD_FLD (r10));
|
||||
GC_push_one(info . THREAD_FLD (r11));
|
||||
GC_push_one(info . THREAD_FLD (r12));
|
||||
GC_push_one(info . THREAD_FLD (r13));
|
||||
GC_push_one(info . THREAD_FLD (r14));
|
||||
GC_push_one(info . THREAD_FLD (r15));
|
||||
GC_push_one(info . THREAD_FLD (r16));
|
||||
GC_push_one(info . THREAD_FLD (r17));
|
||||
GC_push_one(info . THREAD_FLD (r18));
|
||||
GC_push_one(info . THREAD_FLD (r19));
|
||||
GC_push_one(info . THREAD_FLD (r20));
|
||||
GC_push_one(info . THREAD_FLD (r21));
|
||||
GC_push_one(info . THREAD_FLD (r22));
|
||||
GC_push_one(info . THREAD_FLD (r23));
|
||||
GC_push_one(info . THREAD_FLD (r24));
|
||||
GC_push_one(info . THREAD_FLD (r25));
|
||||
GC_push_one(info . THREAD_FLD (r26));
|
||||
GC_push_one(info . THREAD_FLD (r27));
|
||||
GC_push_one(info . THREAD_FLD (r28));
|
||||
GC_push_one(info . THREAD_FLD (r29));
|
||||
GC_push_one(info . THREAD_FLD (r30));
|
||||
GC_push_one(info . THREAD_FLD (r31));
|
||||
|
||||
# elif defined(I386)
|
||||
/* FIXME: Remove after testing: */
|
||||
WARN("This is completely untested and likely will not work\n", 0);
|
||||
GC_THREAD_STATE_T info;
|
||||
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
|
||||
r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
|
||||
&outCount);
|
||||
if(r != KERN_SUCCESS)
|
||||
ABORT("task_get_state failed");
|
||||
|
||||
lo = (void*)info . THREAD_FLD (esp);
|
||||
hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (esp));
|
||||
|
||||
GC_push_one(info . THREAD_FLD (eax));
|
||||
GC_push_one(info . THREAD_FLD (ebx));
|
||||
GC_push_one(info . THREAD_FLD (ecx));
|
||||
GC_push_one(info . THREAD_FLD (edx));
|
||||
GC_push_one(info . THREAD_FLD (edi));
|
||||
GC_push_one(info . THREAD_FLD (esi));
|
||||
/* GC_push_one(info . THREAD_FLD (ebp)); */
|
||||
/* GC_push_one(info . THREAD_FLD (esp)); */
|
||||
GC_push_one(info . THREAD_FLD (ss));
|
||||
GC_push_one(info . THREAD_FLD (eip));
|
||||
GC_push_one(info . THREAD_FLD (cs));
|
||||
GC_push_one(info . THREAD_FLD (ds));
|
||||
GC_push_one(info . THREAD_FLD (es));
|
||||
GC_push_one(info . THREAD_FLD (fs));
|
||||
GC_push_one(info . THREAD_FLD (gs));
|
||||
|
||||
# elif defined(X86_64)
|
||||
GC_THREAD_STATE_T info;
|
||||
mach_msg_type_number_t outCount = THREAD_STATE_MAX;
|
||||
r = thread_get_state(thread, GC_MACH_THREAD_STATE, (natural_t *)&info,
|
||||
&outCount);
|
||||
if(r != KERN_SUCCESS)
|
||||
ABORT("task_get_state failed");
|
||||
|
||||
lo = (void*)info . THREAD_FLD (rsp);
|
||||
hi = (ptr_t)FindTopOfStack(info . THREAD_FLD (rsp));
|
||||
|
||||
GC_push_one(info . THREAD_FLD (rax));
|
||||
GC_push_one(info . THREAD_FLD (rbx));
|
||||
GC_push_one(info . THREAD_FLD (rcx));
|
||||
GC_push_one(info . THREAD_FLD (rdx));
|
||||
GC_push_one(info . THREAD_FLD (rdi));
|
||||
GC_push_one(info . THREAD_FLD (rsi));
|
||||
GC_push_one(info . THREAD_FLD (rbp));
|
||||
GC_push_one(info . THREAD_FLD (rsp));
|
||||
GC_push_one(info . THREAD_FLD (r8));
|
||||
GC_push_one(info . THREAD_FLD (r9));
|
||||
GC_push_one(info . THREAD_FLD (r10));
|
||||
GC_push_one(info . THREAD_FLD (r11));
|
||||
GC_push_one(info . THREAD_FLD (r12));
|
||||
GC_push_one(info . THREAD_FLD (r13));
|
||||
GC_push_one(info . THREAD_FLD (r14));
|
||||
GC_push_one(info . THREAD_FLD (r15));
|
||||
GC_push_one(info . THREAD_FLD (rip));
|
||||
GC_push_one(info . THREAD_FLD (rflags));
|
||||
GC_push_one(info . THREAD_FLD (cs));
|
||||
GC_push_one(info . THREAD_FLD (fs));
|
||||
GC_push_one(info . THREAD_FLD (gs));
|
||||
|
||||
# else
|
||||
# error FIXME for non-x86 || ppc architectures
|
||||
# endif
|
||||
}
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Darwin: Stack for thread 0x%lx = [%p,%p)\n",
|
||||
(unsigned long) thread, lo, hi);
|
||||
# endif
|
||||
GC_push_all_stack(lo, hi);
|
||||
mach_port_deallocate(my_task, thread);
|
||||
} /* for(p=GC_threads[i]...) */
|
||||
vm_deallocate(my_task, (vm_address_t)act_list,
|
||||
sizeof(thread_t) * listcount);
|
||||
mach_port_deallocate(my_task, me);
|
||||
}
|
||||
#endif /* !DARWIN_DONT_PARSE_STACK */
|
||||
|
||||
static mach_port_t GC_mach_handler_thread;
|
||||
static int GC_use_mach_handler_thread = 0;
|
||||
|
||||
static struct GC_mach_thread GC_mach_threads[THREAD_TABLE_SZ];
|
||||
static int GC_mach_threads_count;
|
||||
|
||||
void GC_stop_init()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
||||
GC_mach_threads[i].thread = 0;
|
||||
GC_mach_threads[i].already_suspended = 0;
|
||||
}
|
||||
GC_mach_threads_count = 0;
|
||||
}
|
||||
|
||||
/* returns true if there's a thread in act_list that wasn't in old_list */
|
||||
int GC_suspend_thread_list(thread_act_array_t act_list, int count,
|
||||
thread_act_array_t old_list, int old_count)
|
||||
{
|
||||
mach_port_t my_thread = mach_thread_self();
|
||||
int i, j;
|
||||
|
||||
int changed = 0;
|
||||
|
||||
for(i = 0; i < count; i++) {
|
||||
thread_act_t thread = act_list[i];
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Attempting to suspend thread %p\n", thread);
|
||||
# endif
|
||||
/* find the current thread in the old list */
|
||||
int found = 0;
|
||||
for(j = 0; j < old_count; j++) {
|
||||
thread_act_t old_thread = old_list[j];
|
||||
if (old_thread == thread) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
/* add it to the GC_mach_threads list */
|
||||
GC_mach_threads[GC_mach_threads_count].thread = thread;
|
||||
/* default is not suspended */
|
||||
GC_mach_threads[GC_mach_threads_count].already_suspended = 0;
|
||||
changed = 1;
|
||||
}
|
||||
|
||||
if (thread != my_thread
|
||||
&& (!GC_use_mach_handler_thread
|
||||
|| (GC_use_mach_handler_thread
|
||||
&& GC_mach_handler_thread != thread))) {
|
||||
struct thread_basic_info info;
|
||||
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
|
||||
kern_return_t kern_result = thread_info(thread, THREAD_BASIC_INFO,
|
||||
(thread_info_t)&info, &outCount);
|
||||
if(kern_result != KERN_SUCCESS) {
|
||||
/* the thread may have quit since the thread_threads () call
|
||||
* we mark already_suspended so it's not dealt with anymore later
|
||||
*/
|
||||
if (!found) {
|
||||
GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
|
||||
GC_mach_threads_count++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
|
||||
info.run_state);
|
||||
# endif
|
||||
if (!found) {
|
||||
GC_mach_threads[GC_mach_threads_count].already_suspended
|
||||
= info.suspend_count;
|
||||
}
|
||||
if (info.suspend_count)
|
||||
continue;
|
||||
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Suspending 0x%lx\n", (unsigned long)thread);
|
||||
# endif
|
||||
/* Suspend the thread */
|
||||
kern_result = thread_suspend(thread);
|
||||
if(kern_result != KERN_SUCCESS) {
|
||||
/* the thread may have quit since the thread_threads () call
|
||||
* we mark already_suspended so it's not dealt with anymore later
|
||||
*/
|
||||
if (!found) {
|
||||
GC_mach_threads[GC_mach_threads_count].already_suspended = TRUE;
|
||||
GC_mach_threads_count++;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (!found) GC_mach_threads_count++;
|
||||
}
|
||||
mach_port_deallocate(current_task(), my_thread);
|
||||
return changed;
|
||||
}
|
||||
|
||||
|
||||
/* Caller holds allocation lock. */
|
||||
void GC_stop_world()
|
||||
{
|
||||
unsigned int i, changes;
|
||||
task_t my_task = current_task();
|
||||
mach_port_t my_thread = mach_thread_self();
|
||||
kern_return_t kern_result;
|
||||
thread_act_array_t act_list, prev_list;
|
||||
mach_msg_type_number_t listcount, prevcount;
|
||||
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Stopping the world from 0x%lx\n",
|
||||
(unsigned long)mach_thread_self());
|
||||
# endif
|
||||
|
||||
/* clear out the mach threads list table */
|
||||
GC_stop_init();
|
||||
|
||||
/* Make sure all free list construction has stopped before we start. */
|
||||
/* No new construction can start, since free list construction is */
|
||||
/* required to acquire and release the GC lock before it starts, */
|
||||
/* and we have the lock. */
|
||||
# ifdef PARALLEL_MARK
|
||||
GC_acquire_mark_lock();
|
||||
GC_ASSERT(GC_fl_builder_count == 0);
|
||||
/* We should have previously waited for it to become zero. */
|
||||
# endif /* PARALLEL_MARK */
|
||||
|
||||
/* Loop stopping threads until you have gone over the whole list
|
||||
twice without a new one appearing. thread_create() won't
|
||||
return (and thus the thread stop) until the new thread
|
||||
exists, so there is no window whereby you could stop a
|
||||
thread, recognise it is stopped, but then have a new thread
|
||||
it created before stopping show up later.
|
||||
*/
|
||||
|
||||
changes = 1;
|
||||
prev_list = NULL;
|
||||
prevcount = 0;
|
||||
do {
|
||||
int result;
|
||||
kern_result = task_threads(my_task, &act_list, &listcount);
|
||||
|
||||
if(kern_result == KERN_SUCCESS) {
|
||||
result = GC_suspend_thread_list(act_list, listcount, prev_list,
|
||||
prevcount);
|
||||
changes = result;
|
||||
|
||||
if(prev_list != NULL) {
|
||||
for(i = 0; i < prevcount; i++)
|
||||
mach_port_deallocate(my_task, prev_list[i]);
|
||||
|
||||
vm_deallocate(my_task, (vm_address_t)prev_list,
|
||||
sizeof(thread_t) * prevcount);
|
||||
}
|
||||
prev_list = act_list;
|
||||
prevcount = listcount;
|
||||
}
|
||||
} while (changes);
|
||||
GC_ASSERT(prev_list != 0);
|
||||
for(i = 0; i < prevcount; i++)
|
||||
mach_port_deallocate(my_task, prev_list[i]);
|
||||
|
||||
vm_deallocate(my_task, (vm_address_t)act_list,
|
||||
sizeof(thread_t) * listcount);
|
||||
|
||||
# ifdef MPROTECT_VDB
|
||||
if(GC_incremental) {
|
||||
extern void GC_mprotect_stop();
|
||||
GC_mprotect_stop();
|
||||
}
|
||||
# endif
|
||||
|
||||
# ifdef PARALLEL_MARK
|
||||
GC_release_mark_lock();
|
||||
# endif
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("World stopped from 0x%lx\n", (unsigned long)my_thread);
|
||||
# endif
|
||||
|
||||
mach_port_deallocate(my_task, my_thread);
|
||||
}
|
||||
|
||||
/* Caller holds allocation lock, and has held it continuously since */
|
||||
/* the world stopped. */
|
||||
void GC_start_world()
|
||||
{
|
||||
task_t my_task = current_task();
|
||||
mach_port_t my_thread = mach_thread_self();
|
||||
unsigned int i;
|
||||
int j;
|
||||
kern_return_t kern_result;
|
||||
thread_act_array_t act_list;
|
||||
mach_msg_type_number_t listcount;
|
||||
struct thread_basic_info info;
|
||||
mach_msg_type_number_t outCount = THREAD_INFO_MAX;
|
||||
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("World starting\n");
|
||||
# endif
|
||||
|
||||
# ifdef MPROTECT_VDB
|
||||
if(GC_incremental) {
|
||||
extern void GC_mprotect_resume();
|
||||
GC_mprotect_resume();
|
||||
}
|
||||
# endif
|
||||
|
||||
kern_result = task_threads(my_task, &act_list, &listcount);
|
||||
for(i = 0; i < listcount; i++) {
|
||||
thread_act_t thread = act_list[i];
|
||||
if (thread != my_thread
|
||||
&& (!GC_use_mach_handler_thread
|
||||
|| (GC_use_mach_handler_thread
|
||||
&& GC_mach_handler_thread != thread))) {
|
||||
for(j = 0; j < GC_mach_threads_count; j++) {
|
||||
if (thread == GC_mach_threads[j].thread) {
|
||||
if (GC_mach_threads[j].already_suspended) {
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Not resuming already suspended thread %p\n", thread);
|
||||
# endif
|
||||
continue;
|
||||
}
|
||||
kern_result = thread_info(thread, THREAD_BASIC_INFO,
|
||||
(thread_info_t)&info, &outCount);
|
||||
if(kern_result != KERN_SUCCESS)
|
||||
ABORT("thread_info failed");
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("Thread state for 0x%lx = %d\n", (unsigned long)thread,
|
||||
info.run_state);
|
||||
GC_printf("Resuming 0x%lx\n", (unsigned long)thread);
|
||||
# endif
|
||||
/* Resume the thread */
|
||||
kern_result = thread_resume(thread);
|
||||
if(kern_result != KERN_SUCCESS)
|
||||
ABORT("thread_resume failed");
|
||||
}
|
||||
}
|
||||
}
|
||||
mach_port_deallocate(my_task, thread);
|
||||
}
|
||||
vm_deallocate(my_task, (vm_address_t)act_list,
|
||||
sizeof(thread_t) * listcount);
|
||||
|
||||
mach_port_deallocate(my_task, my_thread);
|
||||
# if DEBUG_THREADS
|
||||
GC_printf("World started\n");
|
||||
# endif
|
||||
}
|
||||
|
||||
void GC_darwin_register_mach_handler_thread(mach_port_t thread)
|
||||
{
|
||||
GC_mach_handler_thread = thread;
|
||||
GC_use_mach_handler_thread = 1;
|
||||
}
|
||||
|
||||
#endif
|
||||
1053
src/engine/boehm_gc/dbg_mlc.c
Normal file
1053
src/engine/boehm_gc/dbg_mlc.c
Normal file
File diff suppressed because it is too large
Load Diff
436
src/engine/boehm_gc/depcomp
Executable file
436
src/engine/boehm_gc/depcomp
Executable file
@@ -0,0 +1,436 @@
|
||||
#! /bin/sh
|
||||
|
||||
# depcomp - compile a program generating dependencies as side-effects
|
||||
# Copyright 1999, 2000 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
|
||||
# 02111-1307, USA.
|
||||
|
||||
# As a special exception to the GNU General Public License, if you
|
||||
# distribute this file as part of a program that contains a
|
||||
# configuration script generated by Autoconf, you may include it under
|
||||
# the same distribution terms that you use for the rest of that program.
|
||||
|
||||
# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
|
||||
|
||||
if test -z "$depmode" || test -z "$source" || test -z "$object"; then
|
||||
echo "depcomp: Variables source, object and depmode must be set" 1>&2
|
||||
exit 1
|
||||
fi
|
||||
# `libtool' can also be set to `yes' or `no'.
|
||||
|
||||
if test -z "$depfile"; then
|
||||
base=`echo "$object" | sed -e 's,^.*/,,' -e 's,\.\([^.]*\)$,.P\1,'`
|
||||
dir=`echo "$object" | sed 's,/.*$,/,'`
|
||||
if test "$dir" = "$object"; then
|
||||
dir=
|
||||
fi
|
||||
# FIXME: should be _deps on DOS.
|
||||
depfile="$dir.deps/$base"
|
||||
fi
|
||||
|
||||
tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
|
||||
|
||||
rm -f "$tmpdepfile"
|
||||
|
||||
# Some modes work just like other modes, but use different flags. We
|
||||
# parameterize here, but still list the modes in the big case below,
|
||||
# to make depend.m4 easier to write. Note that we *cannot* use a case
|
||||
# here, because this file can only contain one case statement.
|
||||
if test "$depmode" = hp; then
|
||||
# HP compiler uses -M and no extra arg.
|
||||
gccflag=-M
|
||||
depmode=gcc
|
||||
fi
|
||||
|
||||
if test "$depmode" = dashXmstdout; then
|
||||
# This is just like dashmstdout with a different argument.
|
||||
dashmflag=-xM
|
||||
depmode=dashmstdout
|
||||
fi
|
||||
|
||||
case "$depmode" in
|
||||
gcc3)
|
||||
## gcc 3 implements dependency tracking that does exactly what
|
||||
## we want. Yay! Note: for some reason libtool 1.4 doesn't like
|
||||
## it if -MD -MP comes after the -MF stuff. Hmm.
|
||||
"$@" -MT "$object" -MD -MP -MF "$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
mv "$tmpdepfile" "$depfile"
|
||||
;;
|
||||
|
||||
gcc)
|
||||
## There are various ways to get dependency output from gcc. Here's
|
||||
## why we pick this rather obscure method:
|
||||
## - Don't want to use -MD because we'd like the dependencies to end
|
||||
## up in a subdir. Having to rename by hand is ugly.
|
||||
## (We might end up doing this anyway to support other compilers.)
|
||||
## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
|
||||
## -MM, not -M (despite what the docs say).
|
||||
## - Using -M directly means running the compiler twice (even worse
|
||||
## than renaming).
|
||||
if test -z "$gccflag"; then
|
||||
gccflag=-MD,
|
||||
fi
|
||||
"$@" -Wp,"$gccflag$tmpdepfile"
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
alpha=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz
|
||||
## The second -e expression handles DOS-style file names with drive letters.
|
||||
sed -e 's/^[^:]*: / /' \
|
||||
-e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
|
||||
## This next piece of magic avoids the `deleted header file' problem.
|
||||
## The problem is that when a header file which appears in a .P file
|
||||
## is deleted, the dependency causes make to die (because there is
|
||||
## typically no way to rebuild the header). We avoid this by adding
|
||||
## dummy dependencies for each header file. Too bad gcc doesn't do
|
||||
## this for us directly.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" |
|
||||
## Some versions of gcc put a space before the `:'. On the theory
|
||||
## that the space means something, we add a space to the output as
|
||||
## well.
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
hp)
|
||||
# This case exists only to let depend.m4 do its work. It works by
|
||||
# looking at the text of this script. This case will never be run,
|
||||
# since it is checked for above.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
sgi)
|
||||
if test "$libtool" = yes; then
|
||||
"$@" "-Wp,-MDupdate,$tmpdepfile"
|
||||
else
|
||||
"$@" -MDupdate "$tmpdepfile"
|
||||
fi
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
rm -f "$depfile"
|
||||
|
||||
if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
|
||||
echo "$object : \\" > "$depfile"
|
||||
|
||||
# Clip off the initial element (the dependent). Don't try to be
|
||||
# clever and replace this with sed code, as IRIX sed won't handle
|
||||
# lines with more than a fixed number of characters (4096 in
|
||||
# IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
|
||||
# the IRIX cc adds comments like `#:fec' to the end of the
|
||||
# dependency line.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
|
||||
tr '
|
||||
' ' ' >> $depfile
|
||||
echo >> $depfile
|
||||
|
||||
# The second pass generates a dummy entry for each header file.
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" \
|
||||
| sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
|
||||
>> $depfile
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
aix)
|
||||
# The C for AIX Compiler uses -M and outputs the dependencies
|
||||
# in a .u file. This file always lives in the current directory.
|
||||
# Also, the AIX compiler puts `$object:' at the start of each line;
|
||||
# $object doesn't have directory information.
|
||||
stripped=`echo "$object" | sed -e 's,^.*/,,' -e 's/\(.*\)\..*$/\1/'`
|
||||
tmpdepfile="$stripped.u"
|
||||
outname="$stripped.o"
|
||||
if test "$libtool" = yes; then
|
||||
"$@" -Wc,-M
|
||||
else
|
||||
"$@" -M
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
if test -f "$tmpdepfile"; then
|
||||
# Each line is of the form `foo.o: dependent.h'.
|
||||
# Do two passes, one to just change these to
|
||||
# `$object: dependent.h' and one to simply `dependent.h:'.
|
||||
sed -e "s,^$outname:,$object :," < "$tmpdepfile" > "$depfile"
|
||||
sed -e "s,^$outname: \(.*\)$,\1:," < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
# The sourcefile does not contain any dependencies, so just
|
||||
# store a dummy comment line, to avoid errors with the Makefile
|
||||
# "include basename.Plo" scheme.
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
tru64)
|
||||
# The Tru64 compiler uses -MD to generate dependencies as a side
|
||||
# effect. `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
|
||||
# At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
|
||||
# dependencies in `foo.d' instead, so we check for that too.
|
||||
# Subdirectories are respected.
|
||||
|
||||
base=`echo "$object" | sed -e 's/\.o$//' -e 's/\.lo$//'`
|
||||
tmpdepfile1="$base.o.d"
|
||||
tmpdepfile2="$base.d"
|
||||
if test "$libtool" = yes; then
|
||||
"$@" -Wc,-MD
|
||||
else
|
||||
"$@" -MD
|
||||
fi
|
||||
|
||||
stat=$?
|
||||
if test $stat -eq 0; then :
|
||||
else
|
||||
rm -f "$tmpdepfile1" "$tmpdepfile2"
|
||||
exit $stat
|
||||
fi
|
||||
|
||||
if test -f "$tmpdepfile1"; then
|
||||
tmpdepfile="$tmpdepfile1"
|
||||
else
|
||||
tmpdepfile="$tmpdepfile2"
|
||||
fi
|
||||
if test -f "$tmpdepfile"; then
|
||||
sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
|
||||
# That's a space and a tab in the [].
|
||||
sed -e 's,^.*\.[a-z]*:[ ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
|
||||
else
|
||||
echo "#dummy" > "$depfile"
|
||||
fi
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
#nosideeffect)
|
||||
# This comment above is used by automake to tell side-effect
|
||||
# dependency tracking mechanisms from slower ones.
|
||||
|
||||
dashmstdout)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
test -z "$dashmflag" && dashmflag=-M
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*) # this is libtool, let us make it quiet
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case "$arg" in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" $dashmflag | sed 's:^[^:]*\:[ ]*:'"$object"'\: :' > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
tr ' ' '
|
||||
' < "$tmpdepfile" | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
dashXmstdout)
|
||||
# This case only exists to satisfy depend.m4. It is never actually
|
||||
# run, as this mode is specially recognized in the preamble.
|
||||
exit 1
|
||||
;;
|
||||
|
||||
makedepend)
|
||||
# X makedepend
|
||||
(
|
||||
shift
|
||||
cleared=no
|
||||
for arg in "$@"; do
|
||||
case $cleared in no)
|
||||
set ""; shift
|
||||
cleared=yes
|
||||
esac
|
||||
case "$arg" in
|
||||
-D*|-I*)
|
||||
set fnord "$@" "$arg"; shift;;
|
||||
-*)
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"; shift;;
|
||||
esac
|
||||
done
|
||||
obj_suffix="`echo $object | sed 's/^.*\././'`"
|
||||
touch "$tmpdepfile"
|
||||
${MAKEDEPEND-makedepend} 2>/dev/null -o"$obj_suffix" -f"$tmpdepfile" "$@"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
cat < "$tmpdepfile" > "$depfile"
|
||||
sed '1,2d' "$tmpdepfile" | tr ' ' '
|
||||
' | \
|
||||
## Some versions of the HPUX 10.20 sed can't process this invocation
|
||||
## correctly. Breaking it into two sed invocations is a workaround.
|
||||
sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile" "$tmpdepfile".bak
|
||||
;;
|
||||
|
||||
cpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*)
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case $arg in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
"$@" -E |
|
||||
sed -n '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' |
|
||||
sed '$ s: \\$::' > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
cat < "$tmpdepfile" >> "$depfile"
|
||||
sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
msvisualcpp)
|
||||
# Important note: in order to support this mode, a compiler *must*
|
||||
# always write the proprocessed file to stdout, regardless of -o,
|
||||
# because we must use -o when running libtool.
|
||||
( IFS=" "
|
||||
case " $* " in
|
||||
*" --mode=compile "*)
|
||||
for arg
|
||||
do # cycle over the arguments
|
||||
case $arg in
|
||||
"--mode=compile")
|
||||
# insert --quiet before "--mode=compile"
|
||||
set fnord "$@" --quiet
|
||||
shift # fnord
|
||||
;;
|
||||
esac
|
||||
set fnord "$@" "$arg"
|
||||
shift # fnord
|
||||
shift # "$arg"
|
||||
done
|
||||
;;
|
||||
esac
|
||||
for arg
|
||||
do
|
||||
case "$arg" in
|
||||
"-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
|
||||
set fnord "$@"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
set fnord "$@" "$arg"
|
||||
shift
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
"$@" -E |
|
||||
sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::echo "`cygpath -u \\"\1\\"`":p' | sort | uniq > "$tmpdepfile"
|
||||
) &
|
||||
proc=$!
|
||||
"$@"
|
||||
stat=$?
|
||||
wait "$proc"
|
||||
if test "$stat" != 0; then exit $stat; fi
|
||||
rm -f "$depfile"
|
||||
echo "$object : \\" > "$depfile"
|
||||
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s:: \1 \\:p' >> "$depfile"
|
||||
echo " " >> "$depfile"
|
||||
. "$tmpdepfile" | sed 's% %\\ %g' | sed -n '/^\(.*\)$/ s::\1\::p' >> "$depfile"
|
||||
rm -f "$tmpdepfile"
|
||||
;;
|
||||
|
||||
none)
|
||||
exec "$@"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unknown depmode $depmode" 1>&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
exit 0
|
||||
90
src/engine/boehm_gc/digimars.mak
Normal file
90
src/engine/boehm_gc/digimars.mak
Normal file
@@ -0,0 +1,90 @@
|
||||
# Makefile to build Hans Boehm garbage collector using the Digital Mars
|
||||
# compiler from www.digitalmars.com
|
||||
# Written by Walter Bright
|
||||
|
||||
|
||||
DEFINES=-DNDEBUG -DGC_BUILD -D_WINDOWS -DGC_DLL -DALL_INTERIOR_POINTERS -D__STDC__ -DWIN32_THREADS
|
||||
CFLAGS=-Iinclude $(DEFINES) -wx -g
|
||||
LFLAGS=/ma/implib/co
|
||||
CC=sc
|
||||
|
||||
.c.obj:
|
||||
$(CC) -c $(CFLAGS) $*
|
||||
|
||||
.cpp.obj:
|
||||
$(CC) -c $(CFLAGS) -Aa $*
|
||||
|
||||
OBJS= \
|
||||
allchblk.obj\
|
||||
alloc.obj\
|
||||
blacklst.obj\
|
||||
checksums.obj\
|
||||
dbg_mlc.obj\
|
||||
dyn_load.obj\
|
||||
finalize.obj\
|
||||
gc_cpp.obj\
|
||||
headers.obj\
|
||||
mach_dep.obj\
|
||||
malloc.obj\
|
||||
mallocx.obj\
|
||||
mark.obj\
|
||||
mark_rts.obj\
|
||||
misc.obj\
|
||||
new_hblk.obj\
|
||||
obj_map.obj\
|
||||
os_dep.obj\
|
||||
ptr_chck.obj\
|
||||
reclaim.obj\
|
||||
stubborn.obj\
|
||||
typd_mlc.obj\
|
||||
win32_threads.obj
|
||||
|
||||
targets: gc.dll gc.lib gctest.exe
|
||||
|
||||
gc.dll: $(OBJS) gc.def digimars.mak
|
||||
sc -ogc.dll $(OBJS) -L$(LFLAGS) gc.def kernel32.lib user32.lib
|
||||
|
||||
gc.def: digimars.mak
|
||||
echo LIBRARY GC >gc.def
|
||||
echo DESCRIPTION "Hans Boehm Garbage Collector" >>gc.def
|
||||
echo EXETYPE NT >>gc.def
|
||||
echo EXPORTS >>gc.def
|
||||
echo GC_is_visible_print_proc >>gc.def
|
||||
echo GC_is_valid_displacement_print_proc >>gc.def
|
||||
|
||||
clean:
|
||||
del gc.def
|
||||
del $(OBJS)
|
||||
|
||||
|
||||
gctest.exe : gc.lib tests\test.obj
|
||||
sc -ogctest.exe tests\test.obj gc.lib
|
||||
|
||||
tests\test.obj : tests\test.c
|
||||
$(CC) -c -g -DNDEBUG -DGC_BUILD -D_WINDOWS -DGC_DLL \
|
||||
-DALL_INTERIOR_POINTERS -DWIN32_THREADS \
|
||||
-Iinclude tests\test.c -otests\test.obj
|
||||
|
||||
allchblk.obj: allchblk.c
|
||||
alloc.obj: alloc.c
|
||||
blacklst.obj: blacklst.c
|
||||
checksums.obj: checksums.c
|
||||
dbg_mlc.obj: dbg_mlc.c
|
||||
dyn_load.obj: dyn_load.c
|
||||
finalize.obj: finalize.c
|
||||
gc_cpp.obj: gc_cpp.cpp
|
||||
headers.obj: headers.c
|
||||
mach_dep.obj: mach_dep.c
|
||||
malloc.obj: malloc.c
|
||||
mallocx.obj: mallocx.c
|
||||
mark.obj: mark.c
|
||||
mark_rts.obj: mark_rts.c
|
||||
misc.obj: misc.c
|
||||
new_hblk.obj: new_hblk.c
|
||||
obj_map.obj: obj_map.c
|
||||
os_dep.obj: os_dep.c
|
||||
ptr_chck.obj: ptr_chck.c
|
||||
reclaim.obj: reclaim.c
|
||||
stubborn.obj: stubborn.c
|
||||
typd_mlc.obj: typd_mlc.c
|
||||
win32_threads.obj: win32_threads.c
|
||||
548
src/engine/boehm_gc/doc/README
Normal file
548
src/engine/boehm_gc/doc/README
Normal file
@@ -0,0 +1,548 @@
|
||||
Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
||||
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
||||
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
||||
Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P.
|
||||
|
||||
The file linux_threads.c is also
|
||||
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
||||
|
||||
The files Makefile.am, and configure.in are
|
||||
Copyright (c) 2001 by Red Hat Inc. All rights reserved.
|
||||
|
||||
Several files supporting GNU-style builds are copyrighted by the Free
|
||||
Software Foundation, and carry a different license from that given
|
||||
below. The files included in the libatomic_ops distribution (included
|
||||
here) use either the license below, or a similar MIT-style license,
|
||||
or, for some files not actually used by the garbage-collector library, the
|
||||
GPL.
|
||||
|
||||
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
||||
Permission is hereby granted to use or copy this program
|
||||
for any purpose, provided the above notices are retained on all copies.
|
||||
Permission to modify the code and to distribute modified code is granted,
|
||||
provided the above notices are retained, and a notice that the code was
|
||||
modified is included with the above copyright notice.
|
||||
|
||||
A few of the files needed to use the GNU-style build procedure come with
|
||||
slightly different licenses, though they are all similar in spirit. A few
|
||||
are GPL'ed, but with an exception that should cover all uses in the
|
||||
collector. (If you are concerned about such things, I recommend you look
|
||||
at the notice in config.guess or ltmain.sh.)
|
||||
|
||||
This is version 7.0 of a conservative garbage collector for C and C++.
|
||||
|
||||
You might find a more recent version of this at
|
||||
|
||||
http://www.hpl.hp.com/personal/Hans_Boehm/gc
|
||||
|
||||
OVERVIEW
|
||||
|
||||
This is intended to be a general purpose, garbage collecting storage
|
||||
allocator. The algorithms used are described in:
|
||||
|
||||
Boehm, H., and M. Weiser, "Garbage Collection in an Uncooperative Environment",
|
||||
Software Practice & Experience, September 1988, pp. 807-820.
|
||||
|
||||
Boehm, H., A. Demers, and S. Shenker, "Mostly Parallel Garbage Collection",
|
||||
Proceedings of the ACM SIGPLAN '91 Conference on Programming Language Design
|
||||
and Implementation, SIGPLAN Notices 26, 6 (June 1991), pp. 157-164.
|
||||
|
||||
Boehm, H., "Space Efficient Conservative Garbage Collection", Proceedings
|
||||
of the ACM SIGPLAN '91 Conference on Programming Language Design and
|
||||
Implementation, SIGPLAN Notices 28, 6 (June 1993), pp. 197-206.
|
||||
|
||||
Boehm H., "Reducing Garbage Collector Cache Misses", Proceedings of the
|
||||
2000 International Symposium on Memory Management.
|
||||
|
||||
Possible interactions between the collector and optimizing compilers are
|
||||
discussed in
|
||||
|
||||
Boehm, H., and D. Chase, "A Proposal for GC-safe C Compilation",
|
||||
The Journal of C Language Translation 4, 2 (December 1992).
|
||||
|
||||
and
|
||||
|
||||
Boehm H., "Simple GC-safe Compilation", Proceedings
|
||||
of the ACM SIGPLAN '96 Conference on Programming Language Design and
|
||||
Implementation.
|
||||
|
||||
(Some of these are also available from
|
||||
http://www.hpl.hp.com/personal/Hans_Boehm/papers/, among other places.)
|
||||
|
||||
Unlike the collector described in the second reference, this collector
|
||||
operates either with the mutator stopped during the entire collection
|
||||
(default) or incrementally during allocations. (The latter is supported
|
||||
on fewer machines.) On the most common platforms, it can be built
|
||||
with or without thread support. On a few platforms, it can take advantage
|
||||
of a multiprocessor to speed up garbage collection.
|
||||
|
||||
Many of the ideas underlying the collector have previously been explored
|
||||
by others. Notably, some of the run-time systems developed at Xerox PARC
|
||||
in the early 1980s conservatively scanned thread stacks to locate possible
|
||||
pointers (cf. Paul Rovner, "On Adding Garbage Collection and Runtime Types
|
||||
to a Strongly-Typed Statically Checked, Concurrent Language" Xerox PARC
|
||||
CSL 84-7). Doug McIlroy wrote a simpler fully conservative collector that
|
||||
was part of version 8 UNIX (tm), but appears to not have received
|
||||
widespread use.
|
||||
|
||||
Rudimentary tools for use of the collector as a leak detector are included
|
||||
(see http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html),
|
||||
as is a fairly sophisticated string package "cord" that makes use of the
|
||||
collector. (See doc/README.cords and H.-J. Boehm, R. Atkinson, and M. Plass,
|
||||
"Ropes: An Alternative to Strings", Software Practice and Experience 25, 12
|
||||
(December 1995), pp. 1315-1330. This is very similar to the "rope" package
|
||||
in Xerox Cedar, or the "rope" package in the SGI STL or the g++ distribution.)
|
||||
|
||||
Further collector documantation can be found at
|
||||
|
||||
http://www.hpl.hp.com/personal/Hans_Boehm/gc
|
||||
|
||||
|
||||
GENERAL DESCRIPTION
|
||||
|
||||
This is a garbage collecting storage allocator that is intended to be
|
||||
used as a plug-in replacement for C's malloc.
|
||||
|
||||
Since the collector does not require pointers to be tagged, it does not
|
||||
attempt to ensure that all inaccessible storage is reclaimed. However,
|
||||
in our experience, it is typically more successful at reclaiming unused
|
||||
memory than most C programs using explicit deallocation. Unlike manually
|
||||
introduced leaks, the amount of unreclaimed memory typically stays
|
||||
bounded.
|
||||
|
||||
In the following, an "object" is defined to be a region of memory allocated
|
||||
by the routines described below.
|
||||
|
||||
Any objects not intended to be collected must be pointed to either
|
||||
from other such accessible objects, or from the registers,
|
||||
stack, data, or statically allocated bss segments. Pointers from
|
||||
the stack or registers may point to anywhere inside an object.
|
||||
The same is true for heap pointers if the collector is compiled with
|
||||
ALL_INTERIOR_POINTERS defined, or GC_all_interior_pointers is otherwise
|
||||
set, as is now the default.
|
||||
|
||||
Compiling without ALL_INTERIOR_POINTERS may reduce accidental retention
|
||||
of garbage objects, by requiring pointers from the heap to to the beginning
|
||||
of an object. But this no longer appears to be a significant
|
||||
issue for most programs occupying a small fraction of the possible
|
||||
address space.
|
||||
|
||||
There are a number of routines which modify the pointer recognition
|
||||
algorithm. GC_register_displacement allows certain interior pointers
|
||||
to be recognized even if ALL_INTERIOR_POINTERS is nor defined.
|
||||
GC_malloc_ignore_off_page allows some pointers into the middle of large objects
|
||||
to be disregarded, greatly reducing the probablility of accidental
|
||||
retention of large objects. For most purposes it seems best to compile
|
||||
with ALL_INTERIOR_POINTERS and to use GC_malloc_ignore_off_page if
|
||||
you get collector warnings from allocations of very large objects.
|
||||
See README.debugging for details.
|
||||
|
||||
WARNING: pointers inside memory allocated by the standard "malloc" are not
|
||||
seen by the garbage collector. Thus objects pointed to only from such a
|
||||
region may be prematurely deallocated. It is thus suggested that the
|
||||
standard "malloc" be used only for memory regions, such as I/O buffers, that
|
||||
are guaranteed not to contain pointers to garbage collectable memory.
|
||||
Pointers in C language automatic, static, or register variables,
|
||||
are correctly recognized. (Note that GC_malloc_uncollectable has semantics
|
||||
similar to standard malloc, but allocates objects that are traced by the
|
||||
collector.)
|
||||
|
||||
WARNING: the collector does not always know how to find pointers in data
|
||||
areas that are associated with dynamic libraries. This is easy to
|
||||
remedy IF you know how to find those data areas on your operating
|
||||
system (see GC_add_roots). Code for doing this under SunOS, IRIX 5.X and 6.X,
|
||||
HP/UX, Alpha OSF/1, Linux, and win32 is included and used by default. (See
|
||||
README.win32 for win32 details.) On other systems pointers from dynamic
|
||||
library data areas may not be considered by the collector.
|
||||
If you're writing a program that depends on the collector scanning
|
||||
dynamic library data areas, it may be a good idea to include at least
|
||||
one call to GC_is_visible() to ensure that those areas are visible
|
||||
to the collector.
|
||||
|
||||
Note that the garbage collector does not need to be informed of shared
|
||||
read-only data. However if the shared library mechanism can introduce
|
||||
discontiguous data areas that may contain pointers, then the collector does
|
||||
need to be informed.
|
||||
|
||||
Signal processing for most signals may be deferred during collection,
|
||||
and during uninterruptible parts of the allocation process.
|
||||
Like standard ANSI C mallocs, by default it is unsafe to invoke
|
||||
malloc (and other GC routines) from a signal handler while another
|
||||
malloc call may be in progress. Removing -DNO_SIGNALS from Makefile
|
||||
attempts to remedy that. But that may not be reliable with a compiler that
|
||||
substantially reorders memory operations inside GC_malloc.
|
||||
|
||||
The allocator/collector can also be configured for thread-safe operation.
|
||||
(Full signal safety can also be achieved, but only at the cost of two system
|
||||
calls per malloc, which is usually unacceptable.)
|
||||
WARNING: the collector does not guarantee to scan thread-local storage
|
||||
(e.g. of the kind accessed with pthread_getspecific()). The collector
|
||||
does scan thread stacks, though, so generally the best solution is to
|
||||
ensure that any pointers stored in thread-local storage are also
|
||||
stored on the thread's stack for the duration of their lifetime.
|
||||
(This is arguably a longstanding bug, but it hasn't been fixed yet.)
|
||||
|
||||
INSTALLATION AND PORTABILITY
|
||||
|
||||
As distributed, the collector operates silently
|
||||
In the event of problems, this can usually be changed by defining the
|
||||
GC_PRINT_STATS or GC_PRINT_VERBOSE_STATS environment variables. This
|
||||
will result in a few lines of descriptive output for each collection.
|
||||
(The given statistics exhibit a few peculiarities.
|
||||
Things don't appear to add up for a variety of reasons, most notably
|
||||
fragmentation losses. These are probably much more significant for the
|
||||
contrived program "test.c" than for your application.)
|
||||
|
||||
On most Un*x-like platforms, the collector can be built either using a
|
||||
GNU autoconf-based build infrastructure (type "configure; make" in the
|
||||
simplest case), or with a classic makefile by itself (type
|
||||
"cp Makefile.direct Makefile; make"). Here we focus on the latter option.
|
||||
On other platforms, typically only the latter option is available, though
|
||||
with a different supplied Makefile.)
|
||||
|
||||
Typing "make test" nstead of "make" will automatically build the collector
|
||||
and then run setjmp_test and gctest. Setjmp_test will give you information
|
||||
about configuring the collector, which is useful primarily if you have
|
||||
a machine that's not already supported. Gctest is a somewhat superficial
|
||||
test of collector functionality. Failure is indicated by a core dump or
|
||||
a message to the effect that the collector is broken. Gctest takes about
|
||||
a second to two to run on reasonable 2007 vintage desktops.
|
||||
It may use up to about 30MB of memory. (The
|
||||
multi-threaded version will use more. 64-bit versions may use more.)
|
||||
"Make test" will also, as its last step, attempt to build and test the
|
||||
"cord" string library.)
|
||||
|
||||
The Makefile will generate a library gc.a which you should link against.
|
||||
Typing "make cords" will add the cord library to gc.a.
|
||||
Note that this requires an ANSI C compiler.
|
||||
|
||||
It is suggested that if you need to replace a piece of the collector
|
||||
(e.g. GC_mark_rts.c) you simply list your version ahead of gc.a on the
|
||||
ld command line, rather than replacing the one in gc.a. (This will
|
||||
generate numerous warnings under some versions of AIX, but it still
|
||||
works.)
|
||||
|
||||
All include files that need to be used by clients will be put in the
|
||||
include subdirectory. (Normally this is just gc.h. "Make cords" adds
|
||||
"cord.h" and "ec.h".)
|
||||
|
||||
The collector currently is designed to run essentially unmodified on
|
||||
machines that use a flat 32-bit or 64-bit address space.
|
||||
That includes the vast majority of Workstations and X86 (X >= 3) PCs.
|
||||
(The list here was deleted because it was getting too long and constantly
|
||||
out of date.)
|
||||
|
||||
In a few cases (Amiga, OS/2, Win32, MacOS) a separate makefile
|
||||
or equivalent is supplied. Many of these have separate README.system
|
||||
files.
|
||||
|
||||
Dynamic libraries are completely supported only under SunOS/Solaris,
|
||||
(and even that support is not functional on the last Sun 3 release),
|
||||
Linux, FreeBSD, NetBSD, IRIX 5&6, HP/UX, Win32 (not Win32S) and OSF/1
|
||||
on DEC AXP machines plus perhaps a few others listed near the top
|
||||
of dyn_load.c. On other machines we recommend that you do one of
|
||||
the following:
|
||||
|
||||
1) Add dynamic library support (and send us the code).
|
||||
2) Use static versions of the libraries.
|
||||
3) Arrange for dynamic libraries to use the standard malloc.
|
||||
This is still dangerous if the library stores a pointer to a
|
||||
garbage collected object. But nearly all standard interfaces
|
||||
prohibit this, because they deal correctly with pointers
|
||||
to stack allocated objects. (Strtok is an exception. Don't
|
||||
use it.)
|
||||
|
||||
In all cases we assume that pointer alignment is consistent with that
|
||||
enforced by the standard C compilers. If you use a nonstandard compiler
|
||||
you may have to adjust the alignment parameters defined in gc_priv.h.
|
||||
Note that this may also be an issue with packed records/structs, if those
|
||||
enforce less alignment for pointers.
|
||||
|
||||
A port to a machine that is not byte addressed, or does not use 32 bit
|
||||
or 64 bit addresses will require a major effort. A port to plain MSDOS
|
||||
or win16 is hard.
|
||||
|
||||
For machines not already mentioned, or for nonstandard compilers,
|
||||
some porting suggestions are provided in the "porting.html" file.
|
||||
|
||||
THE C INTERFACE TO THE ALLOCATOR
|
||||
|
||||
The following routines are intended to be directly called by the user.
|
||||
Note that usually only GC_malloc is necessary. GC_clear_roots and GC_add_roots
|
||||
calls may be required if the collector has to trace from nonstandard places
|
||||
(e.g. from dynamic library data areas on a machine on which the
|
||||
collector doesn't already understand them.) On some machines, it may
|
||||
be desirable to set GC_stacktop to a good approximation of the stack base.
|
||||
(This enhances code portability on HP PA machines, since there is no
|
||||
good way for the collector to compute this value.) Client code may include
|
||||
"gc.h", which defines all of the following, plus many others.
|
||||
|
||||
1) GC_malloc(nbytes)
|
||||
- allocate an object of size nbytes. Unlike malloc, the object is
|
||||
cleared before being returned to the user. Gc_malloc will
|
||||
invoke the garbage collector when it determines this to be appropriate.
|
||||
GC_malloc may return 0 if it is unable to acquire sufficient
|
||||
space from the operating system. This is the most probable
|
||||
consequence of running out of space. Other possible consequences
|
||||
are that a function call will fail due to lack of stack space,
|
||||
or that the collector will fail in other ways because it cannot
|
||||
maintain its internal data structures, or that a crucial system
|
||||
process will fail and take down the machine. Most of these
|
||||
possibilities are independent of the malloc implementation.
|
||||
|
||||
2) GC_malloc_atomic(nbytes)
|
||||
- allocate an object of size nbytes that is guaranteed not to contain any
|
||||
pointers. The returned object is not guaranteed to be cleared.
|
||||
(Can always be replaced by GC_malloc, but results in faster collection
|
||||
times. The collector will probably run faster if large character
|
||||
arrays, etc. are allocated with GC_malloc_atomic than if they are
|
||||
statically allocated.)
|
||||
|
||||
3) GC_realloc(object, new_size)
|
||||
- change the size of object to be new_size. Returns a pointer to the
|
||||
new object, which may, or may not, be the same as the pointer to
|
||||
the old object. The new object is taken to be atomic iff the old one
|
||||
was. If the new object is composite and larger than the original object,
|
||||
then the newly added bytes are cleared (we hope). This is very likely
|
||||
to allocate a new object, unless MERGE_SIZES is defined in gc_priv.h.
|
||||
Even then, it is likely to recycle the old object only if the object
|
||||
is grown in small additive increments (which, we claim, is generally bad
|
||||
coding practice.)
|
||||
|
||||
4) GC_free(object)
|
||||
- explicitly deallocate an object returned by GC_malloc or
|
||||
GC_malloc_atomic. Not necessary, but can be used to minimize
|
||||
collections if performance is critical. Probably a performance
|
||||
loss for very small objects (<= 8 bytes).
|
||||
|
||||
5) GC_expand_hp(bytes)
|
||||
- Explicitly increase the heap size. (This is normally done automatically
|
||||
if a garbage collection failed to GC_reclaim enough memory. Explicit
|
||||
calls to GC_expand_hp may prevent unnecessarily frequent collections at
|
||||
program startup.)
|
||||
|
||||
6) GC_malloc_ignore_off_page(bytes)
|
||||
- identical to GC_malloc, but the client promises to keep a pointer to
|
||||
the somewhere within the first 256 bytes of the object while it is
|
||||
live. (This pointer should nortmally be declared volatile to prevent
|
||||
interference from compiler optimizations.) This is the recommended
|
||||
way to allocate anything that is likely to be larger than 100Kbytes
|
||||
or so. (GC_malloc may result in failure to reclaim such objects.)
|
||||
|
||||
7) GC_set_warn_proc(proc)
|
||||
- Can be used to redirect warnings from the collector. Such warnings
|
||||
should be rare, and should not be ignored during code development.
|
||||
|
||||
8) GC_enable_incremental()
|
||||
- Enables generational and incremental collection. Useful for large
|
||||
heaps on machines that provide access to page dirty information.
|
||||
Some dirty bit implementations may interfere with debugging
|
||||
(by catching address faults) and place restrictions on heap arguments
|
||||
to system calls (since write faults inside a system call may not be
|
||||
handled well).
|
||||
|
||||
9) Several routines to allow for registration of finalization code.
|
||||
User supplied finalization code may be invoked when an object becomes
|
||||
unreachable. To call (*f)(obj, x) when obj becomes inaccessible, use
|
||||
GC_register_finalizer(obj, f, x, 0, 0);
|
||||
For more sophisticated uses, and for finalization ordering issues,
|
||||
see gc.h.
|
||||
|
||||
The global variable GC_free_space_divisor may be adjusted up from its
|
||||
default value of 4 to use less space and more collection time, or down for
|
||||
the opposite effect. Setting it to 1 or 0 will effectively disable collections
|
||||
and cause all allocations to simply grow the heap.
|
||||
|
||||
The variable GC_non_gc_bytes, which is normally 0, may be changed to reflect
|
||||
the amount of memory allocated by the above routines that should not be
|
||||
considered as a candidate for collection. Careless use may, of course, result
|
||||
in excessive memory consumption.
|
||||
|
||||
Some additional tuning is possible through the parameters defined
|
||||
near the top of gc_priv.h.
|
||||
|
||||
If only GC_malloc is intended to be used, it might be appropriate to define:
|
||||
|
||||
#define malloc(n) GC_malloc(n)
|
||||
#define calloc(m,n) GC_malloc((m)*(n))
|
||||
|
||||
For small pieces of VERY allocation intensive code, gc_inl.h
|
||||
includes some allocation macros that may be used in place of GC_malloc
|
||||
and friends.
|
||||
|
||||
All externally visible names in the garbage collector start with "GC_".
|
||||
To avoid name conflicts, client code should avoid this prefix, except when
|
||||
accessing garbage collector routines or variables.
|
||||
|
||||
There are provisions for allocation with explicit type information.
|
||||
This is rarely necessary. Details can be found in gc_typed.h.
|
||||
|
||||
THE C++ INTERFACE TO THE ALLOCATOR:
|
||||
|
||||
The Ellis-Hull C++ interface to the collector is included in
|
||||
the collector distribution. If you intend to use this, type
|
||||
"make c++" after the initial build of the collector is complete.
|
||||
See gc_cpp.h for the definition of the interface. This interface
|
||||
tries to approximate the Ellis-Detlefs C++ garbage collection
|
||||
proposal without compiler changes.
|
||||
|
||||
Very often it will also be necessary to use gc_allocator.h and the
|
||||
allocator declared there to construct STL data structures. Otherwise
|
||||
subobjects of STL data structures wil be allcoated using a system
|
||||
allocator, and objects they refer to may be prematurely collected.
|
||||
|
||||
USE AS LEAK DETECTOR:
|
||||
|
||||
The collector may be used to track down leaks in C programs that are
|
||||
intended to run with malloc/free (e.g. code with extreme real-time or
|
||||
portability constraints). To do so define FIND_LEAK in Makefile
|
||||
This will cause the collector to invoke the report_leak
|
||||
routine defined near the top of reclaim.c whenever an inaccessible
|
||||
object is found that has not been explicitly freed. Such objects will
|
||||
also be automatically reclaimed.
|
||||
If all objects are allocated with GC_DEBUG_MALLOC (see next section), then
|
||||
the default version of report_leak will report at least the source file and
|
||||
line number at which the leaked object was allocated. This may sometimes be
|
||||
sufficient. (On a few machines, it will also report a cryptic stack trace.
|
||||
If this is not symbolic, it can somethimes be called into a sympolic stack
|
||||
trace by invoking program "foo" with "callprocs foo". Callprocs is a short
|
||||
shell script that invokes adb to expand program counter values to symbolic
|
||||
addresses. It was largely supplied by Scott Schwartz.)
|
||||
Note that the debugging facilities described in the next section can
|
||||
sometimes be slightly LESS effective in leak finding mode, since in
|
||||
leak finding mode, GC_debug_free actually results in reuse of the object.
|
||||
(Otherwise the object is simply marked invalid.) Also note that the test
|
||||
program is not designed to run meaningfully in FIND_LEAK mode.
|
||||
Use "make gc.a" to build the collector.
|
||||
|
||||
DEBUGGING FACILITIES:
|
||||
|
||||
The routines GC_debug_malloc, GC_debug_malloc_atomic, GC_debug_realloc,
|
||||
and GC_debug_free provide an alternate interface to the collector, which
|
||||
provides some help with memory overwrite errors, and the like.
|
||||
Objects allocated in this way are annotated with additional
|
||||
information. Some of this information is checked during garbage
|
||||
collections, and detected inconsistencies are reported to stderr.
|
||||
|
||||
Simple cases of writing past the end of an allocated object should
|
||||
be caught if the object is explicitly deallocated, or if the
|
||||
collector is invoked while the object is live. The first deallocation
|
||||
of an object will clear the debugging info associated with an
|
||||
object, so accidentally repeated calls to GC_debug_free will report the
|
||||
deallocation of an object without debugging information. Out of
|
||||
memory errors will be reported to stderr, in addition to returning
|
||||
NIL.
|
||||
|
||||
GC_debug_malloc checking during garbage collection is enabled
|
||||
with the first call to GC_debug_malloc. This will result in some
|
||||
slowdown during collections. If frequent heap checks are desired,
|
||||
this can be achieved by explicitly invoking GC_gcollect, e.g. from
|
||||
the debugger.
|
||||
|
||||
GC_debug_malloc allocated objects should not be passed to GC_realloc
|
||||
or GC_free, and conversely. It is however acceptable to allocate only
|
||||
some objects with GC_debug_malloc, and to use GC_malloc for other objects,
|
||||
provided the two pools are kept distinct. In this case, there is a very
|
||||
low probablility that GC_malloc allocated objects may be misidentified as
|
||||
having been overwritten. This should happen with probability at most
|
||||
one in 2**32. This probability is zero if GC_debug_malloc is never called.
|
||||
|
||||
GC_debug_malloc, GC_malloc_atomic, and GC_debug_realloc take two
|
||||
additional trailing arguments, a string and an integer. These are not
|
||||
interpreted by the allocator. They are stored in the object (the string is
|
||||
not copied). If an error involving the object is detected, they are printed.
|
||||
|
||||
The macros GC_MALLOC, GC_MALLOC_ATOMIC, GC_REALLOC, GC_FREE, and
|
||||
GC_REGISTER_FINALIZER are also provided. These require the same arguments
|
||||
as the corresponding (nondebugging) routines. If gc.h is included
|
||||
with GC_DEBUG defined, they call the debugging versions of these
|
||||
functions, passing the current file name and line number as the two
|
||||
extra arguments, where appropriate. If gc.h is included without GC_DEBUG
|
||||
defined, then all these macros will instead be defined to their nondebugging
|
||||
equivalents. (GC_REGISTER_FINALIZER is necessary, since pointers to
|
||||
objects with debugging information are really pointers to a displacement
|
||||
of 16 bytes form the object beginning, and some translation is necessary
|
||||
when finalization routines are invoked. For details, about what's stored
|
||||
in the header, see the definition of the type oh in debug_malloc.c)
|
||||
|
||||
INCREMENTAL/GENERATIONAL COLLECTION:
|
||||
|
||||
The collector normally interrupts client code for the duration of
|
||||
a garbage collection mark phase. This may be unacceptable if interactive
|
||||
response is needed for programs with large heaps. The collector
|
||||
can also run in a "generational" mode, in which it usually attempts to
|
||||
collect only objects allocated since the last garbage collection.
|
||||
Furthermore, in this mode, garbage collections run mostly incrementally,
|
||||
with a small amount of work performed in response to each of a large number of
|
||||
GC_malloc requests.
|
||||
|
||||
This mode is enabled by a call to GC_enable_incremental().
|
||||
|
||||
Incremental and generational collection is effective in reducing
|
||||
pause times only if the collector has some way to tell which objects
|
||||
or pages have been recently modified. The collector uses two sources
|
||||
of information:
|
||||
|
||||
1. Information provided by the VM system. This may be provided in
|
||||
one of several forms. Under Solaris 2.X (and potentially under other
|
||||
similar systems) information on dirty pages can be read from the
|
||||
/proc file system. Under other systems (currently SunOS4.X) it is
|
||||
possible to write-protect the heap, and catch the resulting faults.
|
||||
On these systems we require that system calls writing to the heap
|
||||
(other than read) be handled specially by client code.
|
||||
See os_dep.c for details.
|
||||
|
||||
2. Information supplied by the programmer. We define "stubborn"
|
||||
objects to be objects that are rarely changed. Such an object
|
||||
can be allocated (and enabled for writing) with GC_malloc_stubborn.
|
||||
Once it has been initialized, the collector should be informed with
|
||||
a call to GC_end_stubborn_change. Subsequent writes that store
|
||||
pointers into the object must be preceded by a call to
|
||||
GC_change_stubborn.
|
||||
|
||||
This mechanism performs best for objects that are written only for
|
||||
initialization, and such that only one stubborn object is writable
|
||||
at once. It is typically not worth using for short-lived
|
||||
objects. Stubborn objects are treated less efficiently than pointerfree
|
||||
(atomic) objects.
|
||||
|
||||
A rough rule of thumb is that, in the absence of VM information, garbage
|
||||
collection pauses are proportional to the amount of pointerful storage
|
||||
plus the amount of modified "stubborn" storage that is reachable during
|
||||
the collection.
|
||||
|
||||
Initial allocation of stubborn objects takes longer than allocation
|
||||
of other objects, since other data structures need to be maintained.
|
||||
|
||||
We recommend against random use of stubborn objects in client
|
||||
code, since bugs caused by inappropriate writes to stubborn objects
|
||||
are likely to be very infrequently observed and hard to trace.
|
||||
However, their use may be appropriate in a few carefully written
|
||||
library routines that do not make the objects themselves available
|
||||
for writing by client code.
|
||||
|
||||
|
||||
BUGS:
|
||||
|
||||
Any memory that does not have a recognizable pointer to it will be
|
||||
reclaimed. Exclusive-or'ing forward and backward links in a list
|
||||
doesn't cut it.
|
||||
Some C optimizers may lose the last undisguised pointer to a memory
|
||||
object as a consequence of clever optimizations. This has almost
|
||||
never been observed in practice. Send mail to boehm@acm.org
|
||||
for suggestions on how to fix your compiler.
|
||||
This is not a real-time collector. In the standard configuration,
|
||||
percentage of time required for collection should be constant across
|
||||
heap sizes. But collection pauses will increase for larger heaps.
|
||||
They will decrease with the number of processors if parallel marking
|
||||
is enabled.
|
||||
(On 2007 vintage machines, GC times may be on the order of 5 msecs
|
||||
per MB of accessible memory that needs to be scanned and processor.
|
||||
Your mileage may vary.) The incremental/generational collection facility
|
||||
may help in some cases.
|
||||
Please address bug reports to boehm@acm.org. If you are
|
||||
contemplating a major addition, you might also send mail to ask whether
|
||||
it's already been done (or whether we tried and discarded it).
|
||||
|
||||
215
src/engine/boehm_gc/doc/README.DGUX386
Normal file
215
src/engine/boehm_gc/doc/README.DGUX386
Normal file
@@ -0,0 +1,215 @@
|
||||
Garbage Collector (parallel iversion) for ix86 DG/UX Release R4.20MU07
|
||||
|
||||
|
||||
*READ* the file README.QUICK.
|
||||
|
||||
You need the GCC-3.0.3 rev (DG/UX) compiler to build this tree.
|
||||
This compiler has the new "dgux386" threads package implemented.
|
||||
It also supports the switch "-pthread" needed to link correctly
|
||||
the DG/UX's -lrte -lthread with -lgcc and the system's -lc.
|
||||
Finally we support parralleli-mark for the SMP DG/UX machines.
|
||||
To build the garbage collector do:
|
||||
|
||||
./configure --enable-parallel-mark
|
||||
make
|
||||
make gctest
|
||||
|
||||
Before you run "gctest" you need to set your LD_LIBRARY_PATH
|
||||
correctly so that "gctest" can find the shared library libgc.
|
||||
Alternatively you can do a configuration
|
||||
|
||||
./configure --enable-parallel-mark --disable-shared
|
||||
|
||||
to build only the static version of libgc.
|
||||
|
||||
To enable debugging messages please do:
|
||||
1) Add the "--enable-full-debug" flag during configuration.
|
||||
2) Edit the file linux-threads.c and uncommnect the line:
|
||||
|
||||
/* #define DEBUG_THREADS 1 */ to --->
|
||||
|
||||
#define DEBUG_THREADS 1
|
||||
|
||||
Then give "make" as usual.
|
||||
|
||||
In a machine with 4 CPUs (my own machine) the option parallel
|
||||
mark (aka --enable-parallel-mark) makes a BIG difference.
|
||||
|
||||
Takis Psarogiannakopoulos
|
||||
University of Cambridge
|
||||
Centre for Mathematical Sciences
|
||||
Department of Pure Mathematics
|
||||
Wilberforce Road
|
||||
Cambridge CB3 0WB ,UK , <takis@XFree86.Org>
|
||||
January 2002
|
||||
|
||||
|
||||
Note (HB):
|
||||
The integration of this patch is currently not complete.
|
||||
The following patches against 6.1alpha3 where hard to move
|
||||
to alpha4, and are not integrated. There may also be minor
|
||||
problems with stylistic corrections made by me.
|
||||
|
||||
|
||||
--- ltconfig.ORIG Mon Jan 28 20:22:18 2002
|
||||
+++ ltconfig Mon Jan 28 20:44:00 2002
|
||||
@@ -689,6 +689,11 @@
|
||||
pic_flag=-Kconform_pic
|
||||
fi
|
||||
;;
|
||||
+ dgux*)
|
||||
+ pic_flag='-fPIC'
|
||||
+ link_static='-Bstatic'
|
||||
+ wl='-Wl,'
|
||||
+ ;;
|
||||
*)
|
||||
pic_flag='-fPIC'
|
||||
;;
|
||||
@@ -718,6 +723,12 @@
|
||||
# We can build DLLs from non-PIC.
|
||||
;;
|
||||
|
||||
+ dgux*)
|
||||
+ pic_flag='-KPIC'
|
||||
+ link_static='-Bstatic'
|
||||
+ wl='-Wl,'
|
||||
+ ;;
|
||||
+
|
||||
osf3* | osf4* | osf5*)
|
||||
# All OSF/1 code is PIC.
|
||||
wl='-Wl,'
|
||||
@@ -1154,6 +1165,22 @@
|
||||
fi
|
||||
;;
|
||||
|
||||
+ dgux*)
|
||||
+ ld_shlibs=yes
|
||||
+ # For both C/C++ ommit the deplibs. This is because we relying on the fact
|
||||
+ # that compilation of execitables will put them in correct order
|
||||
+ # in any case and sometimes are wrong when listed as deplibs (or missing some deplibs)
|
||||
+ # However when GNU ld and --whole-archive needs to be used we have the problem
|
||||
+ # that if the -fPIC *_s.a archive is linked through deplibs list we ommiting crucial
|
||||
+ # .lo/.o files from the created shared lib. This I think is not the case here.
|
||||
+ archive_cmds='$CC -shared -h $soname -o $lib $libobjs $linkopts'
|
||||
+ thread_safe_flag_spec='-pthread'
|
||||
+ wlarc=
|
||||
+ hardcode_libdir_flag_spec='-L$libdir'
|
||||
+ hardcode_shlibpath_var=no
|
||||
+ ac_cv_archive_cmds_needs_lc=no
|
||||
+ ;;
|
||||
+
|
||||
cygwin* | mingw*)
|
||||
# hardcode_libdir_flag_spec is actually meaningless, as there is
|
||||
# no search path for DLLs.
|
||||
@@ -1497,7 +1524,7 @@
|
||||
;;
|
||||
|
||||
dgux*)
|
||||
- archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linkopts'
|
||||
+ archive_cmds='$CC -shared -h $soname -o $lib $libobjs $linkopts'
|
||||
hardcode_libdir_flag_spec='-L$libdir'
|
||||
hardcode_shlibpath_var=no
|
||||
;;
|
||||
@@ -2092,12 +2119,17 @@
|
||||
;;
|
||||
|
||||
dgux*)
|
||||
- version_type=linux
|
||||
+ version_type=dgux
|
||||
need_lib_prefix=no
|
||||
need_version=no
|
||||
- library_names_spec='${libname}${release}.so$versuffix ${libname}${release}.so$major $libname.so'
|
||||
- soname_spec='${libname}${release}.so$major'
|
||||
+ library_names_spec='$libname.so$versuffix'
|
||||
+ soname_spec='$libname.so$versuffix'
|
||||
shlibpath_var=LD_LIBRARY_PATH
|
||||
+ thread_safe_flag_spec='-pthread'
|
||||
+ wlarc=
|
||||
+ hardcode_libdir_flag_spec='-L$libdir'
|
||||
+ hardcode_shlibpath_var=no
|
||||
+ ac_cv_archive_cmds_needs_lc=no
|
||||
;;
|
||||
|
||||
sysv4*MP*)
|
||||
|
||||
|
||||
--- ltmain.sh.ORIG Mon Jan 28 20:31:18 2002
|
||||
+++ ltmain.sh Tue Jan 29 00:11:29 2002
|
||||
@@ -1072,11 +1072,38 @@
|
||||
esac
|
||||
;;
|
||||
|
||||
+ -thread*)
|
||||
+ # DG/UX GCC 2.95.x, 3.x.x rev (DG/UX) links -lthread
|
||||
+ # with the switch -threads
|
||||
+ if test "$arg" = "-threads"; then
|
||||
+ case "$host" in
|
||||
+ i[3456]86-*-dgux*)
|
||||
+ deplibs="$deplibs $arg"
|
||||
+ continue
|
||||
+ ;;
|
||||
+ esac
|
||||
+ fi
|
||||
+ ;;
|
||||
+
|
||||
+ -pthread*)
|
||||
+ # DG/UX GCC 2.95.x, 3.x.x rev (DG/UX) links -lthread
|
||||
+ # with the switch -pthread
|
||||
+ if test "$arg" = "-pthread"; then
|
||||
+ case "$host" in
|
||||
+ i[3456]86-*-dgux*)
|
||||
+ deplibs="$deplibs $arg"
|
||||
+ continue
|
||||
+ ;;
|
||||
+ esac
|
||||
+ fi
|
||||
+ ;;
|
||||
+
|
||||
-l*)
|
||||
if test "$arg" = "-lc"; then
|
||||
case "$host" in
|
||||
- *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
|
||||
+ *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos* | i[3456]86-*-dgux*)
|
||||
# These systems don't actually have c library (as such)
|
||||
+ # It is wrong in DG/UX to add -lc when creating shared/dynamic objs/libs
|
||||
continue
|
||||
;;
|
||||
esac
|
||||
@@ -1248,6 +1275,12 @@
|
||||
temp_deplibs=
|
||||
for deplib in $dependency_libs; do
|
||||
case "$deplib" in
|
||||
+ -thread*)
|
||||
+ temp_deplibs="$temp_deplibs $deplib"
|
||||
+ ;;
|
||||
+ -pthread)
|
||||
+ temp_deplibs="$temp_deplibs $deplib"
|
||||
+ ;;
|
||||
-R*) temp_xrpath=`$echo "X$deplib" | $Xsed -e 's/^-R//'`
|
||||
case " $rpath $xrpath " in
|
||||
*" $temp_xrpath "*) ;;
|
||||
@@ -1709,6 +1742,13 @@
|
||||
done
|
||||
;;
|
||||
|
||||
+ dgux)
|
||||
+ # Leave mostly blank for DG/UX
|
||||
+ major=
|
||||
+ versuffix=".$current.$revision";
|
||||
+ verstring=
|
||||
+ ;;
|
||||
+
|
||||
linux)
|
||||
major=.`expr $current - $age`
|
||||
versuffix="$major.$age.$revision"
|
||||
@@ -1792,8 +1832,9 @@
|
||||
|
||||
dependency_libs="$deplibs"
|
||||
case "$host" in
|
||||
- *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos*)
|
||||
+ *-*-cygwin* | *-*-mingw* | *-*-os2* | *-*-beos* | i[3456]86-*-dgux*)
|
||||
# these systems don't actually have a c library (as such)!
|
||||
+ # It is wrong in DG/UX to add -lc when creating shared/dynamic objs/libs
|
||||
;;
|
||||
*)
|
||||
# Add libc to deplibs on all other systems.
|
||||
390
src/engine/boehm_gc/doc/README.Mac
Normal file
390
src/engine/boehm_gc/doc/README.Mac
Normal file
@@ -0,0 +1,390 @@
|
||||
The contents of this file are old and pertain to pre-MacOSX versions.
|
||||
You probably really wanted README.darwin.
|
||||
|
||||
---------------------------------------------
|
||||
|
||||
Patrick Beard's Notes for building GC v4.12 with CodeWarrior Pro 2:
|
||||
----------------------------------------------------------------------------
|
||||
The current build environment for the collector is CodeWarrior Pro 2.
|
||||
Projects for CodeWarrior Pro 2 (and for quite a few older versions)
|
||||
are distributed in the file Mac_projects.sit.hqx. The project file
|
||||
:Mac_projects:gc.prj builds static library versions of the collector.
|
||||
:Mac_projects:gctest.prj builds the GC test suite.
|
||||
|
||||
Configuring the collector is still done by editing the files
|
||||
:Mac_files:MacOS_config.h and :Mac_files:MacOS_Test_config.h.
|
||||
|
||||
Lars Farm's suggestions on building the collector:
|
||||
----------------------------------------------------------------------------
|
||||
Garbage Collection on MacOS - a manual 'MakeFile'
|
||||
-------------------------------------------------
|
||||
|
||||
Project files and IDE's are great on the Macintosh, but they do have
|
||||
problems when used as distribution media. This note tries to provide
|
||||
porting instructions in pure TEXT form to avoid those problems. A manual
|
||||
'makefile' if you like.
|
||||
|
||||
GC version: 4.12a2
|
||||
Codewarrior: CWPro1
|
||||
date: 18 July 1997
|
||||
|
||||
The notes may or may not apply to earlier or later versions of the
|
||||
GC/CWPro. Actually, they do apply to earlier versions of both except that
|
||||
until recently a project could only build one target so each target was a
|
||||
separate project. The notes will most likely apply to future versions too.
|
||||
Possibly with minor tweaks.
|
||||
|
||||
This is just to record my experiences. These notes do not mean I now
|
||||
provide a supported port of the GC to MacOS. It works for me. If it works
|
||||
for you, great. If it doesn't, sorry, try again...;-) Still, if you find
|
||||
errors, please let me know.
|
||||
|
||||
mailto: lars.farm@ite.mh.se
|
||||
|
||||
address: Lars Farm
|
||||
Krönvägen 33b
|
||||
856 44 Sundsvall
|
||||
Sweden
|
||||
|
||||
Porting to MacOS is a bit more complex than it first seems. Which MacOS?
|
||||
68K/PowerPC? Which compiler? Each supports both 68K and PowerPC and offer a
|
||||
large number of (unique to each environment) compiler settings. Each
|
||||
combination of compiler/68K/PPC/settings require a unique combination of
|
||||
standard libraries. And the IDE's does not select them for you. They don't
|
||||
even check that the library is built with compatible setting and this is
|
||||
the major source of problems when porting the GC (and otherwise too).
|
||||
|
||||
You will have to make choices when you configure the GC. I've made some
|
||||
choices here, but there are other combinations of settings and #defines
|
||||
that work too.
|
||||
|
||||
As for target settings the major obstacles may be:
|
||||
- 68K Processor: check "4-byte Ints".
|
||||
- PPC Processor: uncheck "Store Static Data in TOC".
|
||||
|
||||
What you need to do:
|
||||
===================
|
||||
|
||||
1) Build the GC as a library
|
||||
2) Test that the library works with 'test.c'.
|
||||
3) Test that the C++ interface 'gc_cpp.cc/h' works with 'test_cpp.cc'.
|
||||
|
||||
1) The Libraries:
|
||||
=================
|
||||
I made one project with four targets (68K/PPC tempmem or appheap). One target
|
||||
will suffice if you're able to decide which one you want. I wasn't...
|
||||
|
||||
Codewarrior allows a large number of compiler/linker settings. I used these:
|
||||
|
||||
Settings shared by all targets:
|
||||
------------------------------
|
||||
o Access Paths:
|
||||
- User Paths: the GC folder
|
||||
- System Paths: {Compiler}:Metrowerks Standard Library:
|
||||
{Compiler}:MacOS Support:Headers:
|
||||
{Compiler}:MacOS Support:MacHeaders:
|
||||
o C/C++ language:
|
||||
- inlining: normal
|
||||
- direct to SOM: off
|
||||
- enable/check: exceptions, RTTI, bool (and if you like pool strings)
|
||||
|
||||
PowerPC target settings
|
||||
-----------------------
|
||||
o Target Settings:
|
||||
- name of target
|
||||
- MacOS PPC Linker
|
||||
o PPC Target
|
||||
- name of library
|
||||
o C/C++ language
|
||||
- prefix file as described below
|
||||
o PPC Processor
|
||||
- Struct Alignment: PowerPC
|
||||
- uncheck "Store Static Data in TOC" -- important!
|
||||
I don't think the others matter, I use full optimization and its ok
|
||||
o PPC Linker
|
||||
- Factory Settings (SYM file with full paths, faster linking, dead-strip
|
||||
static init, Main: __start)
|
||||
|
||||
|
||||
68K target settings
|
||||
-------------------
|
||||
o Target Settings:
|
||||
- name of target
|
||||
- MacOS 68K Linker
|
||||
o 68K Target
|
||||
- name of library
|
||||
- A5 relative data
|
||||
o C/C++ language
|
||||
- prefix file as described below
|
||||
o 68K Processor
|
||||
- Code model: smart
|
||||
- Struct alignment: 68K
|
||||
- FP: SANE
|
||||
- enable 4-Byte Ints -- important!
|
||||
I don't think the others matter. I selected...
|
||||
- enable: 68020
|
||||
- enable: global register allocation
|
||||
o IR Optimizer
|
||||
- enable: Optimize Space, Optimize Speed
|
||||
I suppose the others would work too, but haven't tried...
|
||||
o 68K Linker
|
||||
- Factory Settings (New Style MacsBug,SYM file with full paths,
|
||||
A6 Frames, fast link, Merge compiler glue into segment 1,
|
||||
dead-strip static init)
|
||||
|
||||
Prefix Files to configure the GC sources
|
||||
----------------------------------------
|
||||
The Codewarrior equivalent of commandline compilers -DNAME=X is to use
|
||||
prefix-files. A TEXT file that is automatically #included before the first byte
|
||||
of every source file. I used these:
|
||||
|
||||
---- ( cut here ) ---- gc_prefix_tempmem.h -- 68K and PPC -----
|
||||
#include "gc_prefix_common.h"
|
||||
#undef USE_TEMPORARY_MEMORY
|
||||
#define USE_TEMPORARY_MEMORY
|
||||
---- ( cut here ) ---- gc_prefix_appmem.h -- 68K and PPC -----
|
||||
#include "gc_prefix_common.h"
|
||||
#undef USE_TEMPORARY_MEMORY
|
||||
// #define USE_TEMPORARY_MEMORY
|
||||
|
||||
---- ( cut here ) ---- gc_prefix_common.h --------------------
|
||||
// gc_prefix_common.h
|
||||
// ------------------
|
||||
// Codewarrior prefix file to configure the GC libraries
|
||||
//
|
||||
// prefix files are the Codewarrior equivalent of the
|
||||
// command line option -Dname=x frequently seen in makefiles
|
||||
|
||||
#if !__MWERKS__
|
||||
#error only tried this with Codewarrior
|
||||
#endif
|
||||
|
||||
#if macintosh
|
||||
#define MSL_USE_PRECOMPILED_HEADERS 0
|
||||
#include <ansi_prefix.mac.h>
|
||||
#ifndef __STDC__
|
||||
#define __STDC__ 0
|
||||
#endif
|
||||
|
||||
// See list of #defines to configure the library in: 'MakeFile'
|
||||
// see also README
|
||||
|
||||
#define SILENT // no collection messages. In case
|
||||
// of trouble you might want this off
|
||||
#define ALL_INTERIOR_POINTERS // follows interior pointers.
|
||||
//#define DONT_ADD_BYTE_AT_END // disables the padding if defined.
|
||||
//#define SMALL_CONFIG // whether to use a smaller heap.
|
||||
#define NO_SIGNALS // signals aren't real on the Macintosh.
|
||||
#define ATOMIC_UNCOLLECTABLE // GC_malloc_atomic_uncollectable()
|
||||
|
||||
// define either or none as per personal preference
|
||||
// used in malloc.c
|
||||
#define REDIRECT_MALLOC GC_malloc
|
||||
//#define REDIRECT_MALLOC GC_malloc_uncollectable
|
||||
// if REDIRECT_MALLOC is #defined make sure that the GC library
|
||||
// is listed before the ANSI/ISO libs in the Codewarrior
|
||||
// 'Link order' panel
|
||||
//#define IGNORE_FREE
|
||||
|
||||
// mac specific configs
|
||||
//#define USE_TEMPORARY_MEMORY // use Macintosh temporary memory.
|
||||
//#define SHARED_LIBRARY_BUILD // build for use in a shared library.
|
||||
|
||||
#else
|
||||
// could build Win32 here too, or in the future
|
||||
// Rhapsody PPC-mach, Rhapsody PPC-MacOS,
|
||||
// Rhapsody Intel-mach, Rhapsody Intel-Win32,...
|
||||
// ... ugh this will get messy ...
|
||||
#endif
|
||||
|
||||
// make sure ints are at least 32-bit
|
||||
// ( could be set to 16-bit by compiler settings (68K) )
|
||||
|
||||
struct gc_private_assert_intsize_{ char x[ sizeof(int)>=4 ? 1 : 0 ]; };
|
||||
|
||||
#if __powerc
|
||||
#if __option(toc_data)
|
||||
#error turn off "store static data in TOC" when using GC
|
||||
// ... or find a way to add TOC to the root set...(?)
|
||||
#endif
|
||||
#endif
|
||||
---- ( cut here ) ---- end of gc_prefix_common.h -----------------
|
||||
|
||||
Files to build the GC libraries:
|
||||
--------------------------------
|
||||
allchblk.c
|
||||
alloc.c
|
||||
blacklst.c
|
||||
checksums.c
|
||||
dbg_mlc.c
|
||||
finalize.c
|
||||
headers.c
|
||||
mach_dep.c
|
||||
MacOS.c -- contains MacOS code
|
||||
malloc.c
|
||||
mallocx.c
|
||||
mark.c
|
||||
mark_rts.c
|
||||
misc.c
|
||||
new_hblk.c
|
||||
obj_map.c
|
||||
os_dep.c -- contains MacOS code
|
||||
ptr_chck.c
|
||||
reclaim.c
|
||||
stubborn.c
|
||||
typd_mlc.c
|
||||
gc++.cc -- this is 'gc_cpp.cc' with less 'inline' and
|
||||
-- throw std::bad_alloc when out of memory
|
||||
-- gc_cpp.cc works just fine too
|
||||
|
||||
2) Test that the library works with 'test.c'.
|
||||
=============================================
|
||||
|
||||
The test app is just an ordinary ANSI-C console app. Make sure settings
|
||||
match the library you're testing.
|
||||
|
||||
Files
|
||||
-----
|
||||
test.c
|
||||
the GC library to test -- link order before ANSI libs
|
||||
suitable Mac+ANSI libraries
|
||||
|
||||
prefix:
|
||||
------
|
||||
---- ( cut here ) ---- gc_prefix_testlib.h -- all libs -----
|
||||
#define MSL_USE_PRECOMPILED_HEADERS 0
|
||||
#include <ansi_prefix.mac.h>
|
||||
#undef NDEBUG
|
||||
|
||||
#define ALL_INTERIOR_POINTERS /* for GC_priv.h */
|
||||
---- ( cut here ) ----
|
||||
|
||||
3) Test that the C++ interface 'gc_cpp.cc/h' works with 'test_cpp.cc'.
|
||||
|
||||
The test app is just an ordinary ANSI-C console app. Make sure settings match
|
||||
the library you're testing.
|
||||
|
||||
Files
|
||||
-----
|
||||
test_cpp.cc
|
||||
the GC library to test -- link order before ANSI libs
|
||||
suitable Mac+ANSI libraries
|
||||
|
||||
prefix:
|
||||
------
|
||||
same as for test.c
|
||||
|
||||
For convenience I used one test-project with several targets so that all
|
||||
test apps are build at once. Two for each library to test: test.c and
|
||||
gc_app.cc. When I was satisfied that the libraries were ok. I put the
|
||||
libraries + gc.h + the c++ interface-file in a folder that I then put into
|
||||
the MSL hierarchy so that I don't have to alter access-paths in projects
|
||||
that use the GC.
|
||||
|
||||
After that, just add the proper GC library to your project and the GC is in
|
||||
action! malloc will call GC_malloc and free GC_free, new/delete too. You
|
||||
don't have to call free or delete. You may have to be a bit cautious about
|
||||
delete if you're freeing other resources than RAM. See gc_cpp.h. You can
|
||||
also keep coding as always with delete/free. That works too. If you want,
|
||||
"include <gc.h> and tweak it's use a bit.
|
||||
|
||||
Symantec SPM
|
||||
============
|
||||
It has been a while since I tried the GC in SPM, but I think that the above
|
||||
instructions should be sufficient to guide you through in SPM too. SPM
|
||||
needs to know where the global data is. Use the files 'datastart.c' and
|
||||
'dataend.c'. Put 'datastart.c' at the top of your project and 'dataend.c'
|
||||
at the bottom of your project so that all data is surrounded. This is not
|
||||
needed in Codewarrior because it provides intrinsic variables
|
||||
__datastart__, __data_end__ that wraps all globals.
|
||||
|
||||
Source Changes (GC 4.12a2)
|
||||
==========================
|
||||
Very few. Just one tiny in the GC, not strictly needed.
|
||||
- MacOS.c line 131 in routine GC_MacFreeTemporaryMemory()
|
||||
change # if !defined(SHARED_LIBRARY_BUILD)
|
||||
to # if !defined(SILENT) && !defined(SHARED_LIBRARY_BUILD)
|
||||
To turn off a message when the application quits (actually, I faked
|
||||
this change by #defining SHARED_LIBRARY_BUILD in a statically linked
|
||||
library for more than a year without ill effects but perhaps this is
|
||||
better).
|
||||
|
||||
- test_cpp.cc
|
||||
made the first lines of main() look like this:
|
||||
------------
|
||||
int main( int argc, char* argv[] ) {
|
||||
#endif
|
||||
#if macintosh // MacOS
|
||||
char* argv_[] = {"test_cpp","10"}; // doesn't
|
||||
argv=argv_; // have a
|
||||
argc = sizeof(argv_)/sizeof(argv_[0]); // commandline
|
||||
#endif //
|
||||
|
||||
int i, iters, n;
|
||||
# ifndef __GNUC__
|
||||
alloc dummy_to_fool_the_compiler_into_doing_things_it_currently_cant_handle;
|
||||
------------
|
||||
|
||||
- config.h [now gcconfig.h]
|
||||
__MWERKS__ does not have to mean MACOS. You can use Codewarrior to
|
||||
build a Win32 or BeOS library and soon a Rhapsody library. You may
|
||||
have to change that #if...
|
||||
|
||||
|
||||
|
||||
It worked for me, hope it works for you.
|
||||
|
||||
Lars Farm
|
||||
18 July 1997
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
|
||||
Patrick Beard's instructions (may be dated):
|
||||
|
||||
v4.3 of the collector now runs under Symantec C++/THINK C v7.0.4, and
|
||||
Metrowerks C/C++ v4.5 both 68K and PowerPC. Project files are provided
|
||||
to build and test the collector under both development systems.
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
To configure the collector, under both development systems, a prefix file
|
||||
is used to set preprocessor directives. This file is called "MacOS_config.h".
|
||||
Also to test the collector, "MacOS_Test_config.h" is provided.
|
||||
|
||||
Testing
|
||||
-------
|
||||
|
||||
To test the collector (always a good idea), build one of the gctest projects,
|
||||
gctest.¹ (Symantec C++/THINK C), mw/gctest.68K.¹, or mw/gctest.PPC.¹. The
|
||||
test will ask you how many times to run; 1 should be sufficient.
|
||||
|
||||
Building
|
||||
--------
|
||||
|
||||
For your convenience project files for the major Macintosh development
|
||||
systems are provided.
|
||||
|
||||
For Symantec C++/THINK C, you must build the two projects gclib-1.¹ and
|
||||
gclib-2.¹. It has to be split up because the collector has more than 32k
|
||||
of static data and no library can have more than this in the Symantec
|
||||
environment. (Future versions will probably fix this.)
|
||||
|
||||
For Metrowerks C/C++ 4.5 you build gc.68K.¹/gc.PPC.¹ and the result will
|
||||
be a library called gc.68K.lib/gc.PPC.lib.
|
||||
|
||||
Using
|
||||
-----
|
||||
|
||||
Under Symantec C++/THINK C, you can just add the gclib-1.¹ and gclib-2.¹
|
||||
projects to your own project. Under Metrowerks, you add gc.68K.lib or
|
||||
gc.PPC.lib and two additional files. You add the files called datastart.c
|
||||
and dataend.c to your project, bracketing all files that use the collector.
|
||||
See mw/gctest.¹ for an example.
|
||||
|
||||
Include the projects/libraries you built above into your own project,
|
||||
#include "gc.h", and call GC_malloc. You don't have to call GC_free.
|
||||
|
||||
|
||||
Patrick C. Beard
|
||||
January 4, 1995
|
||||
1
src/engine/boehm_gc/doc/README.MacOSX
Normal file
1
src/engine/boehm_gc/doc/README.MacOSX
Normal file
@@ -0,0 +1 @@
|
||||
See README.darwin for the latest Darwin/MacOSX information.
|
||||
6
src/engine/boehm_gc/doc/README.OS2
Normal file
6
src/engine/boehm_gc/doc/README.OS2
Normal file
@@ -0,0 +1,6 @@
|
||||
The code assumes static linking, and a single thread. The editor de has
|
||||
not been ported. The cord test program has. The supplied OS2_MAKEFILE
|
||||
assumes the IBM C Set/2 environment, but the code shouldn't.
|
||||
|
||||
Since we haven't figured out hoe to do perform partial links or to build static
|
||||
libraries, clients currently need to link against a long list of executables.
|
||||
322
src/engine/boehm_gc/doc/README.amiga
Normal file
322
src/engine/boehm_gc/doc/README.amiga
Normal file
@@ -0,0 +1,322 @@
|
||||
===========================================================================
|
||||
Kjetil S. Matheussen's notes (28-11-2000)
|
||||
===========================================================================
|
||||
Compiles under SAS/C again. Should allso still compile under other
|
||||
amiga compilers without big changes. I haven't checked if it still
|
||||
works under gcc, because I don't have gcc for amiga. But I have
|
||||
updated 'Makefile', and hope it compiles fine.
|
||||
|
||||
|
||||
WHATS NEW:
|
||||
|
||||
1.
|
||||
Made a pretty big effort in preventing GCs allocating-functions from returning
|
||||
chip-mem.
|
||||
|
||||
The lower part of the new file AmigaOS.c does this in various ways, mainly by
|
||||
wrapping GC_malloc, GC_malloc_atomic, GC_malloc_uncollectable,
|
||||
GC_malloc_atomic_uncollectable, GC_malloc_stubborn, GC_malloc_ignore_off_page
|
||||
and GC_malloc_atomic_ignore_off_page. GC_realloc is allso wrapped, but
|
||||
doesn't do the same effort in preventing to return chip-mem.
|
||||
Other allocating-functions (f.ex. GC_*_typed_) can probably be
|
||||
used without any problems, but beware that the warn hook will not be called.
|
||||
In case of problems, don't define GC_AMIGA_FASTALLOC.
|
||||
|
||||
Programs using more time actually using the memory allocated
|
||||
(instead of just allocate and free rapidly) have
|
||||
the most to earn on this, but even gctest now normally runs twice
|
||||
as fast and uses less memory, on my poor 8MB machine.
|
||||
|
||||
The changes have only effect when there is no more
|
||||
fast-mem left. But with the way GC works, it
|
||||
could happen quite often. Beware that an atexit handler had to be added,
|
||||
so using the abort() function will make a big memory-loss.
|
||||
If you absolutely must call abort() instead of exit(), try calling
|
||||
the GC_amiga_free_all_mem function before abort().
|
||||
|
||||
New amiga-spesific compilation flags:
|
||||
|
||||
GC_AMIGA_FASTALLOC - By NOT defining this option, GC will work like before,
|
||||
it will not try to force fast-mem out of the OS, and
|
||||
it will use normal calloc for allocation, and the rest
|
||||
of the following flags will have no effect.
|
||||
|
||||
GC_AMIGA_ONLYFAST - Makes GC never to return chip-mem. GC_AMIGA_RETRY have
|
||||
no effect if this flag is set.
|
||||
|
||||
GC_AMIGA_GC - If gc returns NULL, do a GC_gcollect, and try again. This
|
||||
usually is a success with the standard GC configuration.
|
||||
It is allso the most important flag to set to prevent
|
||||
GC from returning chip-mem. Beware that it slows down a lot
|
||||
when a program is rapidly allocating/deallocating when
|
||||
theres either very little fast-memory left or verly little
|
||||
chip-memory left. Its not a very common situation, but gctest
|
||||
sometimes (very rare) use many minutes because of this.
|
||||
|
||||
GC_AMIGA_RETRY - If gc succeed allocating memory, but it is chip-mem,
|
||||
try again and see if it is fast-mem. Most of the time,
|
||||
it will actually return fast-mem for the second try.
|
||||
I have set max number of retries to 9 or size/5000. You
|
||||
can change this if you like. (see GC_amiga_rec_alloc())
|
||||
|
||||
GC_AMIGA_PRINTSTATS - Gather some statistics during the execution of a
|
||||
program, and prints out the info when the atexit-handler
|
||||
is called.
|
||||
|
||||
My reccomendation is to set all this flags, except GC_AMIGA_PRINTSTATS and
|
||||
GC_AMIGA_ONLYFAST.
|
||||
|
||||
If your program demands high response-time, you should
|
||||
not define GC_AMIGA_GC, and possible allso define GC_AMIGA_ONLYFAST.
|
||||
GC_AMIGA_RETRY does not seem to slow down much.
|
||||
|
||||
Allso, when compiling up programs, and GC_AMIGA_FASTALLOC was not defined when
|
||||
compilling gc, you can define GC_AMIGA_MAKINGLIB to avoid having these allocation-
|
||||
functions wrapped. (see gc.h)
|
||||
|
||||
Note that GC_realloc must not be called before any of
|
||||
the other above mentioned allocating-functions have been called. (shouldn't be
|
||||
any programs doing so either, I hope).
|
||||
|
||||
Another note. The allocation-function is wrapped when defining
|
||||
GC_AMIGA_FASTALLOC by letting the function go thru the new
|
||||
GC_amiga_allocwrapper_do function-pointer (see gc.h). Means that
|
||||
sending function-pointers, such as GC_malloc, GC_malloc_atomic, etc.,
|
||||
for later to be called like f.ex this, (*GC_malloc_functionpointer)(size),
|
||||
will not wrap the function. This is normally not a big problem, unless
|
||||
all allocation function is called like this, which will cause the
|
||||
atexit un-allocating function never to be called. Then you either
|
||||
have to manually add the atexit handler, or call the allocation-
|
||||
functions function-pointer functions like this;
|
||||
(*GC_amiga_allocwrapper_do)(size,GC_malloc_functionpointer).
|
||||
There are probably better ways this problem could be handled, unfortunately,
|
||||
I didn't find any without rewriting or replacing a lot of the GC-code, which
|
||||
I really didn't want to. (Making new GC_malloc_* functions, and just
|
||||
define f.ex GC_malloc as GC_amiga_malloc should allso work).
|
||||
|
||||
|
||||
New amiga-spesific function:
|
||||
|
||||
void GC_amiga_set_toany(void (*func)(void));
|
||||
|
||||
'func' is a function that will be called right before gc has to change
|
||||
allocation-method from MEMF_FAST to MEMF_ANY. Ie. when it is likely
|
||||
it will return chip-mem.
|
||||
|
||||
|
||||
2. A few small compiler-spesific additions to make it compile with SAS/C again.
|
||||
|
||||
3. Updated and rewritten the smakefile, so that it works again and that
|
||||
the "unnecesarry" 'SCOPTIONS' files could be removed. Allso included
|
||||
the cord-smakefile stuff in the main smakefile, so that the cord smakefile
|
||||
could be removed too. By writing smake -f Smakefile.smk, both gc.lib and
|
||||
cord.lib will be made.
|
||||
|
||||
|
||||
|
||||
STILL MISSING:
|
||||
|
||||
Programs can not be started from workbench, at least not for SAS/C. (Martin
|
||||
Tauchmanns note about that it now works with workbench is definitely wrong
|
||||
when concerning SAS/C). I guess it works if you use the old "#if 0'ed"-code,
|
||||
but I haven't tested it. I think the reason for MT to replace the
|
||||
"#if 0'ed"-code was only because it was a bit to SAS/C-spesific. But I
|
||||
don't know. An iconx-script solves this problem anyway.
|
||||
|
||||
|
||||
BEWARE!
|
||||
|
||||
-To run gctest, set the stack to around 200000 bytes first.
|
||||
-SAS/C-spesific: cord will crash if you compile gc.lib with
|
||||
either parm=reg or parm=both. (missing legal prototypes for
|
||||
function-pointers someplace is the reason I guess.).
|
||||
|
||||
|
||||
tested with software: Radium, http://www.stud.ifi.uio.no/~ksvalast/radium/
|
||||
|
||||
tested with hardware: MC68060
|
||||
|
||||
|
||||
-ksvalast@ifi.uio.no
|
||||
|
||||
|
||||
===========================================================================
|
||||
Martin Tauchmann's notes (1-Apr-99)
|
||||
===========================================================================
|
||||
|
||||
Works now, also with the GNU-C compiler V2.7.2.1. <ftp://ftp.unina.it/pub/amiga/geekgadgets/amiga/m68k/snapshots/971125/amiga-bin/>
|
||||
Modify the `Makefile`
|
||||
CC=cc $(ABI_FLAG)
|
||||
to
|
||||
CC=gcc $(ABI_FLAG)
|
||||
|
||||
TECHNICAL NOTES
|
||||
|
||||
- `GC_get_stack_base()`, `GC_register_data_segments()` works now with every
|
||||
C compiler; also Workbench.
|
||||
|
||||
- Removed AMIGA_SKIP_SEG, but the Code-Segment must not be scanned by GC.
|
||||
|
||||
|
||||
PROBLEMS
|
||||
- When the Linker, does`t merge all Code-Segments to an single one. LD of GCC
|
||||
do it always.
|
||||
|
||||
- With ixemul.library V47.3, when an GC program launched from another program
|
||||
(example: `Make` or `if_mach M68K AMIGA gctest`), `GC_register_data_segments()`
|
||||
found the Segment-List of the caller program.
|
||||
Can be fixed, if the run-time initialization code (for C programs, usually *crt0*)
|
||||
support `__data` and `__bss`.
|
||||
|
||||
- PowerPC Amiga currently not supported.
|
||||
|
||||
- Dynamic libraries (dyn_load.c) not supported.
|
||||
|
||||
|
||||
TESTED WITH SOFTWARE
|
||||
|
||||
`Optimized Oberon 2 C` (oo2c) <http://cognac.informatik.uni-kl.de/download/index.html>
|
||||
|
||||
|
||||
TESTED WITH HARDWARE
|
||||
|
||||
MC68030
|
||||
|
||||
|
||||
CONTACT
|
||||
|
||||
Please, contact me at <martintauchmann@bigfoot.com>, when you change the
|
||||
Amiga port. <http://martintauchmann.home.pages.de>
|
||||
|
||||
===========================================================================
|
||||
Michel Schinz's notes
|
||||
===========================================================================
|
||||
WHO DID WHAT
|
||||
|
||||
The original Amiga port was made by Jesper Peterson. I (Michel Schinz)
|
||||
modified it slightly to reflect the changes made in the new official
|
||||
distributions, and to take advantage of the new SAS/C 6.x features. I also
|
||||
created a makefile to compile the "cord" package (see the cord
|
||||
subdirectory).
|
||||
|
||||
TECHNICAL NOTES
|
||||
|
||||
In addition to Jesper's notes, I have the following to say:
|
||||
|
||||
- Starting with version 4.3, gctest checks to see if the code segment is
|
||||
added to the root set or not, and complains if it is. Previous versions
|
||||
of this Amiga port added the code segment to the root set, so I tried to
|
||||
fix that. The only problem is that, as far as I know, it is impossible to
|
||||
know which segments are code segments and which are data segments (there
|
||||
are indeed solutions to this problem, like scanning the program on disk
|
||||
or patch the LoadSeg functions, but they are rather complicated). The
|
||||
solution I have chosen (see os_dep.c) is to test whether the program
|
||||
counter is in the segment we are about to add to the root set, and if it
|
||||
is, to skip the segment. The problems are that this solution is rather
|
||||
awkward and that it works only for one code segment. This means that if
|
||||
your program has more than one code segment, all of them but one will be
|
||||
added to the root set. This isn't a big problem in fact, since the
|
||||
collector will continue to work correctly, but it may be slower.
|
||||
|
||||
Anyway, the code which decides whether to skip a segment or not can be
|
||||
removed simply by not defining AMIGA_SKIP_SEG. But notice that if you do
|
||||
so, gctest will complain (it will say that "GC_is_visible produced wrong
|
||||
failure indication"). However, it may be useful if you happen to have
|
||||
pointers stored in a code segment (you really shouldn't).
|
||||
|
||||
If anyone has a good solution to the problem of finding, when a program
|
||||
is loaded in memory, whether a segment is a code or a data segment,
|
||||
please let me know.
|
||||
|
||||
PROBLEMS
|
||||
|
||||
If you have any problem with this version, please contact me at
|
||||
schinz@alphanet.ch (but do *not* send long files, since we pay for
|
||||
every mail!).
|
||||
|
||||
===========================================================================
|
||||
Jesper Peterson's notes
|
||||
===========================================================================
|
||||
|
||||
ADDITIONAL NOTES FOR AMIGA PORT
|
||||
|
||||
These notes assume some familiarity with Amiga internals.
|
||||
|
||||
WHY I PORTED TO THE AMIGA
|
||||
|
||||
The sole reason why I made this port was as a first step in getting
|
||||
the Sather(*) language on the Amiga. A port of this language will
|
||||
be done as soon as the Sather 1.0 sources are made available to me.
|
||||
Given this motivation, the garbage collection (GC) port is rather
|
||||
minimal.
|
||||
|
||||
(*) For information on Sather read the comp.lang.sather newsgroup.
|
||||
|
||||
LIMITATIONS
|
||||
|
||||
This port assumes that the startup code linked with target programs
|
||||
is that supplied with SAS/C versions 6.0 or later. This allows
|
||||
assumptions to be made about where to find the stack base pointer
|
||||
and data segments when programs are run from WorkBench, as opposed
|
||||
to running from the CLI. The compiler dependent code is all in the
|
||||
GC_get_stack_base() and GC_register_data_segments() functions, but
|
||||
may spread as I add Amiga specific features.
|
||||
|
||||
Given that SAS/C was assumed, the port is set up to be built with
|
||||
"smake" using the "SMakefile". Compiler options in "SCoptions" can
|
||||
be set with "scopts" program. Both "smake" and "scopts" are part of
|
||||
the SAS/C commercial development system.
|
||||
|
||||
In keeping with the porting philosophy outlined above, this port
|
||||
will not behave well with Amiga specific code. Especially not inter-
|
||||
process comms via messages, and setting up public structures like
|
||||
Intuition objects or anything else in the system lists. For the
|
||||
time being the use of this library is limited to single threaded
|
||||
ANSI/POSIX compliant or near-complient code. (ie. Stick to stdio
|
||||
for now). Given this limitation there is currently no mechanism for
|
||||
allocating "CHIP" or "PUBLIC" memory under the garbage collector.
|
||||
I'll add this after giving it considerable thought. The major
|
||||
problem is the entire physical address space may have to me scanned,
|
||||
since there is no telling who we may have passed memory to.
|
||||
|
||||
If you allocate your own stack in client code, you will have to
|
||||
assign the pointer plus stack size to GC_stackbottom.
|
||||
|
||||
The initial stack size of the target program can be compiled in by
|
||||
setting the __stack symbol (see SAS documentaion). It can be over-
|
||||
ridden from the CLI by running the AmigaDOS "stack" program, or from
|
||||
the WorkBench by setting the stack size in the tool types window.
|
||||
|
||||
SAS/C COMPILER OPTIONS (SCoptions)
|
||||
|
||||
You may wish to check the "CPU" code option is appropriate for your
|
||||
intended target system.
|
||||
|
||||
Under no circumstances set the "StackExtend" code option in either
|
||||
compiling the library or *ANY* client code.
|
||||
|
||||
All benign compiler warnings have been suppressed. These mainly
|
||||
involve lack of prototypes in the code, and dead assignments
|
||||
detected by the optimizer.
|
||||
|
||||
THE GOOD NEWS
|
||||
|
||||
The library as it stands is compatible with the GigaMem commercial
|
||||
virtual memory software, and probably similar PD software.
|
||||
|
||||
The performance of "gctest" on an Amiga 2630 (68030 @ 25Mhz)
|
||||
compares favourably with an HP9000 with similar architecture (a 325
|
||||
with a 68030 I think).
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
The Amiga port has been brought to you by:
|
||||
|
||||
Jesper Peterson.
|
||||
|
||||
jep@mtiame.mtia.oz.au (preferred, but 1 week turnaround)
|
||||
jep@orca1.vic.design.telecom.au (that's orca<one>, 1 day turnaround)
|
||||
|
||||
At least one of these addresses should be around for a while, even
|
||||
though I don't work for either of the companies involved.
|
||||
|
||||
68
src/engine/boehm_gc/doc/README.arm.cross
Normal file
68
src/engine/boehm_gc/doc/README.arm.cross
Normal file
@@ -0,0 +1,68 @@
|
||||
From: Margaret Fleck
|
||||
|
||||
Here's the key details of what worked for me, in case anyone else needs them.
|
||||
There may well be better ways to do some of this, but ....
|
||||
-- Margaret
|
||||
|
||||
|
||||
The badge4 has a StrongArm-1110 processor and a StrongArm-1111 coprocessor.
|
||||
|
||||
Assume that the garbage collector distribution is unpacked into /home/arm/gc6.0,
|
||||
which is visible to both the ARM machine and a linux desktop (e.g. via NFS mounting).
|
||||
|
||||
Assume that you have a file /home/arm/config.site with contents something like the
|
||||
example attached below. Notice that our local ARM toolchain lives in
|
||||
/skiff/local.
|
||||
|
||||
Go to /home/arm/gc6.0 directory. Do
|
||||
CONFIG_SITE=/home/arm/config.site ./configure --target=arm-linux
|
||||
--prefix=/home/arm/gc6.0
|
||||
|
||||
On your desktop, do:
|
||||
make
|
||||
make install
|
||||
The main garbage collector library should now be in ../gc6.0/lib/libgc.so.
|
||||
|
||||
To test the garbage collector, first do the following on your desktop
|
||||
make gctest
|
||||
./gctest
|
||||
Then do the following on the ARM machine
|
||||
cd .libs
|
||||
./lt-gctest
|
||||
|
||||
Do not try to do "make test" (the usual way of running the test
|
||||
program). This does not work and seems to erase some of the important
|
||||
files.
|
||||
|
||||
The gctest program claims to have succeeded. Haven't run any further tests
|
||||
with it, though I'll be doing so in the near future.
|
||||
|
||||
-------------------------------
|
||||
# config.site for configure
|
||||
|
||||
# Modified from the one provided by Bradley D. LaRonde
|
||||
# Edited by Andrej Cedilnik <acedil1@csee.umbc.edu>
|
||||
# Used some of solutions by Tilman Vogel <Tilman.Vogel@web.de>
|
||||
# Ported for iPAQ Familiar by Oliver Kurth <oliver.kurth@innominate.com>
|
||||
# Further modified by Margaret Fleck for the badge4
|
||||
|
||||
HOSTCC=gcc
|
||||
|
||||
# Names of the cross-compilers
|
||||
CC=/skiff/local/bin/arm-linux-gcc
|
||||
CXX=/skiff/local/bin/arm-linux-gcc
|
||||
|
||||
# The cross compiler specific options
|
||||
CFLAGS="-O2 -fno-exceptions"
|
||||
CXXFLAGS="-O2 -fno-exceptions"
|
||||
CPPFLAGS="-O2 -fno-exceptions"
|
||||
LDFLAGS=""
|
||||
|
||||
# Some other programs
|
||||
AR=/skiff/local/bin/arm-linux-ar
|
||||
RANLIB=/skiff/local/bin/arm-linux-ranlib
|
||||
NM=/skiff/local/bin/arm-linux-nm
|
||||
ac_cv_path_NM=/skiff/local/bin/arm-linux-nm
|
||||
ac_cv_func_setpgrp_void=yes
|
||||
x_includes=/skiff/local/arm-linux/include/X11
|
||||
x_libraries=/skiff/local/arm-linux/lib/X11
|
||||
59
src/engine/boehm_gc/doc/README.autoconf
Normal file
59
src/engine/boehm_gc/doc/README.autoconf
Normal file
@@ -0,0 +1,59 @@
|
||||
As of GC6.0alpha8, we attempt to support GNU-style builds based on automake,
|
||||
autoconf and libtool. This is based almost entirely on Tom Tromey's work
|
||||
with gcj.
|
||||
|
||||
To build and install libraries use
|
||||
|
||||
configure; make; make install
|
||||
|
||||
The advantages of this process are:
|
||||
|
||||
1) It should eventually do a better job of automatically determining the
|
||||
right compiler to use, etc. It probably already does in some cases.
|
||||
|
||||
2) It tries to automatically set a good set of default GC parameters for
|
||||
the platform (e.g. thread support). It provides an easier way to configure
|
||||
some of the others.
|
||||
|
||||
3) It integrates better with other projects using a GNU-style build process.
|
||||
|
||||
4) It builds both dynamic and static libraries.
|
||||
|
||||
The known disadvantages are:
|
||||
|
||||
1) The build scripts are much more complex and harder to debug (though largely
|
||||
standard). I don't understand them all, and there's probably lots of redundant
|
||||
stuff.
|
||||
|
||||
2) It probably doesn't work on all Un*x-like platforms yet. It probably will
|
||||
never work on the rest.
|
||||
|
||||
3) The scripts are not yet complete. Some of the standard GNU targets don't
|
||||
yet work. (Corrections/additions are very welcome.)
|
||||
|
||||
The distribution should contain all files needed to run "configure" and "make",
|
||||
as well as the sources needed to regenerate the derived files. (If I missed
|
||||
some, please let me know.)
|
||||
|
||||
Note that the distribution comes with a "Makefile" which will be overwritten
|
||||
by "configure" with one that is not at all equiavelent to the original. The
|
||||
distribution contains a copy of the original "Makefile" in "Makefile.direct".
|
||||
|
||||
Important options to configure:
|
||||
|
||||
--prefix=PREFIX install architecture-independent files in PREFIX
|
||||
[/usr/local]
|
||||
--exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
|
||||
[same as prefix]
|
||||
--enable-threads=TYPE choose threading package
|
||||
--enable-parallel-mark parallelize marking and free list construction
|
||||
--enable-full-debug include full support for pointer backtracing etc.
|
||||
|
||||
Unless --prefix is set (or --exec-prefix or one of the more obscure options),
|
||||
make install will install libgc.a and libgc.so in /usr/local/bin, which
|
||||
would typically require the "make install" to be run as root.
|
||||
|
||||
Most commonly --enable-threads=posix or will be needed. --enable-parallel-mark
|
||||
is recommended for multiprocessors if it is supported on the platform.
|
||||
|
||||
|
||||
2594
src/engine/boehm_gc/doc/README.changes
Normal file
2594
src/engine/boehm_gc/doc/README.changes
Normal file
File diff suppressed because it is too large
Load Diff
57
src/engine/boehm_gc/doc/README.contributors
Normal file
57
src/engine/boehm_gc/doc/README.contributors
Normal file
@@ -0,0 +1,57 @@
|
||||
This is an attempt to acknowledge early contributions to the garbage
|
||||
collector. Later contributions should instead be mentioned in
|
||||
README.changes.
|
||||
|
||||
HISTORY -
|
||||
|
||||
Early versions of this collector were developed as a part of research
|
||||
projects supported in part by the National Science Foundation
|
||||
and the Defense Advance Research Projects Agency.
|
||||
|
||||
The garbage collector originated as part of the run-time system for
|
||||
the Russell programming language implementation. The first version of the
|
||||
garbage collector was written primarily by Al Demers. It was then refined
|
||||
and mostly rewritten, primarily by Hans-J. Boehm, at Cornell U.,
|
||||
the University of Washington, Rice University (where it was first used for
|
||||
C and assembly code), Xerox PARC, SGI, and HP Labs. However, significant
|
||||
contributions have also been made by many others.
|
||||
|
||||
Some other contributors:
|
||||
|
||||
More recent contributors are mentioned in the modification history in
|
||||
README.changes. My apologies for any omissions.
|
||||
|
||||
The SPARC specific code was originally contributed by Mark Weiser.
|
||||
The Encore Multimax modifications were supplied by
|
||||
Kevin Kenny (kenny@m.cs.uiuc.edu). The adaptation to the IBM PC/RT is largely
|
||||
due to Vernon Lee, on machines made available to Rice by IBM.
|
||||
Much of the HP specific code and a number of good suggestions for improving the
|
||||
generic code are due to Walter Underwood.
|
||||
Robert Brazile (brazile@diamond.bbn.com) originally supplied the ULTRIX code.
|
||||
Al Dosser (dosser@src.dec.com) and Regis Cridlig (Regis.Cridlig@cl.cam.ac.uk)
|
||||
subsequently provided updates and information on variation between ULTRIX
|
||||
systems. Parag Patel (parag@netcom.com) supplied the A/UX code.
|
||||
Jesper Peterson(jep@mtiame.mtia.oz.au), Michel Schinz, and
|
||||
Martin Tauchmann (martintauchmann@bigfoot.com) supplied the Amiga port.
|
||||
Thomas Funke (thf@zelator.in-berlin.de(?)) and
|
||||
Brian D.Carlstrom (bdc@clark.lcs.mit.edu) supplied the NeXT ports.
|
||||
Douglas Steel (doug@wg.icl.co.uk) provided ICL DRS6000 code.
|
||||
Bill Janssen (janssen@parc.xerox.com) supplied the SunOS dynamic loader
|
||||
specific code. Manuel Serrano (serrano@cornas.inria.fr) supplied linux and
|
||||
Sony News specific code. Al Dosser provided Alpha/OSF/1 code. He and
|
||||
Dave Detlefs(detlefs@src.dec.com) also provided several generic bug fixes.
|
||||
Alistair G. Crooks(agc@uts.amdahl.com) supplied the NetBSD and 386BSD ports.
|
||||
Jeffrey Hsu (hsu@soda.berkeley.edu) provided the FreeBSD port.
|
||||
Brent Benson (brent@jade.ssd.csd.harris.com) ported the collector to
|
||||
a Motorola 88K processor running CX/UX (Harris NightHawk).
|
||||
Ari Huttunen (Ari.Huttunen@hut.fi) generalized the OS/2 port to
|
||||
nonIBM development environments (a nontrivial task).
|
||||
Patrick Beard (beard@cs.ucdavis.edu) provided the initial MacOS port.
|
||||
David Chase, then at Olivetti Research, suggested several improvements.
|
||||
Scott Schwartz (schwartz@groucho.cse.psu.edu) supplied some of the
|
||||
code to save and print call stacks for leak detection on a SPARC.
|
||||
Jesse Hull and John Ellis supplied the C++ interface code.
|
||||
Zhong Shao performed much of the experimentation that led to the
|
||||
current typed allocation facility. (His dynamic type inference code hasn't
|
||||
made it into the released version of the collector, yet.)
|
||||
|
||||
53
src/engine/boehm_gc/doc/README.cords
Normal file
53
src/engine/boehm_gc/doc/README.cords
Normal file
@@ -0,0 +1,53 @@
|
||||
Copyright (c) 1993-1994 by Xerox Corporation. All rights reserved.
|
||||
|
||||
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
||||
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
||||
|
||||
Permission is hereby granted to use or copy this program
|
||||
for any purpose, provided the above notices are retained on all copies.
|
||||
Permission to modify the code and to distribute modified code is granted,
|
||||
provided the above notices are retained, and a notice that the code was
|
||||
modified is included with the above copyright notice.
|
||||
|
||||
Please send bug reports to Hans-J. Boehm (Hans_Boehm@hp.com or
|
||||
boehm@acm.org).
|
||||
|
||||
This is a string packages that uses a tree-based representation.
|
||||
See cord.h for a description of the functions provided. Ec.h describes
|
||||
"extensible cords", which are essentially output streams that write
|
||||
to a cord. These allow for efficient construction of cords without
|
||||
requiring a bound on the size of a cord.
|
||||
|
||||
More details on the data structure can be found in
|
||||
|
||||
Boehm, Atkinson, and Plass, "Ropes: An Alternative to Strings",
|
||||
Software Practice and Experience 25, 12, December 1995, pp. 1315-1330.
|
||||
|
||||
A fundamentally similar "rope" data structure is also part of SGI's standard
|
||||
template library implementation, and its descendents, which include the
|
||||
GNU C++ library. That uses reference counting by default.
|
||||
There is a short description of that data structure at
|
||||
http://reality.sgi.com/boehm/ropeimpl.html . (The more official location
|
||||
http://www.sgi.com/tech/stl/ropeimpl.html is missing a figure.)
|
||||
|
||||
All of these are descendents of the "ropes" in Xerox Cedar.
|
||||
|
||||
de.c is a very dumb text editor that illustrates the use of cords.
|
||||
It maintains a list of file versions. Each version is simply a
|
||||
cord representing the file contents. Nonetheless, standard
|
||||
editing operations are efficient, even on very large files.
|
||||
(Its 3 line "user manual" can be obtained by invoking it without
|
||||
arguments. Note that ^R^N and ^R^P move the cursor by
|
||||
almost a screen. It does not understand tabs, which will show
|
||||
up as highlighred "I"s. Use the UNIX "expand" program first.)
|
||||
To build the editor, type "make cord/de" in the gc directory.
|
||||
|
||||
This package assumes an ANSI C compiler such as gcc. It will
|
||||
not compile with an old-style K&R compiler.
|
||||
|
||||
Note that CORD_printf iand friends use C functions with variable numbers
|
||||
of arguments in non-standard-conforming ways. This code is known to
|
||||
break on some platforms, notably PowerPC. It should be possible to
|
||||
build the remainder of the library (everything but cordprnt.c) on
|
||||
any platform that supports the collector.
|
||||
|
||||
142
src/engine/boehm_gc/doc/README.darwin
Normal file
142
src/engine/boehm_gc/doc/README.darwin
Normal file
@@ -0,0 +1,142 @@
|
||||
Darwin/MacOSX Support - December 16, 2003
|
||||
=========================================
|
||||
|
||||
Important Usage Notes
|
||||
=====================
|
||||
|
||||
GC_init() MUST be called before calling any other GC functions. This
|
||||
is necessary to properly register segments in dynamic libraries. This
|
||||
call is required even if you code does not use dynamic libraries as the
|
||||
dyld code handles registering all data segments.
|
||||
|
||||
When your use of the garbage collector is confined to dylibs and you
|
||||
cannot call GC_init() before your libraries' static initializers have
|
||||
run and perhaps called GC_malloc(), create an initialization routine
|
||||
for each library to call GC_init():
|
||||
|
||||
#include <gc/gc.h>
|
||||
extern "C" void my_library_init() { GC_init(); }
|
||||
|
||||
Compile this code into a my_library_init.o, and link it into your
|
||||
dylib. When you link the dylib, pass the -init argument with
|
||||
_my_library_init (e.g. gcc -dynamiclib -o my_library.dylib a.o b.o c.o
|
||||
my_library_init.o -init _my_library_init). This causes
|
||||
my_library_init() to be called before any static initializers, and
|
||||
will initialize the garbage collector properly.
|
||||
|
||||
Note: It doesn't hurt to call GC_init() more than once, so it's best,
|
||||
if you have an application or set of libraries that all use the
|
||||
garbage collector, to create an initialization routine for each of
|
||||
them that calls GC_init(). Better safe than sorry.
|
||||
|
||||
The incremental collector is still a bit flaky on darwin. It seems to
|
||||
work reliably with workarounds for a few possible bugs in place however
|
||||
these workaround may not work correctly in all cases. There may also
|
||||
be additional problems that I have not found.
|
||||
|
||||
Thread-local GC allocation will not work with threads that are not
|
||||
created using the GC-provided override of pthread_create(). Threads
|
||||
created without the GC-provided pthread_create() do not have the
|
||||
necessary data structures in the GC to store this data.
|
||||
|
||||
|
||||
Implementation Information
|
||||
==========================
|
||||
Darwin/MacOSX support is nearly complete. Thread support is reliable on
|
||||
Darwin 6.x (MacOSX 10.2) and there have been reports of success on older
|
||||
Darwin versions (MacOSX 10.1). Shared library support had also been
|
||||
added and the gc can be run from a shared library. There is currently only
|
||||
support for Darwin/PPC although adding x86 support should be trivial.
|
||||
|
||||
Thread support is implemented in terms of mach thread_suspend and
|
||||
thread_resume calls. These provide a very clean interface to thread
|
||||
suspension. This implementation doesn't rely on pthread_kill so the
|
||||
code works on Darwin < 6.0 (MacOSX 10.1). All the code to stop and
|
||||
start the world is located in darwin_stop_world.c.
|
||||
|
||||
Since not all uses of the GC enable clients to override pthread_create()
|
||||
before threads have been created, the code for stopping the world has
|
||||
been rewritten to look for threads using Mach kernel calls. Each
|
||||
thread identified in this way is suspended and resumed as above. In
|
||||
addition, since Mach kernel threads do not contain pointers to their
|
||||
stacks, a stack-walking function has been written to find the stack
|
||||
limits. Given an initial stack pointer (for the current thread, a
|
||||
pointer to a stack-allocated local variable will do; for a non-active
|
||||
thread, we grab the value of register 1 (on PowerPC)), it
|
||||
will walk the PPC Mach-O-ABI compliant stack chain until it reaches the
|
||||
top of the stack. This appears to work correctly for GCC-compiled C,
|
||||
C++, Objective-C, and Objective-C++ code, as well as for Java
|
||||
programs that use JNI. If you run code that does not follow the stack
|
||||
layout or stack pointer conventions laid out in the PPC Mach-O ABI,
|
||||
then this will likely crash the garbage collector.
|
||||
|
||||
The original incremental collector support unfortunatelly no longer works
|
||||
on recent Darwin versions. It also relied on some undocumented kernel
|
||||
structures. Mach, however, does have a very clean interface to exception
|
||||
handing. The current implementation uses Mach's exception handling.
|
||||
|
||||
Much thanks goes to Andrew Stone, Dietmar Planitzer, Andrew Begel,
|
||||
Jeff Sturm, and Jesse Rosenstock for all their work on the
|
||||
Darwin/OS X port.
|
||||
|
||||
-Brian Alliet
|
||||
brian@brianweb.net
|
||||
|
||||
gc_cpp.h usage
|
||||
==============
|
||||
|
||||
Replacement of operator new and delete is apparently not supported with
|
||||
dynamic libraries. This means that applications using gc_cpp.h
|
||||
(including the built-in test) will probably not work correctly with
|
||||
the collector in a dynamic library, unless special care is taken.
|
||||
|
||||
See
|
||||
http://article.gmane.org/gmane.comp.programming.garbage-collection.boehmgc/1421
|
||||
for some details.
|
||||
|
||||
- Hans Boehm (based on information from Andrew Begel)
|
||||
|
||||
|
||||
Older Information (Most of this no longer applies to the current code)
|
||||
======================================================================
|
||||
|
||||
While the GC should work on MacOS X Server, MacOS X and Darwin, I only tested
|
||||
it on MacOS X Server.
|
||||
I've added a PPC assembly version of GC_push_regs(), thus the setjmp() hack is
|
||||
no longer necessary. Incremental collection is supported via mprotect/signal.
|
||||
The current solution isn't really optimal because the signal handler must decode
|
||||
the faulting PPC machine instruction in order to find the correct heap address.
|
||||
Further, it must poke around in the register state which the kernel saved away
|
||||
in some obscure register state structure before it calls the signal handler -
|
||||
needless to say the layout of this structure is no where documented.
|
||||
Threads and dynamic libraries are not yet supported (adding dynamic library
|
||||
support via the low-level dyld API shouldn't be that hard).
|
||||
|
||||
The original MacOS X port was brought to you by Andrew Stone.
|
||||
|
||||
|
||||
June, 1 2000
|
||||
|
||||
Dietmar Planitzer
|
||||
dave.pl@ping.at
|
||||
|
||||
Note from Andrew Begel:
|
||||
|
||||
One more fix to enable gc.a to link successfully into a shared library for
|
||||
MacOS X. You have to add -fno-common to the CFLAGS in the Makefile. MacOSX
|
||||
disallows common symbols in anything that eventually finds its way into a
|
||||
shared library. (I don't completely understand why, but -fno-common seems to
|
||||
work and doesn't mess up the garbage collector's functionality).
|
||||
|
||||
Feb 26, 2003
|
||||
|
||||
Jeff Sturm and Jesse Rosenstock provided a patch that adds thread support.
|
||||
GC_MACOSX_THREADS should be defined in the build and in clients. Real
|
||||
dynamic library support is still missing, i.e. dynamic library data segments
|
||||
are still not scanned. Code that stores pointers to the garbage collected
|
||||
heap in statically allocated variables should not reside in a dynamic
|
||||
library. This still doesn't appear to be 100% reliable.
|
||||
|
||||
Mar 10, 2003
|
||||
Brian Alliet contributed dynamic library support for MacOSX. It could also
|
||||
use more testing.
|
||||
12
src/engine/boehm_gc/doc/README.dj
Normal file
12
src/engine/boehm_gc/doc/README.dj
Normal file
@@ -0,0 +1,12 @@
|
||||
[Original version supplied by Xiaokun Zhu <xiaokun@aero.gla.ac.uk>]
|
||||
[This version came mostly from Gary Leavens. ]
|
||||
|
||||
Look first at Makefile.dj, and possibly change the definitions of
|
||||
RM and MV if you don't have rm and mv installed.
|
||||
Then use Makefile.dj to compile the garbage collector.
|
||||
For example, you can do:
|
||||
|
||||
make -f Makefile.dj test
|
||||
|
||||
All the tests should work fine.
|
||||
|
||||
135
src/engine/boehm_gc/doc/README.environment
Normal file
135
src/engine/boehm_gc/doc/README.environment
Normal file
@@ -0,0 +1,135 @@
|
||||
The garbage collector looks at a number of environment variables which are
|
||||
then used to affect its operation. These are examined only on Un*x-like
|
||||
platforms and win32.
|
||||
|
||||
GC_INITIAL_HEAP_SIZE=<bytes> - Initial heap size in bytes. May speed up
|
||||
process start-up.
|
||||
|
||||
GC_MAXIMUM_HEAP_SIZE=<bytes> - Maximum collected heap size.
|
||||
|
||||
GC_LOOP_ON_ABORT - Causes the collector abort routine to enter a tight loop.
|
||||
This may make it easier to debug, such a process, especially
|
||||
for multithreaded platforms that don't produce usable core
|
||||
files, or if a core file would be too large. On some
|
||||
platforms, this also causes SIGSEGV to be caught and
|
||||
result in an infinite loop in a handler, allowing
|
||||
similar debugging techniques.
|
||||
|
||||
GC_PRINT_STATS - Turn on GC logging. Not functional with -DSMALL_CONFIG.
|
||||
|
||||
GC_LOG_FILE - The name of the log file. Stderr by default.
|
||||
|
||||
GC_PRINT_VERBOSE_STATS - Turn on even more logging.
|
||||
|
||||
GC_DUMP_REGULARLY - Generate a GC debugging dump GC_dump() on startup
|
||||
and during every collection. Very verbose. Useful
|
||||
if you have a bug to report, but please include only the
|
||||
last complete dump.
|
||||
|
||||
GC_BACKTRACES=<n> - Generate n random backtraces (for heap profiling) after
|
||||
each GC. Collector must have been built with
|
||||
KEEP_BACK_PTRS. This won't generate useful output unless
|
||||
most objects in the heap were allocated through debug
|
||||
allocators. This is intended to be only a statistical
|
||||
sample; individual traces may be erroneous due to
|
||||
concurrent heap mutation.
|
||||
|
||||
GC_PRINT_ADDRESS_MAP - Linux only. Dump /proc/self/maps, i.e. various address
|
||||
maps for the process, to stderr on every GC. Useful for
|
||||
mapping root addresses to source for deciphering leak
|
||||
reports.
|
||||
|
||||
GC_NPROCS=<n> - Linux w/threads only. Explicitly sets the number of processors
|
||||
that the GC should expect to use. Note that setting this to 1
|
||||
when multiple processors are available will preserve
|
||||
correctness, but may lead to really horrible performance,
|
||||
since the lock implementation will immediately yield without
|
||||
first spinning.
|
||||
|
||||
GC_MARKERS=<n> - Linux w/threads and parallel marker only. Set the number
|
||||
of marker threads. This is normally set to the number of
|
||||
processors. It is safer to adjust GC_MARKERS than GC_NPROCS,
|
||||
since GC_MARKERS has no impact on the lock implementation.
|
||||
|
||||
GC_NO_BLACKLIST_WARNING - Prevents the collector from issuing
|
||||
warnings about allocations of very large blocks.
|
||||
Deprecated. Use GC_LARGE_ALLOC_WARN_INTERVAL instead.
|
||||
|
||||
GC_LARGE_ALLOC_WARN_INTERVAL=<n> - Print every nth warning about very large
|
||||
block allocations, starting with the nth one. Small values
|
||||
of n are generally benign, in that a bounded number of
|
||||
such warnings generally indicate at most a bounded leak.
|
||||
For best results it should be set at 1 during testing.
|
||||
Default is 5. Very large numbers effectively disable the
|
||||
warning.
|
||||
|
||||
GC_IGNORE_GCJ_INFO - Ignore the type descriptors implicitly supplied by
|
||||
GC_gcj_malloc and friends. This is useful for debugging
|
||||
descriptor generation problems, and possibly for
|
||||
temporarily working around such problems. It forces a
|
||||
fully conservative scan of all heap objects except
|
||||
those known to be pointerfree, and may thus have other
|
||||
adverse effects.
|
||||
|
||||
GC_PRINT_BACK_HEIGHT - Print max length of chain through unreachable objects
|
||||
ending in a reachable one. If this number remains
|
||||
bounded, then the program is "GC robust". This ensures
|
||||
that a fixed number of misidentified pointers can only
|
||||
result in a bounded space leak. This currently only
|
||||
works if debugging allocation is used throughout.
|
||||
It increases GC space and time requirements appreciably.
|
||||
This feature is still somewhat experimental, and requires
|
||||
that the collector have been built with MAKE_BACK_GRAPH
|
||||
defined. For details, see Boehm, "Bounding Space Usage
|
||||
of Conservative Garbage Collectors", POPL 2001, or
|
||||
http://lib.hpl.hp.com/techpubs/2001/HPL-2001-251.html .
|
||||
|
||||
GC_RETRY_SIGNALS, GC_NO_RETRY_SIGNALS - Try to compensate for lost
|
||||
thread suspend signals in linux_threads.c. On by
|
||||
default for GC_OSF1_THREADS, off otherwise. Note
|
||||
that this does not work around a possible loss of
|
||||
thread restart signals. This seems to be necessary for
|
||||
some versions of Tru64. Since we've previously seen
|
||||
similar issues on some other operating systems, it
|
||||
was turned into a runtime flag to enable last-minute
|
||||
work-arounds.
|
||||
|
||||
The following turn on runtime flags that are also program settable. Checked
|
||||
only during initialization. We expect that they will usually be set through
|
||||
other means, but this may help with debugging and testing:
|
||||
|
||||
GC_ENABLE_INCREMENTAL - Turn on incremental collection at startup. Note that,
|
||||
depending on platform and collector configuration, this
|
||||
may involve write protecting pieces of the heap to
|
||||
track modifications. These pieces may include pointerfree
|
||||
objects or not. Although this is intended to be
|
||||
transparent, it may cause unintended system call failures.
|
||||
Use with caution.
|
||||
|
||||
GC_PAUSE_TIME_TARGET - Set the desired garbage collector pause time in msecs.
|
||||
This only has an effect if incremental collection is
|
||||
enabled. If a collection requires appreciably more time
|
||||
than this, the client will be restarted, and the collector
|
||||
will need to do additional work to compensate. The
|
||||
special value "999999" indicates that pause time is
|
||||
unlimited, and the incremental collector will behave
|
||||
completely like a simple generational collector. If
|
||||
the collector is configured for parallel marking, and
|
||||
run on a multiprocessor, incremental collection should
|
||||
only be used with unlimited pause time.
|
||||
|
||||
GC_FIND_LEAK - Turns on GC_find_leak and thus leak detection. Forces a
|
||||
collection at program termination to detect leaks that would
|
||||
otherwise occur after the last GC.
|
||||
|
||||
GC_ALL_INTERIOR_POINTERS - Turns on GC_all_interior_pointers and thus interior
|
||||
pointer recognition.
|
||||
|
||||
GC_DONT_GC - Turns off garbage collection. Use cautiously.
|
||||
|
||||
GC_TRACE=addr - Intended for collector debugging. Requires that the collector
|
||||
have been built with ENABLE_TRACE defined. Causes the debugger
|
||||
to log information about the tracing of address ranges containing
|
||||
addr. Typically addr is the address that contains a pointer to
|
||||
an object that mysteriously failed to get marked. Addr must be
|
||||
specified as a hexadecimal integer.
|
||||
81
src/engine/boehm_gc/doc/README.ews4800
Normal file
81
src/engine/boehm_gc/doc/README.ews4800
Normal file
@@ -0,0 +1,81 @@
|
||||
GC on EWS4800
|
||||
-------------
|
||||
|
||||
1. About EWS4800
|
||||
EWS4800 is 32bit/64bit workstation.
|
||||
|
||||
Vender: NEC Corporation
|
||||
OS: UX/4800 R9.* - R13.* (SystemV R4.2)
|
||||
CPU: R4000, R4400, R10000 (MIPS)
|
||||
|
||||
2. Compiler
|
||||
|
||||
32bit:
|
||||
Use ANSI C compiler.
|
||||
CC = /usr/abiccs/bin/cc
|
||||
|
||||
64bit:
|
||||
Use 64bit ANSI C compiler.
|
||||
CC = /usr/ccs64/bin/cc
|
||||
AR = /usr/ccs64/bin/ar
|
||||
|
||||
3. ELF file format
|
||||
*** Caution: The following infomation is empirical. ***
|
||||
|
||||
32bit:
|
||||
ELF file has an unique format. (See a.out(4) and end(3C).)
|
||||
|
||||
&_start
|
||||
: text segment
|
||||
&etext
|
||||
DATASTART
|
||||
: data segment (initialized)
|
||||
&edata
|
||||
DATASTART2
|
||||
: data segment (uninitialized)
|
||||
&end
|
||||
|
||||
Here, DATASTART and DATASTART2 are macros of GC, and are defined as
|
||||
the following equations. (See include/private/gcconfig.h.)
|
||||
The algorithm for DATASTART is similar with the function
|
||||
GC_SysVGetDataStart() in os_dep.c.
|
||||
|
||||
DATASTART = ((&etext + 0x3ffff) & ~0x3ffff) + (&etext & 0xffff)
|
||||
|
||||
Dynamically linked:
|
||||
DATASTART2 = (&_gp + 0x8000 + 0x3ffff) & ~0x3ffff
|
||||
|
||||
Statically linked:
|
||||
DATASTART2 = &edata
|
||||
|
||||
GC has to check addresses both between DATASTART and &edata, and
|
||||
between DATASTART2 and &end. If a program accesses between &etext
|
||||
and DATASTART, or between &edata and DATASTART2, the segmentation
|
||||
error occurs and the program stops.
|
||||
|
||||
If a program is statically linked, there is not a gap between
|
||||
&edata and DATASTART2. The global symbol &_DYNAMIC_LINKING is used
|
||||
for the detection.
|
||||
|
||||
64bit:
|
||||
ELF file has a simple format. (See end(3C).)
|
||||
|
||||
_ftext
|
||||
: text segment
|
||||
_etext
|
||||
_fdata = DATASTART
|
||||
: data segment (initialized)
|
||||
_edata
|
||||
_fbss
|
||||
: data segment (uninitialized)
|
||||
_end = DATAEND
|
||||
|
||||
--
|
||||
Hironori SAKAMOTO <hsaka@mth.biglobe.ne.jp>
|
||||
|
||||
|
||||
When using the new "configure; make" build process, please
|
||||
run configure with the --disable-shared option. "Make check" does not
|
||||
yet pass with dynamic libraries. Ther reasons for that are not yet
|
||||
understood. (HB, paraphrasing message from Hironori SAKAMOTO.)
|
||||
|
||||
18
src/engine/boehm_gc/doc/README.hp
Normal file
18
src/engine/boehm_gc/doc/README.hp
Normal file
@@ -0,0 +1,18 @@
|
||||
Dynamic loading support requires that executables be linked with -ldld.
|
||||
The alternative is to build the collector without defining DYNAMIC_LOADING
|
||||
in gcconfig.h and ensuring that all garbage collectable objects are
|
||||
accessible without considering statically allocated variables in dynamic
|
||||
libraries.
|
||||
|
||||
The collector should compile with either plain cc or cc -Ae. Cc -Aa
|
||||
fails to define _HPUX_SOURCE and thus will not configure the collector
|
||||
correctly.
|
||||
|
||||
Incremental collection support was reccently added, and should now work.
|
||||
|
||||
In spite of past claims, pthread support under HP/UX 11 should now work.
|
||||
Define GC_HPUX_THREADS for the build. Incremental collection still does not
|
||||
work in combination with it.
|
||||
|
||||
The stack finding code can be confused by putenv calls before collector
|
||||
initialization. Call GC_malloc or GC_init before any putenv calls.
|
||||
131
src/engine/boehm_gc/doc/README.linux
Normal file
131
src/engine/boehm_gc/doc/README.linux
Normal file
@@ -0,0 +1,131 @@
|
||||
See README.alpha for Linux on DEC AXP info.
|
||||
|
||||
This file applies mostly to Linux/Intel IA32. Ports to Linux on an M68K, IA64,
|
||||
SPARC, MIPS, Alpha and PowerPC are also integrated. They should behave
|
||||
similarly, except that the PowerPC port lacks incremental GC support, and
|
||||
it is unknown to what extent the Linux threads code is functional.
|
||||
See below for M68K specific notes.
|
||||
|
||||
Incremental GC is generally supported.
|
||||
|
||||
Dynamic libraries are supported on an ELF system. A static executable
|
||||
should be linked with the gcc option "-Wl,-defsym,_DYNAMIC=0".
|
||||
|
||||
The collector appears to work reliably with Linux threads, but beware
|
||||
of older versions of glibc and gdb.
|
||||
|
||||
The garbage collector uses SIGPWR and SIGXCPU if it is used with
|
||||
Linux threads. These should not be touched by the client program.
|
||||
|
||||
To use threads, you need to abide by the following requirements:
|
||||
|
||||
1) You need to use LinuxThreads or NPTL (which are included in libc6).
|
||||
|
||||
The collector relies on some implementation details of the LinuxThreads
|
||||
package. This code may not work on other
|
||||
pthread implementations (in particular it will *not* work with
|
||||
MIT pthreads).
|
||||
|
||||
2) You must compile the collector with -DGC_LINUX_THREADS (or
|
||||
just -DGC_THREADS) and -D_REENTRANT specified in the Makefile.
|
||||
|
||||
3a) Every file that makes thread calls should define GC_LINUX_THREADS and
|
||||
_REENTRANT and then include gc.h. Gc.h redefines some of the
|
||||
pthread primitives as macros which also provide the collector with
|
||||
information it requires.
|
||||
|
||||
3b) A new alternative to (3a) is to build the collector and compile GC clients
|
||||
with -DGC_USE_LD_WRAP, and to link the final program with
|
||||
|
||||
(for ld) --wrap read --wrap dlopen --wrap pthread_create \
|
||||
--wrap pthread_join --wrap pthread_detach \
|
||||
--wrap pthread_sigmask --wrap sleep
|
||||
|
||||
(for gcc) -Wl,--wrap -Wl,read -Wl,--wrap -Wl,dlopen -Wl,--wrap \
|
||||
-Wl,pthread_create -Wl,--wrap -Wl,pthread_join -Wl,--wrap \
|
||||
-Wl,pthread_detach -Wl,--wrap -Wl,pthread_sigmask \
|
||||
-Wl,--wrap -Wl,sleep
|
||||
|
||||
In any case, _REENTRANT should be defined during compilation.
|
||||
|
||||
4) Dlopen() disables collection during its execution. (It can't run
|
||||
concurrently with the collector, since the collector looks at its
|
||||
data structures. It can't acquire the allocator lock, since arbitrary
|
||||
user startup code may run as part of dlopen().) Under unusual
|
||||
conditions, this may cause unexpected heap growth.
|
||||
|
||||
5) The combination of GC_LINUX_THREADS, REDIRECT_MALLOC, and incremental
|
||||
collection is probably not fully reliable, though it now seems to work
|
||||
in simple cases.
|
||||
|
||||
6) Thread local storage may not be viewed as part of the root set by the
|
||||
collector. This probably depends on the linuxthreads version. For the
|
||||
time being, any collectable memory referenced by thread local storage should
|
||||
also be referenced from elsewhere, or be allocated as uncollectable.
|
||||
(This is really a bug that should be fixed somehow. The current GC
|
||||
version probably gets things right if there are not too many tls locations
|
||||
and if dlopen is not used.)
|
||||
|
||||
|
||||
M68K LINUX:
|
||||
(From Richard Zidlicky)
|
||||
The bad news is that it can crash every linux-m68k kernel on a 68040,
|
||||
so an additional test is needed somewhere on startup. I have meanwhile
|
||||
patches to correct the problem in 68040 buserror handler but it is not
|
||||
yet in any standard kernel.
|
||||
|
||||
Here is a simple test program to detect whether the kernel has the
|
||||
problem. It could be run as a separate check in configure or tested
|
||||
upon startup. If it fails (return !0) than mprotect can't be used
|
||||
on that system.
|
||||
|
||||
/*
|
||||
* test for bug that may crash 68040 based Linux
|
||||
*/
|
||||
|
||||
#include <sys/mman.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
char *membase;
|
||||
int pagesize=4096;
|
||||
int pageshift=12;
|
||||
int x_taken=0;
|
||||
|
||||
int sighandler(int sig)
|
||||
{
|
||||
mprotect(membase,pagesize,PROT_READ|PROT_WRITE);
|
||||
x_taken=1;
|
||||
}
|
||||
|
||||
main()
|
||||
{
|
||||
long l;
|
||||
|
||||
signal(SIGSEGV,sighandler);
|
||||
l=(long)mmap(NULL,pagesize,PROT_READ,MAP_PRIVATE | MAP_ANON,-1,0);
|
||||
if (l==-1)
|
||||
{
|
||||
perror("mmap/malloc");
|
||||
abort();
|
||||
}
|
||||
membase=(char*)l;
|
||||
*(long*)(membase+sizeof(long))=123456789;
|
||||
if (*(long*)(membase+sizeof(long)) != 123456789 )
|
||||
{
|
||||
fprintf(stderr,"writeback failed !\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!x_taken)
|
||||
{
|
||||
fprintf(stderr,"exception not taken !\n");
|
||||
exit(1);
|
||||
}
|
||||
fprintf(stderr,"vmtest Ok\n");
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
||||
82
src/engine/boehm_gc/doc/README.macros
Normal file
82
src/engine/boehm_gc/doc/README.macros
Normal file
@@ -0,0 +1,82 @@
|
||||
The collector uses a large amount of conditional compilation in order to
|
||||
deal with platform dependencies. This violates a number of known coding
|
||||
standards. On the other hand, it seems to be the only practical way to
|
||||
support this many platforms without excessive code duplication.
|
||||
|
||||
A few guidelines have mostly been followed in order to keep this manageable:
|
||||
|
||||
1) #if and #ifdef directives are properly indented whenever easily possible.
|
||||
All known C compilers allow whitespace between the "#" and the "if" to make
|
||||
this possible. ANSI C also allows white space before the "#", though we
|
||||
avoid that. It has the known disadvantages that it differs from the normal
|
||||
GNU conventions, and that it makes patches larger than otherwise necessary.
|
||||
In my opinion, it's still well worth it, for the same reason that we indent
|
||||
ordinary "if" statements.
|
||||
|
||||
2) Whenever possible, tests are performed on the macros defined in gcconfig.h
|
||||
instead of directly testing patform-specific predefined macros. This makes it
|
||||
relatively easy to adapt to new compilers with a different set of predefined
|
||||
macros. Currently these macros generally identify platforms instead of
|
||||
features. In many cases, this is a mistake.
|
||||
|
||||
Many of the tested configuration macros are at least somewhat defined in
|
||||
either include/private/gcconfig.h or in Makefile.direct. Here is an attempt
|
||||
at defining some of the remainder: (Thanks to Walter Bright for suggesting
|
||||
this. This is a work in progress)
|
||||
|
||||
MACRO EXPLANATION
|
||||
----- -----------
|
||||
|
||||
__DMC__ Always #define'd by the Digital Mars compiler. Expands
|
||||
to the compiler version number in hex, i.e. 0x810 is
|
||||
version 8.1b0
|
||||
|
||||
_ENABLE_ARRAYNEW
|
||||
#define'd by the Digital Mars C++ compiler when
|
||||
operator new[] and delete[] are separately
|
||||
overloadable. Used in gc_cpp.h.
|
||||
|
||||
_MSC_VER Expands to the Visual C++ compiler version. Assumed to
|
||||
not be defined for other compilers (at least if they behave
|
||||
appreciably differently).
|
||||
|
||||
_DLL Defined by Visual C++ if dynamic libraries are being built
|
||||
or used. Used to test whether __declspec(dllimport) or
|
||||
__declspec(dllexport) needs to be added to declarations
|
||||
to support the case in which the collector is in a dll.
|
||||
|
||||
GC_DLL User-settable macro that forces the effect of _DLL. Set
|
||||
by gc.h if _DLL is defined and GC_NOT_DLL is undefined.
|
||||
This is the macro that is tested internally to determine
|
||||
whether the GC is in its own dynamic library. May need
|
||||
to be set by clients before including gc.h. Note that
|
||||
inside the GC implementation it indicates that the
|
||||
collector is in its own dynamic library, should export
|
||||
its symbols, etc. But in clients it indicates that the
|
||||
GC resides in a different DLL, its entry points should
|
||||
be referenced accordingly, and precautions may need to
|
||||
be taken to properly deal with statically allocated
|
||||
variables in the main program. Used only for MS Windows.
|
||||
|
||||
GC_NOT_DLL User-settable macro that overrides _DLL, e.g. if dynamic
|
||||
libraries are used, but the collector is in a static library.
|
||||
|
||||
__STDC__ Assumed to be defined only by compilers that understand
|
||||
prototypes and other C89 features. Its value is generally
|
||||
not used, since we are fine with most nonconforming extensions.
|
||||
|
||||
SUNOS5SIGS Solaris-like signal handling. This is probably misnamed,
|
||||
since it really doesn't guarantee much more than Posix.
|
||||
Currently set only for Solaris2.X, HPUX, and DRSNX. Should
|
||||
probably be set for some other platforms.
|
||||
|
||||
PCR Set if the collector is being built as part of the Xerox
|
||||
Portable Common Runtime.
|
||||
|
||||
USE_COMPILER_TLS Assume the existence of __thread-style thread-local
|
||||
storage. Set automatically for thread-local allocation with
|
||||
the HP/UX vendor compiler. Usable with gcc on sufficiently
|
||||
up-to-date ELF platforms.
|
||||
|
||||
|
||||
|
||||
9
src/engine/boehm_gc/doc/README.rs6000
Normal file
9
src/engine/boehm_gc/doc/README.rs6000
Normal file
@@ -0,0 +1,9 @@
|
||||
We have so far failed to find a good way to determine the stack base.
|
||||
It is highly recommended that GC_stackbottom be set explicitly on program
|
||||
startup. The supplied value sometimes causes failure under AIX 4.1, though
|
||||
it appears to work under 3.X. HEURISTIC2 seems to work under 4.1, but
|
||||
involves a substantial performance penalty, and will fail if there is
|
||||
no limit on stack size.
|
||||
|
||||
There is no thread support. (I assume recent versions of AIX provide
|
||||
pthreads? I no longer have access to a machine ...)
|
||||
41
src/engine/boehm_gc/doc/README.sgi
Normal file
41
src/engine/boehm_gc/doc/README.sgi
Normal file
@@ -0,0 +1,41 @@
|
||||
Performance of the incremental collector can be greatly enhanced with
|
||||
-DNO_EXECUTE_PERMISSION.
|
||||
|
||||
The collector should run with all of the -32, -n32 and -64 ABIs. Remember to
|
||||
define the AS macro in the Makefile to be "as -64", or "as -n32".
|
||||
|
||||
If you use -DREDIRECT_MALLOC=GC_malloc with C++ code, your code should make
|
||||
at least one explicit call to malloc instead of new to ensure that the proper
|
||||
version of malloc is linked in.
|
||||
|
||||
Sproc threads are not supported in this version, though there may exist other
|
||||
ports.
|
||||
|
||||
Pthreads support is provided. This requires that:
|
||||
|
||||
1) You compile the collector with -DGC_IRIX_THREADS specified in the Makefile.
|
||||
|
||||
2) You have the latest pthreads patches installed.
|
||||
|
||||
(Though the collector makes only documented pthread calls,
|
||||
it relies on signal/threads interactions working just right in ways
|
||||
that are not required by the standard. It is unlikely that this code
|
||||
will run on other pthreads platforms. But please tell me if it does.)
|
||||
|
||||
3) Every file that makes thread calls should define IRIX_THREADS and then
|
||||
include gc.h. Gc.h redefines some of the pthread primitives as macros which
|
||||
also provide the collector with information it requires.
|
||||
|
||||
4) pthread_cond_wait and pthread_cond_timed_wait should be prepared for
|
||||
premature wakeups. (I believe the pthreads and realted standards require this
|
||||
anyway. Irix pthreads often terminate a wait if a signal arrives.
|
||||
The garbage collector uses signals to stop threads.)
|
||||
|
||||
5) It is expensive to stop a thread waiting in IO at the time the request is
|
||||
initiated. Applications with many such threads may not exhibit acceptable
|
||||
performance with the collector. (Increasing the heap size may help.)
|
||||
|
||||
6) The collector should not be compiled with -DREDIRECT_MALLOC. This
|
||||
confuses some library calls made by the pthreads implementation, which
|
||||
expect the standard malloc.
|
||||
|
||||
64
src/engine/boehm_gc/doc/README.solaris2
Normal file
64
src/engine/boehm_gc/doc/README.solaris2
Normal file
@@ -0,0 +1,64 @@
|
||||
The collector supports both incremental collection and threads under
|
||||
Solaris 2. The incremental collector normally retrieves page dirty information
|
||||
through the appropriate /proc calls. But it can also be configured
|
||||
(by defining MPROTECT_VDB instead of PROC_VDB in gcconfig.h) to use mprotect
|
||||
and signals. This may result in shorter pause times, but it is no longer
|
||||
safe to issue arbitrary system calls that write to the heap.
|
||||
|
||||
Under other UNIX versions,
|
||||
the collector normally obtains memory through sbrk. There is some reason
|
||||
to expect that this is not safe if the client program also calls the system
|
||||
malloc, or especially realloc. The sbrk man page strongly suggests this is
|
||||
not safe: "Many library routines use malloc() internally, so use brk()
|
||||
and sbrk() only when you know that malloc() definitely will not be used by
|
||||
any library routine." This doesn't make a lot of sense to me, since there
|
||||
seems to be no documentation as to which routines can transitively call malloc.
|
||||
Nonetheless, under Solaris2, the collector now (since 4.12) allocates
|
||||
memory using mmap by default. (It defines USE_MMAP in gcconfig.h.)
|
||||
You may want to reverse this decisions if you use -DREDIRECT_MALLOC=...
|
||||
|
||||
|
||||
SOLARIS THREADS:
|
||||
|
||||
The collector must be compiled with -DGC_SOLARIS_THREADS (thr_ functions)
|
||||
or -DGC_THREADS to be thread safe. This assumes use of the pthread_
|
||||
interface. Old style Solaris threads are no longer supported.
|
||||
|
||||
It is also essential that gc.h be included in files that call thr_create,
|
||||
thr_join, thr_suspend, thr_continue, or dlopen. Gc.h macro defines
|
||||
these to also do GC bookkeeping, etc. Gc.h must be included with
|
||||
one or both of these macros defined, otherwise
|
||||
these replacements are not visible.
|
||||
A collector built in this way way only be used by programs that are
|
||||
linked with the threads library.
|
||||
|
||||
Since 5.0 alpha5, dlopen disables collection temporarily,
|
||||
unless USE_PROC_FOR_LIBRARIES is defined. In some unlikely cases, this
|
||||
can result in unpleasant heap growth. But it seems better than the
|
||||
race/deadlock issues we had before.
|
||||
|
||||
If solaris_threads are used on an X86 processor with malloc redirected to
|
||||
GC_malloc, it is necessary to call GC_thr_init explicitly before forking the
|
||||
first thread. (This avoids a deadlock arising from calling GC_thr_init
|
||||
with the allocation lock held.)
|
||||
|
||||
It appears that there is a problem in using gc_cpp.h in conjunction with
|
||||
Solaris threads and Sun's C++ runtime. Apparently the overloaded new operator
|
||||
is invoked by some iostream initialization code before threads are correctly
|
||||
initialized. As a result, call to thr_self() in garbage collector
|
||||
initialization segfaults. Currently the only known workaround is to not
|
||||
invoke the garbage collector from a user defined global operator new, or to
|
||||
have it invoke the garbage-collector's allocators only after main has started.
|
||||
(Note that the latter requires a moderately expensive test in operator
|
||||
delete.)
|
||||
|
||||
I encountered "symbol <unknown>: offet .... is non-aligned" errors. These
|
||||
appear to be traceable to the use of the GNU assembler with the Sun linker.
|
||||
The former appears to generate a relocation not understood by the latter.
|
||||
The fix appears to be to use a consistent tool chain. (As a non-Solaris-expert
|
||||
my solution involved hacking the libtool script, but I'm sure you can
|
||||
do something less ugly.)
|
||||
|
||||
Hans-J. Boehm
|
||||
(The above contains my personal opinions, which are probably not shared
|
||||
by anyone else.)
|
||||
2
src/engine/boehm_gc/doc/README.uts
Normal file
2
src/engine/boehm_gc/doc/README.uts
Normal file
@@ -0,0 +1,2 @@
|
||||
Alistair Crooks supplied the port. He used Lexa C version 2.1.3 with
|
||||
-Xa to compile.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user