Add files using upload-large-folder tool
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- mosesdecoder/doc/PhraseDictionaryBitextSampling.howto +4 -0
- mosesdecoder/jam-files/boost-build/build/alias.jam +73 -0
- mosesdecoder/jam-files/boost-build/build/build-request.jam +322 -0
- mosesdecoder/jam-files/boost-build/build/configure.jam +237 -0
- mosesdecoder/jam-files/boost-build/build/feature.jam +1335 -0
- mosesdecoder/jam-files/boost-build/build/generators.jam +1380 -0
- mosesdecoder/jam-files/boost-build/build/modifiers.jam +232 -0
- mosesdecoder/jam-files/boost-build/build/property.jam +788 -0
- mosesdecoder/jam-files/boost-build/build/scanner.jam +153 -0
- mosesdecoder/jam-files/boost-build/build/toolset.jam +575 -0
- mosesdecoder/jam-files/boost-build/build/type.jam +425 -0
- mosesdecoder/jam-files/engine/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE +74 -0
- mosesdecoder/jam-files/engine/boehm_gc/SMakefile.amiga +177 -0
- mosesdecoder/jam-files/engine/boehm_gc/alpha_mach_dep.S +86 -0
- mosesdecoder/jam-files/engine/boehm_gc/backgraph.c +469 -0
- mosesdecoder/jam-files/engine/boehm_gc/bdw-gc.pc +10 -0
- mosesdecoder/jam-files/engine/boehm_gc/callprocs +4 -0
- mosesdecoder/jam-files/engine/boehm_gc/compile +142 -0
- mosesdecoder/jam-files/engine/boehm_gc/configure +0 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/README +548 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/README.amiga +322 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/README.changes +0 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/README.ews4800 +81 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/README.macros +82 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/README.rs6000 +9 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/doc.am +55 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/gcdescr.html +621 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/scale.html +210 -0
- mosesdecoder/jam-files/engine/boehm_gc/doc/simple_example.html +202 -0
- mosesdecoder/jam-files/engine/boehm_gc/finalize.c +869 -0
- mosesdecoder/jam-files/engine/boehm_gc/gc.mak +2220 -0
- mosesdecoder/jam-files/engine/boehm_gc/gc_cpp.cpp +2 -0
- mosesdecoder/jam-files/engine/boehm_gc/hpux_test_and_clear.s +21 -0
- mosesdecoder/jam-files/engine/boehm_gc/mips_ultrix_mach_dep.s +26 -0
- mosesdecoder/jam-files/engine/boehm_gc/misc.c +1177 -0
- mosesdecoder/jam-files/engine/boehm_gc/os_dep.c +0 -0
- mosesdecoder/jam-files/engine/boehm_gc/pcr_interface.c +179 -0
- mosesdecoder/jam-files/engine/boehm_gc/pthread_support.c +1495 -0
- mosesdecoder/jam-files/engine/boehm_gc/reclaim.c +608 -0
- mosesdecoder/jam-files/engine/boehm_gc/sparc_netbsd_mach_dep.s +34 -0
- mosesdecoder/jam-files/engine/boehm_gc/version.h +30 -0
- mosesdecoder/lm/common/compare.hh +174 -0
- mosesdecoder/lm/common/model_buffer.cc +91 -0
- mosesdecoder/lm/common/model_buffer.hh +63 -0
- mosesdecoder/lm/common/ngram_stream.hh +65 -0
- mosesdecoder/lm/common/print.hh +58 -0
- mosesdecoder/lm/common/size_option.cc +24 -0
- mosesdecoder/lm/common/size_option.hh +11 -0
- mosesdecoder/lm/common/special.hh +27 -0
- mosesdecoder/lm/config.cc +30 -0
mosesdecoder/doc/PhraseDictionaryBitextSampling.howto
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The documentation for memory-mapped, dynamic suffix arrays has moved to
|
| 2 |
+
http://www.statmt.org/moses/?n=Moses.AdvancedFeatures#ntoc40
|
| 3 |
+
|
| 4 |
+
Search for PhraseDictionaryBitextSampling.
|
mosesdecoder/jam-files/boost-build/build/alias.jam
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2003, 2004, 2006 Vladimir Prus
|
| 2 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 3 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 4 |
+
|
| 5 |
+
# This module defines the 'alias' rule and the associated target class.
|
| 6 |
+
#
|
| 7 |
+
# Alias is just a main target which returns its source targets without any
|
| 8 |
+
# processing. For example:
|
| 9 |
+
#
|
| 10 |
+
# alias bin : hello test_hello ;
|
| 11 |
+
# alias lib : helpers xml_parser ;
|
| 12 |
+
#
|
| 13 |
+
# Another important use of 'alias' is to conveniently group source files:
|
| 14 |
+
#
|
| 15 |
+
# alias platform-src : win.cpp : <os>NT ;
|
| 16 |
+
# alias platform-src : linux.cpp : <os>LINUX ;
|
| 17 |
+
# exe main : main.cpp platform-src ;
|
| 18 |
+
#
|
| 19 |
+
# Lastly, it is possible to create a local alias for some target, with different
|
| 20 |
+
# properties:
|
| 21 |
+
#
|
| 22 |
+
# alias big_lib : : @/external_project/big_lib/<link>static ;
|
| 23 |
+
#
|
| 24 |
+
|
| 25 |
+
import "class" : new ;
|
| 26 |
+
import project ;
|
| 27 |
+
import property-set ;
|
| 28 |
+
import targets ;
|
| 29 |
+
|
| 30 |
+
|
| 31 |
+
class alias-target-class : basic-target
|
| 32 |
+
{
|
| 33 |
+
rule __init__ ( name : project : sources * : requirements *
|
| 34 |
+
: default-build * : usage-requirements * )
|
| 35 |
+
{
|
| 36 |
+
basic-target.__init__ $(name) : $(project) : $(sources) :
|
| 37 |
+
$(requirements) : $(default-build) : $(usage-requirements) ;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
rule construct ( name : source-targets * : property-set )
|
| 41 |
+
{
|
| 42 |
+
return [ property-set.empty ] $(source-targets) ;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
rule compute-usage-requirements ( subvariant )
|
| 46 |
+
{
|
| 47 |
+
local base = [ basic-target.compute-usage-requirements $(subvariant) ] ;
|
| 48 |
+
return [ $(base).add [ $(subvariant).sources-usage-requirements ] ] ;
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
|
| 53 |
+
# Declares the 'alias' target. It will process its sources virtual-targets by
|
| 54 |
+
# returning them unaltered as its own constructed virtual-targets.
|
| 55 |
+
#
|
| 56 |
+
rule alias ( name : sources * : requirements * : default-build * :
|
| 57 |
+
usage-requirements * )
|
| 58 |
+
{
|
| 59 |
+
local project = [ project.current ] ;
|
| 60 |
+
|
| 61 |
+
targets.main-target-alternative
|
| 62 |
+
[ new alias-target-class $(name) : $(project)
|
| 63 |
+
: [ targets.main-target-sources $(sources) : $(name) : no-renaming ]
|
| 64 |
+
: [ targets.main-target-requirements $(requirements) : $(project) ]
|
| 65 |
+
: [ targets.main-target-default-build $(default-build) : $(project)
|
| 66 |
+
]
|
| 67 |
+
: [ targets.main-target-usage-requirements $(usage-requirements) :
|
| 68 |
+
$(project) ]
|
| 69 |
+
] ;
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
IMPORT $(__name__) : alias : : alias ;
|
mosesdecoder/jam-files/boost-build/build/build-request.jam
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2002 Dave Abrahams
|
| 2 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 3 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 4 |
+
|
| 5 |
+
import "class" : new ;
|
| 6 |
+
import sequence ;
|
| 7 |
+
import set ;
|
| 8 |
+
import regex ;
|
| 9 |
+
import feature ;
|
| 10 |
+
import property ;
|
| 11 |
+
import container ;
|
| 12 |
+
import string ;
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
# Transform property-set by applying f to each component property.
|
| 16 |
+
#
|
| 17 |
+
local rule apply-to-property-set ( f property-set )
|
| 18 |
+
{
|
| 19 |
+
local properties = [ feature.split $(property-set) ] ;
|
| 20 |
+
return [ string.join [ $(f) $(properties) ] : / ] ;
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
|
| 24 |
+
# Expand the given build request by combining all property-sets which do not
|
| 25 |
+
# specify conflicting non-free features. Expects all the project files to
|
| 26 |
+
# already be loaded.
|
| 27 |
+
#
|
| 28 |
+
rule expand-no-defaults ( property-sets * )
|
| 29 |
+
{
|
| 30 |
+
# First make all features and subfeatures explicit.
|
| 31 |
+
local expanded-property-sets = [ sequence.transform apply-to-property-set
|
| 32 |
+
feature.expand-subfeatures : $(property-sets) ] ;
|
| 33 |
+
|
| 34 |
+
# Now combine all of the expanded property-sets
|
| 35 |
+
local product = [ x-product $(expanded-property-sets) : $(feature-space) ] ;
|
| 36 |
+
|
| 37 |
+
return $(product) ;
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
|
| 41 |
+
# Implementation of x-product, below. Expects all the project files to already
|
| 42 |
+
# be loaded.
|
| 43 |
+
#
|
| 44 |
+
local rule x-product-aux ( property-sets + )
|
| 45 |
+
{
|
| 46 |
+
local result ;
|
| 47 |
+
local p = [ feature.split $(property-sets[1]) ] ;
|
| 48 |
+
local f = [ set.difference $(p:G) : [ feature.free-features ] ] ;
|
| 49 |
+
local seen ;
|
| 50 |
+
# No conflict with things used at a higher level?
|
| 51 |
+
if ! [ set.intersection $(f) : $(x-product-used) ]
|
| 52 |
+
{
|
| 53 |
+
local x-product-seen ;
|
| 54 |
+
{
|
| 55 |
+
# Do not mix in any conflicting features.
|
| 56 |
+
local x-product-used = $(x-product-used) $(f) ;
|
| 57 |
+
|
| 58 |
+
if $(property-sets[2])
|
| 59 |
+
{
|
| 60 |
+
local rest = [ x-product-aux $(property-sets[2-]) : $(feature-space) ] ;
|
| 61 |
+
result = $(property-sets[1])/$(rest) ;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
result ?= $(property-sets[1]) ;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
# If we did not encounter a conflicting feature lower down, do not
|
| 68 |
+
# recurse again.
|
| 69 |
+
if ! [ set.intersection $(f) : $(x-product-seen) ]
|
| 70 |
+
{
|
| 71 |
+
property-sets = ;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
seen = $(x-product-seen) ;
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
if $(property-sets[2])
|
| 78 |
+
{
|
| 79 |
+
result += [ x-product-aux $(property-sets[2-]) : $(feature-space) ] ;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
# Note that we have seen these features so that higher levels will recurse
|
| 83 |
+
# again without them set.
|
| 84 |
+
x-product-seen += $(f) $(seen) ;
|
| 85 |
+
return $(result) ;
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
# Return the cross-product of all elements of property-sets, less any that would
|
| 90 |
+
# contain conflicting values for single-valued features. Expects all the project
|
| 91 |
+
# files to already be loaded.
|
| 92 |
+
#
|
| 93 |
+
local rule x-product ( property-sets * )
|
| 94 |
+
{
|
| 95 |
+
if $(property-sets).non-empty
|
| 96 |
+
{
|
| 97 |
+
# Prepare some "scoped globals" that can be used by the implementation
|
| 98 |
+
# function, x-product-aux.
|
| 99 |
+
local x-product-seen x-product-used ;
|
| 100 |
+
return [ x-product-aux $(property-sets) : $(feature-space) ] ;
|
| 101 |
+
}
|
| 102 |
+
# Otherwise return empty.
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
|
| 106 |
+
# Returns true if either 'v' or the part of 'v' before the first '-' symbol is
|
| 107 |
+
# an implicit value. Expects all the project files to already be loaded.
|
| 108 |
+
#
|
| 109 |
+
local rule looks-like-implicit-value ( v )
|
| 110 |
+
{
|
| 111 |
+
if [ feature.is-implicit-value $(v) ]
|
| 112 |
+
{
|
| 113 |
+
return true ;
|
| 114 |
+
}
|
| 115 |
+
else
|
| 116 |
+
{
|
| 117 |
+
local split = [ regex.split $(v) - ] ;
|
| 118 |
+
if [ feature.is-implicit-value $(split[1]) ]
|
| 119 |
+
{
|
| 120 |
+
return true ;
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
}
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
# Takes the command line tokens (such as taken from the ARGV rule) and
|
| 127 |
+
# constructs a build request from them. Returns a vector of two vectors (where
|
| 128 |
+
# "vector" means container.jam's "vector"). First is the set of targets
|
| 129 |
+
# specified in the command line, and second is the set of requested build
|
| 130 |
+
# properties. Expects all the project files to already be loaded.
|
| 131 |
+
#
|
| 132 |
+
rule from-command-line ( command-line * )
|
| 133 |
+
{
|
| 134 |
+
local targets ;
|
| 135 |
+
local properties ;
|
| 136 |
+
|
| 137 |
+
command-line = $(command-line[2-]) ;
|
| 138 |
+
local skip-next = ;
|
| 139 |
+
for local e in $(command-line)
|
| 140 |
+
{
|
| 141 |
+
if $(skip-next)
|
| 142 |
+
{
|
| 143 |
+
skip-next = ;
|
| 144 |
+
}
|
| 145 |
+
else if ! [ MATCH "^(-).*" : $(e) ]
|
| 146 |
+
{
|
| 147 |
+
# Build request spec either has "=" in it or completely consists of
|
| 148 |
+
# implicit feature values.
|
| 149 |
+
local fs = feature-space ;
|
| 150 |
+
if [ MATCH "(.*=.*)" : $(e) ]
|
| 151 |
+
|| [ looks-like-implicit-value $(e:D=) : $(feature-space) ]
|
| 152 |
+
{
|
| 153 |
+
properties += [ convert-command-line-element $(e) :
|
| 154 |
+
$(feature-space) ] ;
|
| 155 |
+
}
|
| 156 |
+
else
|
| 157 |
+
{
|
| 158 |
+
targets += $(e) ;
|
| 159 |
+
}
|
| 160 |
+
}
|
| 161 |
+
else if [ MATCH "^(-[-ldjfsto])$" : $(e) ]
|
| 162 |
+
{
|
| 163 |
+
skip-next = true ;
|
| 164 |
+
}
|
| 165 |
+
}
|
| 166 |
+
return [ new vector
|
| 167 |
+
[ new vector $(targets) ]
|
| 168 |
+
[ new vector $(properties) ] ] ;
|
| 169 |
+
}
|
| 170 |
+
|
| 171 |
+
|
| 172 |
+
# Converts one element of command line build request specification into internal
|
| 173 |
+
# form. Expects all the project files to already be loaded.
|
| 174 |
+
#
|
| 175 |
+
local rule convert-command-line-element ( e )
|
| 176 |
+
{
|
| 177 |
+
local result ;
|
| 178 |
+
local parts = [ regex.split $(e) "/" ] ;
|
| 179 |
+
while $(parts)
|
| 180 |
+
{
|
| 181 |
+
local p = $(parts[1]) ;
|
| 182 |
+
local m = [ MATCH "([^=]*)=(.*)" : $(p) ] ;
|
| 183 |
+
local lresult ;
|
| 184 |
+
local feature ;
|
| 185 |
+
local values ;
|
| 186 |
+
if $(m)
|
| 187 |
+
{
|
| 188 |
+
feature = $(m[1]) ;
|
| 189 |
+
values = [ regex.split $(m[2]) "," ] ;
|
| 190 |
+
lresult = <$(feature)>$(values) ;
|
| 191 |
+
}
|
| 192 |
+
else
|
| 193 |
+
{
|
| 194 |
+
lresult = [ regex.split $(p) "," ] ;
|
| 195 |
+
}
|
| 196 |
+
|
| 197 |
+
if $(feature) && free in [ feature.attributes $(feature) ]
|
| 198 |
+
{
|
| 199 |
+
# If we have free feature, then the value is everything
|
| 200 |
+
# until the end of the command line token. Slashes in
|
| 201 |
+
# the following string are not taked to mean separation
|
| 202 |
+
# of properties. Commas are also not interpreted specially.
|
| 203 |
+
values = $(values:J=,) ;
|
| 204 |
+
values = $(values) $(parts[2-]) ;
|
| 205 |
+
values = $(values:J=/) ;
|
| 206 |
+
lresult = <$(feature)>$(values) ;
|
| 207 |
+
parts = ;
|
| 208 |
+
}
|
| 209 |
+
|
| 210 |
+
if ! [ MATCH (.*-.*) : $(p) ]
|
| 211 |
+
{
|
| 212 |
+
# property.validate cannot handle subfeatures, so we avoid the check
|
| 213 |
+
# here.
|
| 214 |
+
for local p in $(lresult)
|
| 215 |
+
{
|
| 216 |
+
property.validate $(p) : $(feature-space) ;
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
if ! $(result)
|
| 221 |
+
{
|
| 222 |
+
result = $(lresult) ;
|
| 223 |
+
}
|
| 224 |
+
else
|
| 225 |
+
{
|
| 226 |
+
result = $(result)/$(lresult) ;
|
| 227 |
+
}
|
| 228 |
+
|
| 229 |
+
parts = $(parts[2-]) ;
|
| 230 |
+
}
|
| 231 |
+
|
| 232 |
+
return $(result) ;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
|
| 236 |
+
rule __test__ ( )
|
| 237 |
+
{
|
| 238 |
+
import assert ;
|
| 239 |
+
import feature ;
|
| 240 |
+
|
| 241 |
+
feature.prepare-test build-request-test-temp ;
|
| 242 |
+
|
| 243 |
+
import build-request ;
|
| 244 |
+
import build-request : expand-no-defaults : build-request.expand-no-defaults ;
|
| 245 |
+
import errors : try catch ;
|
| 246 |
+
import feature : feature subfeature ;
|
| 247 |
+
|
| 248 |
+
feature toolset : gcc msvc borland : implicit ;
|
| 249 |
+
subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4
|
| 250 |
+
3.0 3.0.1 3.0.2 : optional ;
|
| 251 |
+
|
| 252 |
+
feature variant : debug release : implicit composite ;
|
| 253 |
+
feature inlining : on off ;
|
| 254 |
+
feature "include" : : free ;
|
| 255 |
+
|
| 256 |
+
feature stdlib : native stlport : implicit ;
|
| 257 |
+
|
| 258 |
+
feature runtime-link : dynamic static : symmetric ;
|
| 259 |
+
|
| 260 |
+
# Empty build requests should expand to empty.
|
| 261 |
+
assert.result
|
| 262 |
+
: build-request.expand-no-defaults ;
|
| 263 |
+
|
| 264 |
+
assert.result
|
| 265 |
+
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
|
| 266 |
+
<toolset>msvc/<stdlib>stlport/<variant>debug
|
| 267 |
+
<toolset>msvc/<variant>debug
|
| 268 |
+
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc/stlport msvc debug ;
|
| 269 |
+
|
| 270 |
+
assert.result
|
| 271 |
+
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug
|
| 272 |
+
<toolset>msvc/<variant>debug
|
| 273 |
+
<variant>debug/<toolset>msvc/<stdlib>stlport
|
| 274 |
+
: build-request.expand-no-defaults gcc-3.0.1/stlport msvc debug msvc/stlport ;
|
| 275 |
+
|
| 276 |
+
assert.result
|
| 277 |
+
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<inlining>off
|
| 278 |
+
<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>release/<inlining>off
|
| 279 |
+
: build-request.expand-no-defaults gcc-3.0.1/stlport debug release <inlining>off ;
|
| 280 |
+
|
| 281 |
+
assert.result
|
| 282 |
+
<include>a/b/c/<toolset>gcc/<toolset-gcc:version>3.0.1/<stdlib>stlport/<variant>debug/<include>x/y/z
|
| 283 |
+
<include>a/b/c/<toolset>msvc/<stdlib>stlport/<variant>debug/<include>x/y/z
|
| 284 |
+
<include>a/b/c/<toolset>msvc/<variant>debug/<include>x/y/z
|
| 285 |
+
: build-request.expand-no-defaults <include>a/b/c gcc-3.0.1/stlport msvc/stlport msvc debug <include>x/y/z ;
|
| 286 |
+
|
| 287 |
+
local r ;
|
| 288 |
+
|
| 289 |
+
r = [ build-request.from-command-line bjam debug runtime-link=dynamic ] ;
|
| 290 |
+
assert.equal [ $(r).get-at 1 ] : ;
|
| 291 |
+
assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic ;
|
| 292 |
+
|
| 293 |
+
try ;
|
| 294 |
+
{
|
| 295 |
+
build-request.from-command-line bjam gcc/debug runtime-link=dynamic/static ;
|
| 296 |
+
}
|
| 297 |
+
catch \"static\" is not a value of an implicit feature ;
|
| 298 |
+
|
| 299 |
+
r = [ build-request.from-command-line bjam -d2 --debug debug target runtime-link=dynamic ] ;
|
| 300 |
+
assert.equal [ $(r).get-at 1 ] : target ;
|
| 301 |
+
assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic ;
|
| 302 |
+
|
| 303 |
+
r = [ build-request.from-command-line bjam debug runtime-link=dynamic,static ] ;
|
| 304 |
+
assert.equal [ $(r).get-at 1 ] : ;
|
| 305 |
+
assert.equal [ $(r).get-at 2 ] : debug <runtime-link>dynamic <runtime-link>static ;
|
| 306 |
+
|
| 307 |
+
r = [ build-request.from-command-line bjam debug gcc/runtime-link=dynamic,static ] ;
|
| 308 |
+
assert.equal [ $(r).get-at 1 ] : ;
|
| 309 |
+
assert.equal [ $(r).get-at 2 ] : debug gcc/<runtime-link>dynamic
|
| 310 |
+
gcc/<runtime-link>static ;
|
| 311 |
+
|
| 312 |
+
r = [ build-request.from-command-line bjam msvc gcc,borland/runtime-link=static ] ;
|
| 313 |
+
assert.equal [ $(r).get-at 1 ] : ;
|
| 314 |
+
assert.equal [ $(r).get-at 2 ] : msvc gcc/<runtime-link>static
|
| 315 |
+
borland/<runtime-link>static ;
|
| 316 |
+
|
| 317 |
+
r = [ build-request.from-command-line bjam gcc-3.0 ] ;
|
| 318 |
+
assert.equal [ $(r).get-at 1 ] : ;
|
| 319 |
+
assert.equal [ $(r).get-at 2 ] : gcc-3.0 ;
|
| 320 |
+
|
| 321 |
+
feature.finish-test build-request-test-temp ;
|
| 322 |
+
}
|
mosesdecoder/jam-files/boost-build/build/configure.jam
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright (c) 2010 Vladimir Prus.
|
| 2 |
+
#
|
| 3 |
+
# Use, modification and distribution is subject to the Boost Software
|
| 4 |
+
# License Version 1.0. (See accompanying file LICENSE_1_0.txt or
|
| 5 |
+
# http://www.boost.org/LICENSE_1_0.txt)
|
| 6 |
+
|
| 7 |
+
# This module defines function to help with two main tasks:
|
| 8 |
+
#
|
| 9 |
+
# - Discovering build-time configuration for the purposes of adjusting
|
| 10 |
+
# build process.
|
| 11 |
+
# - Reporting what is built, and how it is configured.
|
| 12 |
+
|
| 13 |
+
import targets ;
|
| 14 |
+
import errors ;
|
| 15 |
+
import targets ;
|
| 16 |
+
import sequence ;
|
| 17 |
+
import property ;
|
| 18 |
+
import property-set ;
|
| 19 |
+
import "class" : new ;
|
| 20 |
+
import common ;
|
| 21 |
+
import path ;
|
| 22 |
+
|
| 23 |
+
rule log-summary ( )
|
| 24 |
+
{
|
| 25 |
+
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
.width = 30 ;
|
| 29 |
+
|
| 30 |
+
rule set-width ( width )
|
| 31 |
+
{
|
| 32 |
+
.width = $(width) ;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
# Declare that the components specified by the parameter exist.
|
| 36 |
+
rule register-components ( components * )
|
| 37 |
+
{
|
| 38 |
+
.components += $(components) ;
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
# Declare that the components specified by the parameters will
|
| 42 |
+
# be build.
|
| 43 |
+
rule components-building ( components * )
|
| 44 |
+
{
|
| 45 |
+
.built-components += $(components) ;
|
| 46 |
+
}
|
| 47 |
+
|
| 48 |
+
# Report something about component configuration that the
|
| 49 |
+
# user should better know.
|
| 50 |
+
rule log-component-configuration ( component : message )
|
| 51 |
+
{
|
| 52 |
+
# FIXME: implement per-property-set logs
|
| 53 |
+
.component-logs.$(component) += $(message) ;
|
| 54 |
+
}
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
rule log-check-result ( result )
|
| 59 |
+
{
|
| 60 |
+
if ! $(.announced-checks)
|
| 61 |
+
{
|
| 62 |
+
ECHO "Performing configuration checks\n" ;
|
| 63 |
+
.announced-checks = 1 ;
|
| 64 |
+
}
|
| 65 |
+
|
| 66 |
+
ECHO $(result) ;
|
| 67 |
+
#.check-results += $(result) ;
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
rule log-library-search-result ( library : result )
|
| 71 |
+
{
|
| 72 |
+
local x = [ PAD " - $(library) : $(result)" : $(.width) ] ;
|
| 73 |
+
log-check-result "$(x)" ;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
rule print-component-configuration ( )
|
| 77 |
+
{
|
| 78 |
+
local c = [ sequence.unique $(.components) ] ;
|
| 79 |
+
|
| 80 |
+
ECHO "\nComponent configuration:\n" ;
|
| 81 |
+
for c in $(.components)
|
| 82 |
+
{
|
| 83 |
+
local s ;
|
| 84 |
+
if $(c) in $(.built-components)
|
| 85 |
+
{
|
| 86 |
+
s = "building" ;
|
| 87 |
+
}
|
| 88 |
+
else
|
| 89 |
+
{
|
| 90 |
+
s = "not building" ;
|
| 91 |
+
}
|
| 92 |
+
ECHO [ PAD " - $(c)" : $(.width) ] ": $(s)" ;
|
| 93 |
+
for local m in $(.component-logs.$(c))
|
| 94 |
+
{
|
| 95 |
+
ECHO " -" $(m) ;
|
| 96 |
+
}
|
| 97 |
+
}
|
| 98 |
+
ECHO ;
|
| 99 |
+
}
|
| 100 |
+
|
| 101 |
+
rule print-configure-checks-summary ( )
|
| 102 |
+
{
|
| 103 |
+
# FIXME: the problem with that approach is tha
|
| 104 |
+
# the user sees checks summary when all checks are
|
| 105 |
+
# done, and has no progress reporting while the
|
| 106 |
+
# checks are being executed.
|
| 107 |
+
if $(.check-results)
|
| 108 |
+
{
|
| 109 |
+
ECHO "Configuration checks summary\n" ;
|
| 110 |
+
|
| 111 |
+
for local r in $(.check-results)
|
| 112 |
+
{
|
| 113 |
+
ECHO $(r) ;
|
| 114 |
+
}
|
| 115 |
+
ECHO ;
|
| 116 |
+
}
|
| 117 |
+
}
|
| 118 |
+
|
| 119 |
+
# Attempt to build a metatarget named by 'metatarget-reference'
|
| 120 |
+
# in context of 'project' with properties 'ps'.
|
| 121 |
+
# Returns non-empty value if build is OK.
|
| 122 |
+
rule builds-raw ( metatarget-reference : project : ps : what : retry ? )
|
| 123 |
+
{
|
| 124 |
+
local result ;
|
| 125 |
+
|
| 126 |
+
if ! $(retry) && ! $(.$(what)-tested.$(ps))
|
| 127 |
+
{
|
| 128 |
+
.$(what)-tested.$(ps) = true ;
|
| 129 |
+
|
| 130 |
+
local targets = [ targets.generate-from-reference
|
| 131 |
+
$(metatarget-reference) : $(project) : $(ps) ] ;
|
| 132 |
+
|
| 133 |
+
local jam-targets ;
|
| 134 |
+
for local t in $(targets[2-])
|
| 135 |
+
{
|
| 136 |
+
jam-targets += [ $(t).actualize ] ;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
if ! UPDATE_NOW in [ RULENAMES ]
|
| 140 |
+
{
|
| 141 |
+
# Cannot determine. Assume existance.
|
| 142 |
+
}
|
| 143 |
+
else
|
| 144 |
+
{
|
| 145 |
+
local x = [ PAD " - $(what)" : $(.width) ] ;
|
| 146 |
+
if [ UPDATE_NOW $(jam-targets) :
|
| 147 |
+
$(.log-fd) : ignore-minus-n : ignore-minus-q ]
|
| 148 |
+
{
|
| 149 |
+
.$(what)-supported.$(ps) = yes ;
|
| 150 |
+
result = true ;
|
| 151 |
+
log-check-result "$(x) : yes" ;
|
| 152 |
+
}
|
| 153 |
+
else
|
| 154 |
+
{
|
| 155 |
+
log-check-result "$(x) : no" ;
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
return $(result) ;
|
| 159 |
+
}
|
| 160 |
+
else
|
| 161 |
+
{
|
| 162 |
+
return $(.$(what)-supported.$(ps)) ;
|
| 163 |
+
}
|
| 164 |
+
}
|
| 165 |
+
|
| 166 |
+
rule builds ( metatarget-reference : properties * : what ? : retry ? )
|
| 167 |
+
{
|
| 168 |
+
what ?= "$(metatarget-reference) builds" ;
|
| 169 |
+
|
| 170 |
+
# FIXME: this should not be hardcoded. Other checks might
|
| 171 |
+
# want to consider different set of features as relevant.
|
| 172 |
+
local toolset = [ property.select <toolset> : $(properties) ] ;
|
| 173 |
+
local toolset-version-property = "<toolset-$(toolset:G=):version>" ;
|
| 174 |
+
local relevant = [ property.select <target-os> <toolset> $(toolset-version-property)
|
| 175 |
+
<address-model> <architecture>
|
| 176 |
+
: $(properties) ] ;
|
| 177 |
+
local ps = [ property-set.create $(relevant) ] ;
|
| 178 |
+
local t = [ targets.current ] ;
|
| 179 |
+
local p = [ $(t).project ] ;
|
| 180 |
+
|
| 181 |
+
return [ builds-raw $(metatarget-reference) : $(p) : $(ps) : $(what) : $(retry) ] ;
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
|
| 185 |
+
# Called by Boost.Build startup code to specify name of a file
|
| 186 |
+
# that will receive results of configure checks. This
|
| 187 |
+
# should never be called by users.
|
| 188 |
+
rule set-log-file ( log-file )
|
| 189 |
+
{
|
| 190 |
+
path.makedirs [ path.parent $(log-file) ] ;
|
| 191 |
+
|
| 192 |
+
.log-fd = [ FILE_OPEN $(log-file) : "w" ] ;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
# Frontend rules
|
| 196 |
+
|
| 197 |
+
class check-target-builds-worker
|
| 198 |
+
{
|
| 199 |
+
import configure ;
|
| 200 |
+
import property-set ;
|
| 201 |
+
import targets ;
|
| 202 |
+
import property ;
|
| 203 |
+
|
| 204 |
+
rule __init__ ( target message ? : true-properties * : false-properties * )
|
| 205 |
+
{
|
| 206 |
+
self.target = $(target) ;
|
| 207 |
+
self.message = $(message) ;
|
| 208 |
+
self.true-properties = $(true-properties) ;
|
| 209 |
+
self.false-properties = $(false-properties) ;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
rule check ( properties * )
|
| 213 |
+
{
|
| 214 |
+
local choosen ;
|
| 215 |
+
if [ configure.builds $(self.target) : $(properties) : $(self.message) ]
|
| 216 |
+
{
|
| 217 |
+
choosen = $(self.true-properties) ;
|
| 218 |
+
}
|
| 219 |
+
else
|
| 220 |
+
{
|
| 221 |
+
choosen = $(self.false-properties) ;
|
| 222 |
+
}
|
| 223 |
+
return [ property.evaluate-conditionals-in-context $(choosen) : $(properties) ] ;
|
| 224 |
+
}
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
|
| 228 |
+
rule check-target-builds ( target message ? : true-properties * : false-properties * )
|
| 229 |
+
{
|
| 230 |
+
local instance = [ new check-target-builds-worker $(target) $(message) : $(true-properties)
|
| 231 |
+
: $(false-properties) ] ;
|
| 232 |
+
return <conditional>@$(instance).check ;
|
| 233 |
+
}
|
| 234 |
+
|
| 235 |
+
IMPORT $(__name__) : check-target-builds : : check-target-builds ;
|
| 236 |
+
|
| 237 |
+
|
mosesdecoder/jam-files/boost-build/build/feature.jam
ADDED
|
@@ -0,0 +1,1335 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2001, 2002, 2003 Dave Abrahams
|
| 2 |
+
# Copyright 2002, 2006 Rene Rivera
|
| 3 |
+
# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
|
| 4 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 5 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 6 |
+
|
| 7 |
+
import assert : * ;
|
| 8 |
+
import "class" : * ;
|
| 9 |
+
import errors : lol->list ;
|
| 10 |
+
import indirect ;
|
| 11 |
+
import modules ;
|
| 12 |
+
import regex ;
|
| 13 |
+
import sequence ;
|
| 14 |
+
import set ;
|
| 15 |
+
import utility ;
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
local rule setup ( )
|
| 19 |
+
{
|
| 20 |
+
.all-attributes =
|
| 21 |
+
implicit
|
| 22 |
+
composite
|
| 23 |
+
optional
|
| 24 |
+
symmetric
|
| 25 |
+
free
|
| 26 |
+
incidental
|
| 27 |
+
path
|
| 28 |
+
dependency
|
| 29 |
+
propagated
|
| 30 |
+
link-incompatible
|
| 31 |
+
subfeature
|
| 32 |
+
order-sensitive
|
| 33 |
+
;
|
| 34 |
+
|
| 35 |
+
.all-features = ;
|
| 36 |
+
.all-subfeatures = ;
|
| 37 |
+
.all-top-features = ; # non-subfeatures
|
| 38 |
+
.all-implicit-values = ;
|
| 39 |
+
}
|
| 40 |
+
setup ;
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
# Prepare a fresh space to test in by moving all global variable settings into
|
| 44 |
+
# the given temporary module and erasing them here.
|
| 45 |
+
#
|
| 46 |
+
rule prepare-test ( temp-module )
|
| 47 |
+
{
|
| 48 |
+
DELETE_MODULE $(temp-module) ;
|
| 49 |
+
|
| 50 |
+
# Transfer globals to temp-module.
|
| 51 |
+
for local v in [ VARNAMES feature ]
|
| 52 |
+
{
|
| 53 |
+
if [ MATCH (\\.) : $(v) ]
|
| 54 |
+
{
|
| 55 |
+
modules.poke $(temp-module) : $(v) : $($(v)) ;
|
| 56 |
+
$(v) = ;
|
| 57 |
+
}
|
| 58 |
+
}
|
| 59 |
+
setup ;
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
|
| 63 |
+
# Clear out all global variables and recover all variables from the given
|
| 64 |
+
# temporary module.
|
| 65 |
+
#
|
| 66 |
+
rule finish-test ( temp-module )
|
| 67 |
+
{
|
| 68 |
+
# Clear globals.
|
| 69 |
+
for local v in [ VARNAMES feature ]
|
| 70 |
+
{
|
| 71 |
+
if [ MATCH (\\.) : $(v) ]
|
| 72 |
+
{
|
| 73 |
+
$(v) = ;
|
| 74 |
+
}
|
| 75 |
+
}
|
| 76 |
+
|
| 77 |
+
for local v in [ VARNAMES $(temp-module) ]
|
| 78 |
+
{
|
| 79 |
+
$(v) = [ modules.peek $(temp-module) : $(v) ] ;
|
| 80 |
+
}
|
| 81 |
+
DELETE_MODULE $(temp-module) ;
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
|
| 85 |
+
# Transform features by bracketing any elements which are not already bracketed
|
| 86 |
+
# by "<>".
|
| 87 |
+
#
|
| 88 |
+
local rule grist ( features * )
|
| 89 |
+
{
|
| 90 |
+
local empty = "" ;
|
| 91 |
+
return $(empty:G=$(features)) ;
|
| 92 |
+
}
|
| 93 |
+
|
| 94 |
+
|
| 95 |
+
# Declare a new feature with the given name, values, and attributes.
|
| 96 |
+
#
|
| 97 |
+
rule feature (
|
| 98 |
+
name # Feature name.
|
| 99 |
+
: values * # Allowable values - may be extended later using feature.extend.
|
| 100 |
+
: attributes * # Feature attributes (e.g. implicit, free, propagated...).
|
| 101 |
+
)
|
| 102 |
+
{
|
| 103 |
+
name = [ grist $(name) ] ;
|
| 104 |
+
|
| 105 |
+
local error ;
|
| 106 |
+
|
| 107 |
+
# Check for any unknown attributes.
|
| 108 |
+
if ! ( $(attributes) in $(.all-attributes) )
|
| 109 |
+
{
|
| 110 |
+
error = unknown attributes:
|
| 111 |
+
[ set.difference $(attributes) : $(.all-attributes) ] ;
|
| 112 |
+
}
|
| 113 |
+
else if $(name) in $(.all-features)
|
| 114 |
+
{
|
| 115 |
+
error = feature already defined: ;
|
| 116 |
+
}
|
| 117 |
+
else if implicit in $(attributes) && free in $(attributes)
|
| 118 |
+
{
|
| 119 |
+
error = free features cannot also be implicit ;
|
| 120 |
+
}
|
| 121 |
+
else if free in $(attributes) && propagated in $(attributes)
|
| 122 |
+
{
|
| 123 |
+
error = free features cannot be propagated ;
|
| 124 |
+
}
|
| 125 |
+
else
|
| 126 |
+
{
|
| 127 |
+
local m = [ MATCH (.*=.*) : $(values) ] ;
|
| 128 |
+
if $(m[1])
|
| 129 |
+
{
|
| 130 |
+
error = "feature value may not contain '='" ;
|
| 131 |
+
}
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
if $(error)
|
| 135 |
+
{
|
| 136 |
+
errors.error $(error)
|
| 137 |
+
: "in" feature declaration:
|
| 138 |
+
: feature [ lol->list $(1) : $(2) : $(3) ] ;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
$(name).values ?= ;
|
| 142 |
+
$(name).attributes = $(attributes) ;
|
| 143 |
+
$(name).subfeatures ?= ;
|
| 144 |
+
$(attributes).features += $(name) ;
|
| 145 |
+
|
| 146 |
+
.all-features += $(name) ;
|
| 147 |
+
if subfeature in $(attributes)
|
| 148 |
+
{
|
| 149 |
+
.all-subfeatures += $(name) ;
|
| 150 |
+
}
|
| 151 |
+
else
|
| 152 |
+
{
|
| 153 |
+
.all-top-features += $(name) ;
|
| 154 |
+
}
|
| 155 |
+
extend $(name) : $(values) ;
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
|
| 159 |
+
# Sets the default value of the given feature, overriding any previous default.
|
| 160 |
+
#
|
| 161 |
+
rule set-default ( feature : value )
|
| 162 |
+
{
|
| 163 |
+
local f = [ grist $(feature) ] ;
|
| 164 |
+
local a = $($(f).attributes) ;
|
| 165 |
+
local bad-attribute = ;
|
| 166 |
+
if free in $(a)
|
| 167 |
+
{
|
| 168 |
+
bad-attribute = free ;
|
| 169 |
+
}
|
| 170 |
+
else if optional in $(a)
|
| 171 |
+
{
|
| 172 |
+
bad-attribute = optional ;
|
| 173 |
+
}
|
| 174 |
+
if $(bad-attribute)
|
| 175 |
+
{
|
| 176 |
+
errors.error "$(bad-attribute) property $(f) cannot have a default." ;
|
| 177 |
+
}
|
| 178 |
+
if ! $(value) in $($(f).values)
|
| 179 |
+
{
|
| 180 |
+
errors.error "The specified default value, '$(value)' is invalid"
|
| 181 |
+
: "allowed values are: " $($(f).values) ;
|
| 182 |
+
}
|
| 183 |
+
$(f).default = $(value) ;
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
|
| 187 |
+
# Returns the default property values for the given features.
|
| 188 |
+
#
|
| 189 |
+
rule defaults ( features * )
|
| 190 |
+
{
|
| 191 |
+
local result ;
|
| 192 |
+
for local f in $(features)
|
| 193 |
+
{
|
| 194 |
+
local gf = $(:E=:G=$(f)) ;
|
| 195 |
+
local a = $($(gf).attributes) ;
|
| 196 |
+
if ( free in $(a) ) || ( optional in $(a) )
|
| 197 |
+
{
|
| 198 |
+
}
|
| 199 |
+
else
|
| 200 |
+
{
|
| 201 |
+
result += $(gf)$($(gf).default) ;
|
| 202 |
+
}
|
| 203 |
+
}
|
| 204 |
+
return $(result) ;
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
# Returns true iff all 'names' elements are valid features.
|
| 209 |
+
#
|
| 210 |
+
rule valid ( names + )
|
| 211 |
+
{
|
| 212 |
+
if $(names) in $(.all-features)
|
| 213 |
+
{
|
| 214 |
+
return true ;
|
| 215 |
+
}
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
|
| 219 |
+
# Returns the attibutes of the given feature.
|
| 220 |
+
#
|
| 221 |
+
rule attributes ( feature )
|
| 222 |
+
{
|
| 223 |
+
return $($(:E=:G=$(feature)).attributes) ;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
|
| 227 |
+
# Returns the values of the given feature.
|
| 228 |
+
#
|
| 229 |
+
rule values ( feature )
|
| 230 |
+
{
|
| 231 |
+
return $($(:E=:G=$(feature)).values) ;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
# Returns true iff 'value-string' is a value-string of an implicit feature.
|
| 236 |
+
#
|
| 237 |
+
rule is-implicit-value ( value-string )
|
| 238 |
+
{
|
| 239 |
+
local v = [ regex.split $(value-string) - ] ;
|
| 240 |
+
local failed ;
|
| 241 |
+
if ! $(v[1]) in $(.all-implicit-values)
|
| 242 |
+
{
|
| 243 |
+
failed = true ;
|
| 244 |
+
}
|
| 245 |
+
else
|
| 246 |
+
{
|
| 247 |
+
local feature = $($(v[1]).implicit-feature) ;
|
| 248 |
+
for local subvalue in $(v[2-])
|
| 249 |
+
{
|
| 250 |
+
if ! [ find-implied-subfeature $(feature) $(subvalue) : $(v[1]) ]
|
| 251 |
+
{
|
| 252 |
+
failed = true ;
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
if ! $(failed)
|
| 258 |
+
{
|
| 259 |
+
return true ;
|
| 260 |
+
}
|
| 261 |
+
}
|
| 262 |
+
|
| 263 |
+
|
| 264 |
+
# Returns the implicit feature associated with the given implicit value.
|
| 265 |
+
#
|
| 266 |
+
rule implied-feature ( implicit-value )
|
| 267 |
+
{
|
| 268 |
+
local components = [ regex.split $(implicit-value) "-" ] ;
|
| 269 |
+
|
| 270 |
+
local feature = $($(components[1]).implicit-feature) ;
|
| 271 |
+
if ! $(feature)
|
| 272 |
+
{
|
| 273 |
+
errors.error \"$(implicit-value)\" is not a value of an implicit feature ;
|
| 274 |
+
feature = "" ; # Keep testing happy; it expects a result.
|
| 275 |
+
}
|
| 276 |
+
return $(feature) ;
|
| 277 |
+
}
|
| 278 |
+
|
| 279 |
+
|
| 280 |
+
local rule find-implied-subfeature ( feature subvalue : value-string ? )
|
| 281 |
+
{
|
| 282 |
+
# Feature should be of the form <feature-name>.
|
| 283 |
+
if $(feature) != $(feature:G)
|
| 284 |
+
{
|
| 285 |
+
errors.error invalid feature $(feature) ;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
return $($(feature)$(value-string:E="")<>$(subvalue).subfeature) ;
|
| 289 |
+
}
|
| 290 |
+
|
| 291 |
+
|
| 292 |
+
# Given a feature and a value of one of its subfeatures, find the name of the
|
| 293 |
+
# subfeature. If value-string is supplied, looks for implied subfeatures that
|
| 294 |
+
# are specific to that value of feature
|
| 295 |
+
#
|
| 296 |
+
rule implied-subfeature (
|
| 297 |
+
feature # The main feature name.
|
| 298 |
+
subvalue # The value of one of its subfeatures.
|
| 299 |
+
: value-string ? # The value of the main feature.
|
| 300 |
+
)
|
| 301 |
+
{
|
| 302 |
+
local subfeature = [ find-implied-subfeature $(feature) $(subvalue)
|
| 303 |
+
: $(value-string) ] ;
|
| 304 |
+
if ! $(subfeature)
|
| 305 |
+
{
|
| 306 |
+
value-string ?= "" ;
|
| 307 |
+
errors.error \"$(subvalue)\" is not a known subfeature value of
|
| 308 |
+
$(feature)$(value-string) ;
|
| 309 |
+
}
|
| 310 |
+
return $(subfeature) ;
|
| 311 |
+
}
|
| 312 |
+
|
| 313 |
+
|
| 314 |
+
# Generate an error if the feature is unknown.
|
| 315 |
+
#
|
| 316 |
+
local rule validate-feature ( feature )
|
| 317 |
+
{
|
| 318 |
+
if ! $(feature) in $(.all-features)
|
| 319 |
+
{
|
| 320 |
+
errors.error unknown feature \"$(feature)\" ;
|
| 321 |
+
}
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
|
| 325 |
+
# Given a feature and its value or just a value corresponding to an implicit
|
| 326 |
+
# feature, returns a property set consisting of all component subfeatures and
|
| 327 |
+
# their values. For example all the following calls:
|
| 328 |
+
#
|
| 329 |
+
# expand-subfeatures-aux <toolset>gcc-2.95.2-linux-x86
|
| 330 |
+
# expand-subfeatures-aux gcc-2.95.2-linux-x86
|
| 331 |
+
#
|
| 332 |
+
# return:
|
| 333 |
+
#
|
| 334 |
+
# <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
|
| 335 |
+
#
|
| 336 |
+
local rule expand-subfeatures-aux (
|
| 337 |
+
feature ? # Feature name or empty if value corresponds to an
|
| 338 |
+
# implicit property.
|
| 339 |
+
: value # Feature value.
|
| 340 |
+
: dont-validate ? # If set, no value string validation will be done.
|
| 341 |
+
)
|
| 342 |
+
{
|
| 343 |
+
if $(feature)
|
| 344 |
+
{
|
| 345 |
+
feature = $(feature) ;
|
| 346 |
+
}
|
| 347 |
+
|
| 348 |
+
if ! $(feature)
|
| 349 |
+
{
|
| 350 |
+
feature = [ implied-feature $(value) ] ;
|
| 351 |
+
}
|
| 352 |
+
else
|
| 353 |
+
{
|
| 354 |
+
validate-feature $(feature) ;
|
| 355 |
+
}
|
| 356 |
+
if ! $(dont-validate)
|
| 357 |
+
{
|
| 358 |
+
validate-value-string $(feature) $(value) ;
|
| 359 |
+
}
|
| 360 |
+
|
| 361 |
+
local components = [ regex.split $(value) "-" ] ;
|
| 362 |
+
|
| 363 |
+
# Get the top-level feature's value.
|
| 364 |
+
local value = $(components[1]:G=) ;
|
| 365 |
+
|
| 366 |
+
local result = $(components[1]:G=$(feature)) ;
|
| 367 |
+
|
| 368 |
+
local subvalues = $(components[2-]) ;
|
| 369 |
+
while $(subvalues)
|
| 370 |
+
{
|
| 371 |
+
local subvalue = $(subvalues[1]) ; # Pop the head off of subvalues.
|
| 372 |
+
subvalues = $(subvalues[2-]) ;
|
| 373 |
+
|
| 374 |
+
local subfeature = [ find-implied-subfeature $(feature) $(subvalue) :
|
| 375 |
+
$(value) ] ;
|
| 376 |
+
|
| 377 |
+
# If no subfeature was found reconstitute the value string and use that.
|
| 378 |
+
if ! $(subfeature)
|
| 379 |
+
{
|
| 380 |
+
result = $(components:J=-) ;
|
| 381 |
+
result = $(result:G=$(feature)) ;
|
| 382 |
+
subvalues = ; # Stop looping.
|
| 383 |
+
}
|
| 384 |
+
else
|
| 385 |
+
{
|
| 386 |
+
local f = [ MATCH ^<(.*)>$ : $(feature) ] ;
|
| 387 |
+
result += $(subvalue:G=$(f)-$(subfeature)) ;
|
| 388 |
+
}
|
| 389 |
+
}
|
| 390 |
+
|
| 391 |
+
return $(result) ;
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
|
| 395 |
+
# Make all elements of properties corresponding to implicit features explicit,
|
| 396 |
+
# and express all subfeature values as separate properties in their own right.
|
| 397 |
+
# For example, all of the following properties
|
| 398 |
+
#
|
| 399 |
+
# gcc-2.95.2-linux-x86
|
| 400 |
+
# <toolset>gcc-2.95.2-linux-x86
|
| 401 |
+
#
|
| 402 |
+
# might expand to
|
| 403 |
+
#
|
| 404 |
+
# <toolset>gcc <toolset-version>2.95.2 <toolset-os>linux <toolset-cpu>x86
|
| 405 |
+
#
|
| 406 |
+
rule expand-subfeatures (
|
| 407 |
+
properties * # Property set with elements of the form
|
| 408 |
+
# <feature>value-string or just value-string in the case
|
| 409 |
+
# of implicit features.
|
| 410 |
+
: dont-validate ?
|
| 411 |
+
)
|
| 412 |
+
{
|
| 413 |
+
local result ;
|
| 414 |
+
for local p in $(properties)
|
| 415 |
+
{
|
| 416 |
+
# Don't expand subfeatures in subfeatures
|
| 417 |
+
if ! [ MATCH "(:)" : $(p:G) ]
|
| 418 |
+
{
|
| 419 |
+
result += [ expand-subfeatures-aux $(p:G) : $(p:G=) : $(dont-validate) ] ;
|
| 420 |
+
}
|
| 421 |
+
else
|
| 422 |
+
{
|
| 423 |
+
result += $(p) ;
|
| 424 |
+
}
|
| 425 |
+
}
|
| 426 |
+
return $(result) ;
|
| 427 |
+
}
|
| 428 |
+
|
| 429 |
+
|
| 430 |
+
# Helper for extend, below. Handles the feature case.
|
| 431 |
+
#
|
| 432 |
+
local rule extend-feature ( feature : values * )
|
| 433 |
+
{
|
| 434 |
+
feature = [ grist $(feature) ] ;
|
| 435 |
+
validate-feature $(feature) ;
|
| 436 |
+
if implicit in $($(feature).attributes)
|
| 437 |
+
{
|
| 438 |
+
for local v in $(values)
|
| 439 |
+
{
|
| 440 |
+
if $($(v).implicit-feature)
|
| 441 |
+
{
|
| 442 |
+
errors.error $(v) is already associated with the \"$($(v).implicit-feature)\" feature ;
|
| 443 |
+
}
|
| 444 |
+
$(v).implicit-feature = $(feature) ;
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
.all-implicit-values += $(values) ;
|
| 448 |
+
}
|
| 449 |
+
if ! $($(feature).values)
|
| 450 |
+
{
|
| 451 |
+
# This is the first value specified for this feature so make it be the
|
| 452 |
+
# default.
|
| 453 |
+
$(feature).default = $(values[1]) ;
|
| 454 |
+
}
|
| 455 |
+
$(feature).values += $(values) ;
|
| 456 |
+
}
|
| 457 |
+
|
| 458 |
+
|
| 459 |
+
# Checks that value-string is a valid value-string for the given feature.
|
| 460 |
+
#
|
| 461 |
+
rule validate-value-string ( feature value-string )
|
| 462 |
+
{
|
| 463 |
+
if ! (
|
| 464 |
+
free in $($(feature).attributes)
|
| 465 |
+
|| ( $(value-string) in $(feature).values )
|
| 466 |
+
)
|
| 467 |
+
{
|
| 468 |
+
local values = $(value-string) ;
|
| 469 |
+
|
| 470 |
+
if $($(feature).subfeatures)
|
| 471 |
+
{
|
| 472 |
+
if ! ( $(value-string) in $($(feature).values) )
|
| 473 |
+
&& ! ( $(value-string) in $($(feature).subfeatures) )
|
| 474 |
+
{
|
| 475 |
+
values = [ regex.split $(value-string) - ] ;
|
| 476 |
+
}
|
| 477 |
+
}
|
| 478 |
+
|
| 479 |
+
if ! ( $(values[1]) in $($(feature).values) ) &&
|
| 480 |
+
|
| 481 |
+
# An empty value is allowed for optional features.
|
| 482 |
+
( $(values[1]) || ! ( optional in $($(feature).attributes) ) )
|
| 483 |
+
{
|
| 484 |
+
errors.error \"$(values[1])\" is not a known value of feature $(feature)
|
| 485 |
+
: legal values: \"$($(feature).values)\" ;
|
| 486 |
+
}
|
| 487 |
+
|
| 488 |
+
for local v in $(values[2-])
|
| 489 |
+
{
|
| 490 |
+
# This will validate any subfeature values in value-string.
|
| 491 |
+
implied-subfeature $(feature) $(v) : $(values[1]) ;
|
| 492 |
+
}
|
| 493 |
+
}
|
| 494 |
+
}
|
| 495 |
+
|
| 496 |
+
|
| 497 |
+
# A helper that computes:
|
| 498 |
+
# * name(s) of module-local variable(s) used to record the correspondence
|
| 499 |
+
# between subvalue(s) and a subfeature
|
| 500 |
+
# * value of that variable when such a subfeature/subvalue has been defined and
|
| 501 |
+
# returns a list consisting of the latter followed by the former.
|
| 502 |
+
#
|
| 503 |
+
local rule subvalue-var (
|
| 504 |
+
feature # Main feature name.
|
| 505 |
+
value-string ? # If supplied, specifies a specific value of the main
|
| 506 |
+
# feature for which the subfeature values are valid.
|
| 507 |
+
: subfeature # Subfeature name.
|
| 508 |
+
: subvalues * # Subfeature values.
|
| 509 |
+
)
|
| 510 |
+
{
|
| 511 |
+
feature = [ grist $(feature) ] ;
|
| 512 |
+
validate-feature $(feature) ;
|
| 513 |
+
if $(value-string)
|
| 514 |
+
{
|
| 515 |
+
validate-value-string $(feature) $(value-string) ;
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
local subfeature-name = [ get-subfeature-name $(subfeature) $(value-string) ] ;
|
| 519 |
+
|
| 520 |
+
return $(subfeature-name)
|
| 521 |
+
$(feature)$(value-string:E="")<>$(subvalues).subfeature ;
|
| 522 |
+
}
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
# Extends the given subfeature with the subvalues. If the optional value-string
|
| 526 |
+
# is provided, the subvalues are only valid for the given value of the feature.
|
| 527 |
+
# Thus, you could say that <target-platform>mingw is specific to
|
| 528 |
+
# <toolset>gcc-2.95.2 as follows:
|
| 529 |
+
#
|
| 530 |
+
# extend-subfeature toolset gcc-2.95.2 : target-platform : mingw ;
|
| 531 |
+
#
|
| 532 |
+
rule extend-subfeature (
|
| 533 |
+
feature # The feature whose subfeature is being extended.
|
| 534 |
+
|
| 535 |
+
value-string ? # If supplied, specifies a specific value of the main
|
| 536 |
+
# feature for which the new subfeature values are valid.
|
| 537 |
+
|
| 538 |
+
: subfeature # Subfeature name.
|
| 539 |
+
: subvalues * # Additional subfeature values.
|
| 540 |
+
)
|
| 541 |
+
{
|
| 542 |
+
local subfeature-vars = [ subvalue-var $(feature) $(value-string)
|
| 543 |
+
: $(subfeature) : $(subvalues) ] ;
|
| 544 |
+
|
| 545 |
+
local f = [ utility.ungrist [ grist $(feature) ] ] ;
|
| 546 |
+
extend $(f)-$(subfeature-vars[1]) : $(subvalues) ;
|
| 547 |
+
|
| 548 |
+
# Provide a way to get from the given feature or property and subfeature
|
| 549 |
+
# value to the subfeature name.
|
| 550 |
+
$(subfeature-vars[2-]) = $(subfeature-vars[1]) ;
|
| 551 |
+
}
|
| 552 |
+
|
| 553 |
+
|
| 554 |
+
# Returns true iff the subvalues are valid for the feature. When the optional
|
| 555 |
+
# value-string is provided, returns true iff the subvalues are valid for the
|
| 556 |
+
# given value of the feature.
|
| 557 |
+
#
|
| 558 |
+
rule is-subvalue ( feature : value-string ? : subfeature : subvalue )
|
| 559 |
+
{
|
| 560 |
+
local subfeature-vars = [ subvalue-var $(feature) $(value-string)
|
| 561 |
+
: $(subfeature) : $(subvalue) ] ;
|
| 562 |
+
|
| 563 |
+
if $($(subfeature-vars[2])) = $(subfeature-vars[1])
|
| 564 |
+
{
|
| 565 |
+
return true ;
|
| 566 |
+
}
|
| 567 |
+
}
|
| 568 |
+
|
| 569 |
+
|
| 570 |
+
# Can be called three ways:
|
| 571 |
+
#
|
| 572 |
+
# 1. extend feature : values *
|
| 573 |
+
# 2. extend <feature> subfeature : values *
|
| 574 |
+
# 3. extend <feature>value-string subfeature : values *
|
| 575 |
+
#
|
| 576 |
+
# * Form 1 adds the given values to the given feature.
|
| 577 |
+
# * Forms 2 and 3 add subfeature values to the given feature.
|
| 578 |
+
# * Form 3 adds the subfeature values as specific to the given property
|
| 579 |
+
# value-string.
|
| 580 |
+
#
|
| 581 |
+
rule extend ( feature-or-property subfeature ? : values * )
|
| 582 |
+
{
|
| 583 |
+
local feature ; # If a property was specified this is its feature.
|
| 584 |
+
local value-string ; # E.g., the gcc-2.95-2 part of <toolset>gcc-2.95.2.
|
| 585 |
+
|
| 586 |
+
# If a property was specified.
|
| 587 |
+
if $(feature-or-property:G) && $(feature-or-property:G=)
|
| 588 |
+
{
|
| 589 |
+
# Extract the feature and value-string, if any.
|
| 590 |
+
feature = $(feature-or-property:G) ;
|
| 591 |
+
value-string = $(feature-or-property:G=) ;
|
| 592 |
+
}
|
| 593 |
+
else
|
| 594 |
+
{
|
| 595 |
+
feature = [ grist $(feature-or-property) ] ;
|
| 596 |
+
}
|
| 597 |
+
|
| 598 |
+
# Dispatch to the appropriate handler.
|
| 599 |
+
if $(subfeature)
|
| 600 |
+
{
|
| 601 |
+
extend-subfeature $(feature) $(value-string) : $(subfeature)
|
| 602 |
+
: $(values) ;
|
| 603 |
+
}
|
| 604 |
+
else
|
| 605 |
+
{
|
| 606 |
+
# If no subfeature was specified, we do not expect to see a
|
| 607 |
+
# value-string.
|
| 608 |
+
if $(value-string)
|
| 609 |
+
{
|
| 610 |
+
errors.error can only specify a property as the first argument when
|
| 611 |
+
extending a subfeature
|
| 612 |
+
: usage:
|
| 613 |
+
: " extend" feature ":" values...
|
| 614 |
+
: " | extend" <feature>value-string subfeature ":" values...
|
| 615 |
+
;
|
| 616 |
+
}
|
| 617 |
+
|
| 618 |
+
extend-feature $(feature) : $(values) ;
|
| 619 |
+
}
|
| 620 |
+
}
|
| 621 |
+
|
| 622 |
+
|
| 623 |
+
local rule get-subfeature-name ( subfeature value-string ? )
|
| 624 |
+
{
|
| 625 |
+
local prefix = $(value-string): ;
|
| 626 |
+
return $(prefix:E="")$(subfeature) ;
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
+
|
| 630 |
+
# Declares a subfeature.
|
| 631 |
+
#
|
| 632 |
+
rule subfeature (
|
| 633 |
+
feature # Root feature that is not a subfeature.
|
| 634 |
+
value-string ? # A value-string specifying which feature or subfeature
|
| 635 |
+
# values this subfeature is specific to, if any.
|
| 636 |
+
: subfeature # The name of the subfeature being declared.
|
| 637 |
+
: subvalues * # The allowed values of this subfeature.
|
| 638 |
+
: attributes * # The attributes of the subfeature.
|
| 639 |
+
)
|
| 640 |
+
{
|
| 641 |
+
feature = [ grist $(feature) ] ;
|
| 642 |
+
validate-feature $(feature) ;
|
| 643 |
+
|
| 644 |
+
# Add grist to the subfeature name if a value-string was supplied.
|
| 645 |
+
local subfeature-name = [ get-subfeature-name $(subfeature) $(value-string) ] ;
|
| 646 |
+
|
| 647 |
+
if $(subfeature-name) in $($(feature).subfeatures)
|
| 648 |
+
{
|
| 649 |
+
errors.error \"$(subfeature)\" already declared as a subfeature of \"$(feature)\"
|
| 650 |
+
"specific to "$(value-string) ;
|
| 651 |
+
}
|
| 652 |
+
$(feature).subfeatures += $(subfeature-name) ;
|
| 653 |
+
|
| 654 |
+
# First declare the subfeature as a feature in its own right.
|
| 655 |
+
local f = [ utility.ungrist $(feature) ] ;
|
| 656 |
+
feature $(f)-$(subfeature-name) : $(subvalues) : $(attributes) subfeature ;
|
| 657 |
+
|
| 658 |
+
# Now make sure the subfeature values are known.
|
| 659 |
+
extend-subfeature $(feature) $(value-string) : $(subfeature) : $(subvalues) ;
|
| 660 |
+
}
|
| 661 |
+
|
| 662 |
+
|
| 663 |
+
# Set components of the given composite property.
|
| 664 |
+
#
|
| 665 |
+
rule compose ( composite-property : component-properties * )
|
| 666 |
+
{
|
| 667 |
+
local feature = $(composite-property:G) ;
|
| 668 |
+
if ! ( composite in [ attributes $(feature) ] )
|
| 669 |
+
{
|
| 670 |
+
errors.error "$(feature)" is not a composite feature ;
|
| 671 |
+
}
|
| 672 |
+
|
| 673 |
+
$(composite-property).components ?= ;
|
| 674 |
+
if $($(composite-property).components)
|
| 675 |
+
{
|
| 676 |
+
errors.error components of "$(composite-property)" already set:
|
| 677 |
+
$($(composite-property).components) ;
|
| 678 |
+
}
|
| 679 |
+
|
| 680 |
+
if $(composite-property) in $(component-properties)
|
| 681 |
+
{
|
| 682 |
+
errors.error composite property "$(composite-property)" cannot have itself as a component ;
|
| 683 |
+
}
|
| 684 |
+
$(composite-property).components = $(component-properties) ;
|
| 685 |
+
}
|
| 686 |
+
|
| 687 |
+
|
| 688 |
+
local rule expand-composite ( property )
|
| 689 |
+
{
|
| 690 |
+
return $(property)
|
| 691 |
+
[ sequence.transform expand-composite : $($(property).components) ] ;
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
|
| 695 |
+
# Return all values of the given feature specified by the given property set.
|
| 696 |
+
#
|
| 697 |
+
rule get-values ( feature : properties * )
|
| 698 |
+
{
|
| 699 |
+
local result ;
|
| 700 |
+
|
| 701 |
+
feature = $(:E=:G=$(feature)) ; # Add <> if necessary.
|
| 702 |
+
for local p in $(properties)
|
| 703 |
+
{
|
| 704 |
+
if $(p:G) = $(feature)
|
| 705 |
+
{
|
| 706 |
+
# Use MATCH instead of :G= to get the value, in order to preserve
|
| 707 |
+
# the value intact instead of having bjam treat it as a decomposable
|
| 708 |
+
# path.
|
| 709 |
+
result += [ MATCH ">(.*)" : $(p) ] ;
|
| 710 |
+
}
|
| 711 |
+
}
|
| 712 |
+
return $(result) ;
|
| 713 |
+
}
|
| 714 |
+
|
| 715 |
+
|
| 716 |
+
rule free-features ( )
|
| 717 |
+
{
|
| 718 |
+
return $(free.features) ;
|
| 719 |
+
}
|
| 720 |
+
|
| 721 |
+
|
| 722 |
+
# Expand all composite properties in the set so that all components are
|
| 723 |
+
# explicitly expressed.
|
| 724 |
+
#
|
| 725 |
+
rule expand-composites ( properties * )
|
| 726 |
+
{
|
| 727 |
+
local explicit-features = $(properties:G) ;
|
| 728 |
+
local result ;
|
| 729 |
+
|
| 730 |
+
# Now expand composite features.
|
| 731 |
+
for local p in $(properties)
|
| 732 |
+
{
|
| 733 |
+
local expanded = [ expand-composite $(p) ] ;
|
| 734 |
+
|
| 735 |
+
for local x in $(expanded)
|
| 736 |
+
{
|
| 737 |
+
if ! $(x) in $(result)
|
| 738 |
+
{
|
| 739 |
+
local f = $(x:G) ;
|
| 740 |
+
|
| 741 |
+
if $(f) in $(free.features)
|
| 742 |
+
{
|
| 743 |
+
result += $(x) ;
|
| 744 |
+
}
|
| 745 |
+
else if ! $(x) in $(properties) # x is the result of expansion
|
| 746 |
+
{
|
| 747 |
+
if ! $(f) in $(explicit-features) # not explicitly-specified
|
| 748 |
+
{
|
| 749 |
+
if $(f) in $(result:G)
|
| 750 |
+
{
|
| 751 |
+
errors.error expansions of composite features result
|
| 752 |
+
in conflicting values for $(f)
|
| 753 |
+
: values: [ get-values $(f) : $(result) ] $(x:G=)
|
| 754 |
+
: one contributing composite property was $(p) ;
|
| 755 |
+
}
|
| 756 |
+
else
|
| 757 |
+
{
|
| 758 |
+
result += $(x) ;
|
| 759 |
+
}
|
| 760 |
+
}
|
| 761 |
+
}
|
| 762 |
+
else if $(f) in $(result:G)
|
| 763 |
+
{
|
| 764 |
+
errors.error explicitly-specified values of non-free feature
|
| 765 |
+
$(f) conflict :
|
| 766 |
+
"existing values:" [ get-values $(f) : $(properties) ] :
|
| 767 |
+
"value from expanding " $(p) ":" $(x:G=) ;
|
| 768 |
+
}
|
| 769 |
+
else
|
| 770 |
+
{
|
| 771 |
+
result += $(x) ;
|
| 772 |
+
}
|
| 773 |
+
}
|
| 774 |
+
}
|
| 775 |
+
}
|
| 776 |
+
return $(result) ;
|
| 777 |
+
}
|
| 778 |
+
|
| 779 |
+
|
| 780 |
+
# Return true iff f is an ordinary subfeature of the parent-property's feature,
|
| 781 |
+
# or if f is a subfeature of the parent-property's feature specific to the
|
| 782 |
+
# parent-property's value.
|
| 783 |
+
#
|
| 784 |
+
local rule is-subfeature-of ( parent-property f )
|
| 785 |
+
{
|
| 786 |
+
if subfeature in $($(f).attributes)
|
| 787 |
+
{
|
| 788 |
+
local specific-subfeature = [ MATCH <(.*):(.*)> : $(f) ] ;
|
| 789 |
+
if $(specific-subfeature)
|
| 790 |
+
{
|
| 791 |
+
# The feature has the form <topfeature-topvalue:subfeature>, e.g.
|
| 792 |
+
# <toolset-msvc:version>.
|
| 793 |
+
local feature-value = [ split-top-feature $(specific-subfeature[1])
|
| 794 |
+
] ;
|
| 795 |
+
if <$(feature-value[1])>$(feature-value[2]) = $(parent-property)
|
| 796 |
+
{
|
| 797 |
+
return true ;
|
| 798 |
+
}
|
| 799 |
+
}
|
| 800 |
+
else
|
| 801 |
+
{
|
| 802 |
+
# The feature has the form <topfeature-subfeature>, e.g.
|
| 803 |
+
# <toolset-version>
|
| 804 |
+
local top-sub = [ split-top-feature [ utility.ungrist $(f) ] ] ;
|
| 805 |
+
if $(top-sub[2]) && <$(top-sub[1])> = $(parent-property:G)
|
| 806 |
+
{
|
| 807 |
+
return true ;
|
| 808 |
+
}
|
| 809 |
+
}
|
| 810 |
+
}
|
| 811 |
+
}
|
| 812 |
+
|
| 813 |
+
|
| 814 |
+
# As for is-subfeature-of but for subproperties.
|
| 815 |
+
#
|
| 816 |
+
local rule is-subproperty-of ( parent-property p )
|
| 817 |
+
{
|
| 818 |
+
return [ is-subfeature-of $(parent-property) $(p:G) ] ;
|
| 819 |
+
}
|
| 820 |
+
|
| 821 |
+
|
| 822 |
+
# Given a property, return the subset of features consisting of all ordinary
|
| 823 |
+
# subfeatures of the property's feature, and all specific subfeatures of the
|
| 824 |
+
# property's feature which are conditional on the property's value.
|
| 825 |
+
#
|
| 826 |
+
local rule select-subfeatures ( parent-property : features * )
|
| 827 |
+
{
|
| 828 |
+
return [ sequence.filter is-subfeature-of $(parent-property) : $(features) ] ;
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
+
|
| 832 |
+
# As for select-subfeatures but for subproperties.
|
| 833 |
+
#
|
| 834 |
+
local rule select-subproperties ( parent-property : properties * )
|
| 835 |
+
{
|
| 836 |
+
return [ sequence.filter is-subproperty-of $(parent-property) : $(properties) ] ;
|
| 837 |
+
}
|
| 838 |
+
|
| 839 |
+
|
| 840 |
+
# Given a property set which may consist of composite and implicit properties
|
| 841 |
+
# and combined subfeature values, returns an expanded, normalized property set
|
| 842 |
+
# with all implicit features expressed explicitly, all subfeature values
|
| 843 |
+
# individually expressed, and all components of composite properties expanded.
|
| 844 |
+
# Non-free features directly expressed in the input properties cause any values
|
| 845 |
+
# of those features due to composite feature expansion to be dropped. If two
|
| 846 |
+
# values of a given non-free feature are directly expressed in the input, an
|
| 847 |
+
# error is issued.
|
| 848 |
+
#
|
| 849 |
+
rule expand ( properties * )
|
| 850 |
+
{
|
| 851 |
+
local expanded = [ expand-subfeatures $(properties) ] ;
|
| 852 |
+
return [ expand-composites $(expanded) ] ;
|
| 853 |
+
}
|
| 854 |
+
|
| 855 |
+
|
| 856 |
+
# Helper rule for minimize. Returns true iff property's feature is present in
|
| 857 |
+
# the contents of the variable named by feature-set-var.
|
| 858 |
+
#
|
| 859 |
+
local rule in-features ( feature-set-var property )
|
| 860 |
+
{
|
| 861 |
+
if $(property:G) in $($(feature-set-var))
|
| 862 |
+
{
|
| 863 |
+
return true ;
|
| 864 |
+
}
|
| 865 |
+
}
|
| 866 |
+
|
| 867 |
+
|
| 868 |
+
# Helper rule for minimize. Returns the list with the same properties, but with
|
| 869 |
+
# all subfeatures moved to the end of the list.
|
| 870 |
+
#
|
| 871 |
+
local rule move-subfeatures-to-the-end ( properties * )
|
| 872 |
+
{
|
| 873 |
+
local x1 ;
|
| 874 |
+
local x2 ;
|
| 875 |
+
for local p in $(properties)
|
| 876 |
+
{
|
| 877 |
+
if subfeature in $($(p:G).attributes)
|
| 878 |
+
{
|
| 879 |
+
x2 += $(p) ;
|
| 880 |
+
}
|
| 881 |
+
else
|
| 882 |
+
{
|
| 883 |
+
x1 += $(p) ;
|
| 884 |
+
}
|
| 885 |
+
}
|
| 886 |
+
return $(x1) $(x2) ;
|
| 887 |
+
}
|
| 888 |
+
|
| 889 |
+
|
| 890 |
+
# Given an expanded property set, eliminate all redundancy: properties that are
|
| 891 |
+
# elements of other (composite) properties in the set will be eliminated.
|
| 892 |
+
# Non-symmetric properties equal to default values will be eliminated unless
|
| 893 |
+
# they override a value from some composite property. Implicit properties will
|
| 894 |
+
# be expressed without feature grist, and sub-property values will be expressed
|
| 895 |
+
# as elements joined to the corresponding main property.
|
| 896 |
+
#
|
| 897 |
+
rule minimize ( properties * )
|
| 898 |
+
{
|
| 899 |
+
# Precondition checking
|
| 900 |
+
local implicits = [ set.intersection $(p:G=) : $(p:G) ] ;
|
| 901 |
+
if $(implicits)
|
| 902 |
+
{
|
| 903 |
+
errors.error minimize requires an expanded property set, but
|
| 904 |
+
\"$(implicits[1])\" appears to be the value of an un-expanded
|
| 905 |
+
implicit feature ;
|
| 906 |
+
}
|
| 907 |
+
|
| 908 |
+
# Remove properties implied by composite features.
|
| 909 |
+
local components = $($(properties).components) ;
|
| 910 |
+
local x = [ set.difference $(properties) : $(components) ] ;
|
| 911 |
+
|
| 912 |
+
# Handle subfeatures and implicit features.
|
| 913 |
+
x = [ move-subfeatures-to-the-end $(x) ] ;
|
| 914 |
+
local result ;
|
| 915 |
+
while $(x)
|
| 916 |
+
{
|
| 917 |
+
local p fullp = $(x[1]) ;
|
| 918 |
+
local f = $(p:G) ;
|
| 919 |
+
local v = $(p:G=) ;
|
| 920 |
+
|
| 921 |
+
# Eliminate features in implicit properties.
|
| 922 |
+
if implicit in [ attributes $(f) ]
|
| 923 |
+
{
|
| 924 |
+
p = $(v) ;
|
| 925 |
+
}
|
| 926 |
+
|
| 927 |
+
# Locate all subproperties of $(x[1]) in the property set.
|
| 928 |
+
local subproperties = [ select-subproperties $(fullp) : $(x) ] ;
|
| 929 |
+
if $(subproperties)
|
| 930 |
+
{
|
| 931 |
+
# Reconstitute the joined property name.
|
| 932 |
+
local sorted = [ sequence.insertion-sort $(subproperties) ] ;
|
| 933 |
+
result += $(p)-$(sorted:G="":J=-) ;
|
| 934 |
+
|
| 935 |
+
x = [ set.difference $(x[2-]) : $(subproperties) ] ;
|
| 936 |
+
}
|
| 937 |
+
else
|
| 938 |
+
{
|
| 939 |
+
# Eliminate properties whose value is equal to feature's default,
|
| 940 |
+
# which are not symmetric and which do not contradict values implied
|
| 941 |
+
# by composite properties.
|
| 942 |
+
|
| 943 |
+
# Since all component properties of composites in the set have been
|
| 944 |
+
# eliminated, any remaining property whose feature is the same as a
|
| 945 |
+
# component of a composite in the set must have a non-redundant
|
| 946 |
+
# value.
|
| 947 |
+
if $(fullp) != [ defaults $(f) ]
|
| 948 |
+
|| symmetric in [ attributes $(f) ]
|
| 949 |
+
|| $(fullp:G) in $(components:G)
|
| 950 |
+
{
|
| 951 |
+
result += $(p) ;
|
| 952 |
+
}
|
| 953 |
+
|
| 954 |
+
x = $(x[2-]) ;
|
| 955 |
+
}
|
| 956 |
+
}
|
| 957 |
+
return $(result) ;
|
| 958 |
+
}
|
| 959 |
+
|
| 960 |
+
|
| 961 |
+
# Combine all subproperties into their parent properties
|
| 962 |
+
#
|
| 963 |
+
# Requires: for every subproperty, there is a parent property. All features are
|
| 964 |
+
# explicitly expressed.
|
| 965 |
+
#
|
| 966 |
+
# This rule probably should not be needed, but build-request.expand-no-defaults
|
| 967 |
+
# is being abused for unintended purposes and it needs help.
|
| 968 |
+
#
|
| 969 |
+
rule compress-subproperties ( properties * )
|
| 970 |
+
{
|
| 971 |
+
local all-subs ;
|
| 972 |
+
local matched-subs ;
|
| 973 |
+
local result ;
|
| 974 |
+
|
| 975 |
+
for local p in $(properties)
|
| 976 |
+
{
|
| 977 |
+
if ! $(p:G)
|
| 978 |
+
{
|
| 979 |
+
# Expecting fully-gristed properties.
|
| 980 |
+
assert.variable-not-empty p:G ;
|
| 981 |
+
}
|
| 982 |
+
|
| 983 |
+
if ! subfeature in $($(p:G).attributes)
|
| 984 |
+
{
|
| 985 |
+
local subs = [ sequence.insertion-sort
|
| 986 |
+
[ sequence.filter is-subproperty-of $(p) : $(properties) ] ] ;
|
| 987 |
+
|
| 988 |
+
matched-subs += $(subs) ;
|
| 989 |
+
|
| 990 |
+
local subvalues = -$(subs:G=:J=-) ;
|
| 991 |
+
subvalues ?= "" ;
|
| 992 |
+
result += $(p)$(subvalues) ;
|
| 993 |
+
}
|
| 994 |
+
else
|
| 995 |
+
{
|
| 996 |
+
all-subs += $(p) ;
|
| 997 |
+
}
|
| 998 |
+
}
|
| 999 |
+
assert.result true : set.equal $(all-subs) : $(matched-subs) ;
|
| 1000 |
+
return $(result) ;
|
| 1001 |
+
}
|
| 1002 |
+
|
| 1003 |
+
|
| 1004 |
+
# Given an ungristed string, finds the longest prefix which is a top-level
|
| 1005 |
+
# feature name followed by a dash, and return a pair consisting of the parts
|
| 1006 |
+
# before and after that dash. More interesting than a simple split because
|
| 1007 |
+
# feature names may contain dashes.
|
| 1008 |
+
#
|
| 1009 |
+
local rule split-top-feature ( feature-plus )
|
| 1010 |
+
{
|
| 1011 |
+
local e = [ regex.split $(feature-plus) - ] ;
|
| 1012 |
+
local f = $(e[1]) ;
|
| 1013 |
+
local v ;
|
| 1014 |
+
while $(e)
|
| 1015 |
+
{
|
| 1016 |
+
if <$(f)> in $(.all-top-features)
|
| 1017 |
+
{
|
| 1018 |
+
v = $(f) $(e[2-]:J=-) ;
|
| 1019 |
+
}
|
| 1020 |
+
e = $(e[2-]) ;
|
| 1021 |
+
f = $(f)-$(e[1]) ;
|
| 1022 |
+
}
|
| 1023 |
+
return $(v) ;
|
| 1024 |
+
}
|
| 1025 |
+
|
| 1026 |
+
|
| 1027 |
+
# Given a set of properties, add default values for features not represented in
|
| 1028 |
+
# the set.
|
| 1029 |
+
#
|
| 1030 |
+
# Note: if there's an ordinary feature F1 and a composite feature F2 which
|
| 1031 |
+
# includes some value for F1 and both feature have default values then the
|
| 1032 |
+
# default value of F1 will be added (as opposed to the value in F2). This might
|
| 1033 |
+
# not be the right idea, e.g. consider:
|
| 1034 |
+
#
|
| 1035 |
+
# feature variant : debug ... ;
|
| 1036 |
+
# <variant>debug : .... <runtime-debugging>on
|
| 1037 |
+
# feature <runtime-debugging> : off on ;
|
| 1038 |
+
#
|
| 1039 |
+
# Here, when adding default for an empty property set, we'll get
|
| 1040 |
+
#
|
| 1041 |
+
# <variant>debug <runtime_debugging>off
|
| 1042 |
+
#
|
| 1043 |
+
# and that's kind of strange.
|
| 1044 |
+
#
|
| 1045 |
+
rule add-defaults ( properties * )
|
| 1046 |
+
{
|
| 1047 |
+
for local v in $(properties:G=)
|
| 1048 |
+
{
|
| 1049 |
+
if $(v) in $(properties)
|
| 1050 |
+
{
|
| 1051 |
+
errors.error add-defaults requires explicitly specified features,
|
| 1052 |
+
but \"$(v)\" appears to be the value of an un-expanded implicit
|
| 1053 |
+
feature ;
|
| 1054 |
+
}
|
| 1055 |
+
}
|
| 1056 |
+
# We don't add default for elements with ":" inside. This catches:
|
| 1057 |
+
# 1. Conditional properties --- we don't want <variant>debug:<define>DEBUG
|
| 1058 |
+
# to be takes as specified value for <variant>
|
| 1059 |
+
# 2. Free properties with ":" in values. We don't care, since free
|
| 1060 |
+
# properties don't have defaults.
|
| 1061 |
+
local xproperties = [ MATCH "^([^:]+)$" : $(properties) ] ;
|
| 1062 |
+
local missing-top = [ set.difference $(.all-top-features) : $(xproperties:G) ] ;
|
| 1063 |
+
local more = [ defaults $(missing-top) ] ;
|
| 1064 |
+
properties += $(more) ;
|
| 1065 |
+
xproperties += $(more) ;
|
| 1066 |
+
|
| 1067 |
+
# Add defaults for subfeatures of features which are present.
|
| 1068 |
+
for local p in $(xproperties)
|
| 1069 |
+
{
|
| 1070 |
+
local s = $($(p:G).subfeatures) ;
|
| 1071 |
+
local f = [ utility.ungrist $(p:G) ] ;
|
| 1072 |
+
local missing-subs = [ set.difference <$(f)-$(s)> : $(properties:G) ] ;
|
| 1073 |
+
properties += [ defaults [ select-subfeatures $(p) : $(missing-subs) ] ] ;
|
| 1074 |
+
}
|
| 1075 |
+
|
| 1076 |
+
return $(properties) ;
|
| 1077 |
+
}
|
| 1078 |
+
|
| 1079 |
+
|
| 1080 |
+
# Given a property-set of the form
|
| 1081 |
+
# v1/v2/...vN-1/<fN>vN/<fN+1>vN+1/...<fM>vM
|
| 1082 |
+
#
|
| 1083 |
+
# Returns
|
| 1084 |
+
# v1 v2 ... vN-1 <fN>vN <fN+1>vN+1 ... <fM>vM
|
| 1085 |
+
#
|
| 1086 |
+
# Note that vN...vM may contain slashes. This needs to be resilient to the
|
| 1087 |
+
# substitution of backslashes for slashes, since Jam, unbidden, sometimes swaps
|
| 1088 |
+
# slash direction on NT.
|
| 1089 |
+
#
|
| 1090 |
+
rule split ( property-set )
|
| 1091 |
+
{
|
| 1092 |
+
local pieces = [ regex.split $(property-set) [\\/] ] ;
|
| 1093 |
+
local result ;
|
| 1094 |
+
|
| 1095 |
+
for local x in $(pieces)
|
| 1096 |
+
{
|
| 1097 |
+
if ( ! $(x:G) ) && $(result[-1]:G)
|
| 1098 |
+
{
|
| 1099 |
+
result = $(result[1--2]) $(result[-1])/$(x) ;
|
| 1100 |
+
}
|
| 1101 |
+
else
|
| 1102 |
+
{
|
| 1103 |
+
result += $(x) ;
|
| 1104 |
+
}
|
| 1105 |
+
}
|
| 1106 |
+
|
| 1107 |
+
return $(result) ;
|
| 1108 |
+
}
|
| 1109 |
+
|
| 1110 |
+
|
| 1111 |
+
# Tests of module feature.
|
| 1112 |
+
#
|
| 1113 |
+
rule __test__ ( )
|
| 1114 |
+
{
|
| 1115 |
+
# Use a fresh copy of the feature module.
|
| 1116 |
+
prepare-test feature-test-temp ;
|
| 1117 |
+
|
| 1118 |
+
import assert ;
|
| 1119 |
+
import errors : try catch ;
|
| 1120 |
+
|
| 1121 |
+
# These are local rules and so must be explicitly reimported into the
|
| 1122 |
+
# testing module.
|
| 1123 |
+
import feature : extend-feature validate-feature select-subfeatures ;
|
| 1124 |
+
|
| 1125 |
+
feature toolset : gcc : implicit ;
|
| 1126 |
+
feature define : : free ;
|
| 1127 |
+
feature runtime-link : dynamic static : symmetric ;
|
| 1128 |
+
feature optimization : on off ;
|
| 1129 |
+
feature variant : debug release profile : implicit composite symmetric ;
|
| 1130 |
+
feature stdlib : native stlport ;
|
| 1131 |
+
feature magic : : free ;
|
| 1132 |
+
|
| 1133 |
+
compose <variant>debug : <define>_DEBUG <optimization>off ;
|
| 1134 |
+
compose <variant>release : <define>NDEBUG <optimization>on ;
|
| 1135 |
+
|
| 1136 |
+
assert.result dynamic static : values <runtime-link> ;
|
| 1137 |
+
assert.result dynamic static : values runtime-link ;
|
| 1138 |
+
|
| 1139 |
+
try ;
|
| 1140 |
+
{
|
| 1141 |
+
compose <variant>profile : <variant>profile ;
|
| 1142 |
+
}
|
| 1143 |
+
catch composite property <variant>profile cannot have itself as a component ;
|
| 1144 |
+
|
| 1145 |
+
extend-feature toolset : msvc metrowerks ;
|
| 1146 |
+
subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 3.0 3.0.1 3.0.2 ;
|
| 1147 |
+
|
| 1148 |
+
assert.true is-subvalue toolset : gcc : version : 2.95.3 ;
|
| 1149 |
+
assert.false is-subvalue toolset : gcc : version : 1.1 ;
|
| 1150 |
+
|
| 1151 |
+
assert.false is-subvalue toolset : msvc : version : 2.95.3 ;
|
| 1152 |
+
assert.false is-subvalue toolset : : version : yabba ;
|
| 1153 |
+
|
| 1154 |
+
feature yabba ;
|
| 1155 |
+
subfeature yabba : version : dabba ;
|
| 1156 |
+
assert.true is-subvalue yabba : : version : dabba ;
|
| 1157 |
+
|
| 1158 |
+
subfeature toolset gcc : platform : linux cygwin : optional ;
|
| 1159 |
+
|
| 1160 |
+
assert.result <toolset-gcc:version>
|
| 1161 |
+
: select-subfeatures <toolset>gcc
|
| 1162 |
+
: <toolset-gcc:version>
|
| 1163 |
+
<toolset-msvc:version>
|
| 1164 |
+
<toolset-version>
|
| 1165 |
+
<stdlib> ;
|
| 1166 |
+
|
| 1167 |
+
subfeature stdlib : version : 3 4 : optional ;
|
| 1168 |
+
|
| 1169 |
+
assert.result <stdlib-version>
|
| 1170 |
+
: select-subfeatures <stdlib>native
|
| 1171 |
+
: <toolset-gcc:version>
|
| 1172 |
+
<toolset-msvc:version>
|
| 1173 |
+
<toolset-version>
|
| 1174 |
+
<stdlib-version> ;
|
| 1175 |
+
|
| 1176 |
+
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
|
| 1177 |
+
: expand-subfeatures <toolset>gcc-3.0.1 ;
|
| 1178 |
+
|
| 1179 |
+
assert.result <toolset>gcc <toolset-gcc:version>3.0.1 <toolset-gcc:platform>linux
|
| 1180 |
+
: expand-subfeatures <toolset>gcc-3.0.1-linux ;
|
| 1181 |
+
|
| 1182 |
+
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
|
| 1183 |
+
: expand <toolset>gcc <toolset-gcc:version>3.0.1 ;
|
| 1184 |
+
|
| 1185 |
+
assert.result <define>foo=x-y
|
| 1186 |
+
: expand-subfeatures <define>foo=x-y ;
|
| 1187 |
+
|
| 1188 |
+
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
|
| 1189 |
+
: expand-subfeatures gcc-3.0.1 ;
|
| 1190 |
+
|
| 1191 |
+
assert.result a c e
|
| 1192 |
+
: get-values <x> : <x>a <y>b <x>c <y>d <x>e ;
|
| 1193 |
+
|
| 1194 |
+
assert.result <toolset>gcc <toolset-gcc:version>3.0.1
|
| 1195 |
+
<variant>debug <define>_DEBUG <optimization>on
|
| 1196 |
+
: expand gcc-3.0.1 debug <optimization>on ;
|
| 1197 |
+
|
| 1198 |
+
assert.result <variant>debug <define>_DEBUG <optimization>on
|
| 1199 |
+
: expand debug <optimization>on ;
|
| 1200 |
+
|
| 1201 |
+
assert.result <optimization>on <variant>debug <define>_DEBUG
|
| 1202 |
+
: expand <optimization>on debug ;
|
| 1203 |
+
|
| 1204 |
+
assert.result <runtime-link>dynamic <optimization>on
|
| 1205 |
+
: defaults <runtime-link> <define> <optimization> ;
|
| 1206 |
+
|
| 1207 |
+
# Make sure defaults is resilient to missing grist.
|
| 1208 |
+
assert.result <runtime-link>dynamic <optimization>on
|
| 1209 |
+
: defaults runtime-link define optimization ;
|
| 1210 |
+
|
| 1211 |
+
feature dummy : dummy1 dummy2 ;
|
| 1212 |
+
subfeature dummy : subdummy : x y z : optional ;
|
| 1213 |
+
|
| 1214 |
+
feature fu : fu1 fu2 : optional ;
|
| 1215 |
+
subfeature fu : subfu : x y z : optional ;
|
| 1216 |
+
subfeature fu : subfu2 : q r s ;
|
| 1217 |
+
|
| 1218 |
+
assert.result optional : attributes <fu> ;
|
| 1219 |
+
assert.result optional : attributes fu ;
|
| 1220 |
+
|
| 1221 |
+
assert.result <runtime-link>static <define>foobar <optimization>on
|
| 1222 |
+
<toolset>gcc:<define>FOO <toolset>gcc <variant>debug <stdlib>native
|
| 1223 |
+
<dummy>dummy1 <toolset-gcc:version>2.95.2
|
| 1224 |
+
: add-defaults <runtime-link>static <define>foobar <optimization>on
|
| 1225 |
+
<toolset>gcc:<define>FOO ;
|
| 1226 |
+
|
| 1227 |
+
assert.result <runtime-link>static <define>foobar <optimization>on
|
| 1228 |
+
<toolset>gcc:<define>FOO <fu>fu1 <toolset>gcc <variant>debug
|
| 1229 |
+
<stdlib>native <dummy>dummy1 <fu-subfu2>q <toolset-gcc:version>2.95.2
|
| 1230 |
+
: add-defaults <runtime-link>static <define>foobar <optimization>on
|
| 1231 |
+
<toolset>gcc:<define>FOO <fu>fu1 ;
|
| 1232 |
+
|
| 1233 |
+
set-default <runtime-link> : static ;
|
| 1234 |
+
assert.result <runtime-link>static : defaults <runtime-link> ;
|
| 1235 |
+
|
| 1236 |
+
assert.result gcc-3.0.1 debug <optimization>on
|
| 1237 |
+
: minimize [ expand gcc-3.0.1 debug <optimization>on <stdlib>native ] ;
|
| 1238 |
+
|
| 1239 |
+
assert.result gcc-3.0.1 debug <runtime-link>dynamic
|
| 1240 |
+
: minimize
|
| 1241 |
+
[ expand gcc-3.0.1 debug <optimization>off <runtime-link>dynamic ] ;
|
| 1242 |
+
|
| 1243 |
+
assert.result gcc-3.0.1 debug
|
| 1244 |
+
: minimize [ expand gcc-3.0.1 debug <optimization>off ] ;
|
| 1245 |
+
|
| 1246 |
+
assert.result debug <optimization>on
|
| 1247 |
+
: minimize [ expand debug <optimization>on ] ;
|
| 1248 |
+
|
| 1249 |
+
assert.result gcc-3.0
|
| 1250 |
+
: minimize <toolset>gcc <toolset-gcc:version>3.0 ;
|
| 1251 |
+
|
| 1252 |
+
assert.result gcc-3.0
|
| 1253 |
+
: minimize <toolset-gcc:version>3.0 <toolset>gcc ;
|
| 1254 |
+
|
| 1255 |
+
assert.result <x>y/z <a>b/c <d>e/f
|
| 1256 |
+
: split <x>y/z/<a>b/c/<d>e/f ;
|
| 1257 |
+
|
| 1258 |
+
assert.result <x>y/z <a>b/c <d>e/f
|
| 1259 |
+
: split <x>y\\z\\<a>b\\c\\<d>e\\f ;
|
| 1260 |
+
|
| 1261 |
+
assert.result a b c <d>e/f/g <h>i/j/k
|
| 1262 |
+
: split a/b/c/<d>e/f/g/<h>i/j/k ;
|
| 1263 |
+
|
| 1264 |
+
assert.result a b c <d>e/f/g <h>i/j/k
|
| 1265 |
+
: split a\\b\\c\\<d>e\\f\\g\\<h>i\\j\\k ;
|
| 1266 |
+
|
| 1267 |
+
# Test error checking.
|
| 1268 |
+
|
| 1269 |
+
try ;
|
| 1270 |
+
{
|
| 1271 |
+
expand release <optimization>off <optimization>on ;
|
| 1272 |
+
}
|
| 1273 |
+
catch explicitly-specified values of non-free feature <optimization> conflict ;
|
| 1274 |
+
|
| 1275 |
+
try ;
|
| 1276 |
+
{
|
| 1277 |
+
validate-feature <foobar> ;
|
| 1278 |
+
}
|
| 1279 |
+
catch unknown feature ;
|
| 1280 |
+
|
| 1281 |
+
validate-value-string <toolset> gcc ;
|
| 1282 |
+
validate-value-string <toolset> gcc-3.0.1 ;
|
| 1283 |
+
|
| 1284 |
+
try ;
|
| 1285 |
+
{
|
| 1286 |
+
validate-value-string <toolset> digital_mars ;
|
| 1287 |
+
}
|
| 1288 |
+
catch \"digital_mars\" is not a known value of <toolset> ;
|
| 1289 |
+
|
| 1290 |
+
try ;
|
| 1291 |
+
{
|
| 1292 |
+
feature foobar : : baz ;
|
| 1293 |
+
}
|
| 1294 |
+
catch unknown attributes: baz ;
|
| 1295 |
+
|
| 1296 |
+
feature feature1 ;
|
| 1297 |
+
try ;
|
| 1298 |
+
{
|
| 1299 |
+
feature feature1 ;
|
| 1300 |
+
}
|
| 1301 |
+
catch feature already defined: ;
|
| 1302 |
+
|
| 1303 |
+
try ;
|
| 1304 |
+
{
|
| 1305 |
+
feature feature2 : : free implicit ;
|
| 1306 |
+
}
|
| 1307 |
+
catch free features cannot also be implicit ;
|
| 1308 |
+
|
| 1309 |
+
try ;
|
| 1310 |
+
{
|
| 1311 |
+
feature feature3 : : free propagated ;
|
| 1312 |
+
}
|
| 1313 |
+
catch free features cannot be propagated ;
|
| 1314 |
+
|
| 1315 |
+
try ;
|
| 1316 |
+
{
|
| 1317 |
+
implied-feature lackluster ;
|
| 1318 |
+
}
|
| 1319 |
+
catch \"lackluster\" is not a value of an implicit feature ;
|
| 1320 |
+
|
| 1321 |
+
try ;
|
| 1322 |
+
{
|
| 1323 |
+
implied-subfeature <toolset> 3.0.1 ;
|
| 1324 |
+
}
|
| 1325 |
+
catch \"3.0.1\" is not a known subfeature value of <toolset> ;
|
| 1326 |
+
|
| 1327 |
+
try ;
|
| 1328 |
+
{
|
| 1329 |
+
implied-subfeature <toolset> not-a-version : gcc ;
|
| 1330 |
+
}
|
| 1331 |
+
catch \"not-a-version\" is not a known subfeature value of <toolset>gcc ;
|
| 1332 |
+
|
| 1333 |
+
# Leave a clean copy of the features module behind.
|
| 1334 |
+
finish-test feature-test-temp ;
|
| 1335 |
+
}
|
mosesdecoder/jam-files/boost-build/build/generators.jam
ADDED
|
@@ -0,0 +1,1380 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright Vladimir Prus 2002.
|
| 2 |
+
# Copyright Rene Rivera 2006.
|
| 3 |
+
#
|
| 4 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 5 |
+
# (See accompanying file LICENSE_1_0.txt or copy at
|
| 6 |
+
# http://www.boost.org/LICENSE_1_0.txt)
|
| 7 |
+
|
| 8 |
+
# Manages 'generators' --- objects which can do transformation between different
|
| 9 |
+
# target types and contain algorithm for finding transformation from sources to
|
| 10 |
+
# targets.
|
| 11 |
+
#
|
| 12 |
+
# The main entry point to this module is generators.construct rule. It is given
|
| 13 |
+
# a list of source targets, desired target type and a set of properties. It
|
| 14 |
+
# starts by selecting 'viable generators', which have any chances of producing
|
| 15 |
+
# the desired target type with the required properties. Generators are ranked
|
| 16 |
+
# and a set of the most specific ones is selected.
|
| 17 |
+
#
|
| 18 |
+
# The most specific generators have their 'run' methods called, with the
|
| 19 |
+
# properties and list of sources. Each one selects a target which can be
|
| 20 |
+
# directly consumed, and tries to convert the remaining ones to the types it can
|
| 21 |
+
# consume. This is done by recursively calling 'construct' with all consumable
|
| 22 |
+
# types.
|
| 23 |
+
#
|
| 24 |
+
# If the generator has collected all the targets it needs, it creates targets
|
| 25 |
+
# corresponding to result, and returns it. When all generators have been run,
|
| 26 |
+
# results of one of them are selected and returned as a result.
|
| 27 |
+
#
|
| 28 |
+
# It is quite possible for 'construct' to return more targets that it was asked
|
| 29 |
+
# for. For example, if it were asked to generate a target of type EXE, but the
|
| 30 |
+
# only found generator produces both EXE and TDS (file with debug) information.
|
| 31 |
+
# The extra target will be returned.
|
| 32 |
+
#
|
| 33 |
+
# Likewise, when generator tries to convert sources to consumable types, it can
|
| 34 |
+
# get more targets that it was asked for. The question is what to do with extra
|
| 35 |
+
# targets. Boost.Build attempts to convert them to requested types, and attempts
|
| 36 |
+
# that as early as possible. Specifically, this is done after invoking each
|
| 37 |
+
# generator. TODO: An example is needed to document the rationale for trying
|
| 38 |
+
# extra target conversion at that point.
|
| 39 |
+
#
|
| 40 |
+
# In order for the system to be able to use a specific generator instance 'when
|
| 41 |
+
# needed', the instance needs to be registered with the system using
|
| 42 |
+
# generators.register() or one of its related rules. Unregistered generators may
|
| 43 |
+
# only be run explicitly and will not be considered by Boost.Build when when
|
| 44 |
+
# converting between given target types.
|
| 45 |
+
|
| 46 |
+
import "class" : new ;
|
| 47 |
+
import errors ;
|
| 48 |
+
import property-set ;
|
| 49 |
+
import sequence ;
|
| 50 |
+
import set ;
|
| 51 |
+
import type ;
|
| 52 |
+
import utility ;
|
| 53 |
+
import virtual-target ;
|
| 54 |
+
|
| 55 |
+
|
| 56 |
+
if "--debug-generators" in [ modules.peek : ARGV ]
|
| 57 |
+
{
|
| 58 |
+
.debug = true ;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
# Updated cached viable source target type information as needed after a new
|
| 63 |
+
# target type gets defined. This is needed because if a target type is a viable
|
| 64 |
+
# source target type for some generator then all of the target type's derived
|
| 65 |
+
# target types should automatically be considered as viable source target types
|
| 66 |
+
# for the same generator as well. Does nothing if a non-derived target type is
|
| 67 |
+
# passed to it.
|
| 68 |
+
#
|
| 69 |
+
rule update-cached-information-with-a-new-type ( type )
|
| 70 |
+
{
|
| 71 |
+
local base-type = [ type.base $(type) ] ;
|
| 72 |
+
if $(base-type)
|
| 73 |
+
{
|
| 74 |
+
for local g in $(.vstg-cached-generators)
|
| 75 |
+
{
|
| 76 |
+
if $(base-type) in $(.vstg.$(g))
|
| 77 |
+
{
|
| 78 |
+
.vstg.$(g) += $(type) ;
|
| 79 |
+
}
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
for local t in $(.vst-cached-types)
|
| 83 |
+
{
|
| 84 |
+
if $(base-type) in $(.vst.$(t))
|
| 85 |
+
{
|
| 86 |
+
.vst.$(t) += $(type) ;
|
| 87 |
+
}
|
| 88 |
+
}
|
| 89 |
+
}
|
| 90 |
+
}
|
| 91 |
+
|
| 92 |
+
|
| 93 |
+
# Clears cached viable source target type information except for target types
|
| 94 |
+
# and generators with all source types listed as viable. Should be called when
|
| 95 |
+
# something invalidates those cached values by possibly causing some new source
|
| 96 |
+
# types to become viable.
|
| 97 |
+
#
|
| 98 |
+
local rule invalidate-extendable-viable-source-target-type-cache ( )
|
| 99 |
+
{
|
| 100 |
+
local generators-with-cached-source-types = $(.vstg-cached-generators) ;
|
| 101 |
+
.vstg-cached-generators = ;
|
| 102 |
+
for local g in $(generators-with-cached-source-types)
|
| 103 |
+
{
|
| 104 |
+
if $(.vstg.$(g)) = *
|
| 105 |
+
{
|
| 106 |
+
.vstg-cached-generators += $(g) ;
|
| 107 |
+
}
|
| 108 |
+
else
|
| 109 |
+
{
|
| 110 |
+
.vstg.$(g) = ;
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
|
| 114 |
+
local types-with-cached-source-types = $(.vst-cached-types) ;
|
| 115 |
+
.vst-cached-types = ;
|
| 116 |
+
for local t in $(types-with-cached-source-types)
|
| 117 |
+
{
|
| 118 |
+
if $(.vst.$(t)) = *
|
| 119 |
+
{
|
| 120 |
+
.vst-cached-types += $(t) ;
|
| 121 |
+
}
|
| 122 |
+
else
|
| 123 |
+
{
|
| 124 |
+
.vst.$(t) = ;
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
|
| 130 |
+
# Outputs a debug message if generators debugging is on. Each element of
|
| 131 |
+
# 'message' is checked to see if it is a class instance. If so, instead of the
|
| 132 |
+
# value, the result of 'str' call is output.
|
| 133 |
+
#
|
| 134 |
+
local rule generators.dout ( message * )
|
| 135 |
+
{
|
| 136 |
+
if $(.debug)
|
| 137 |
+
{
|
| 138 |
+
ECHO [ sequence.transform utility.str : $(message) ] ;
|
| 139 |
+
}
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
local rule indent ( )
|
| 144 |
+
{
|
| 145 |
+
return $(.indent:J="") ;
|
| 146 |
+
}
|
| 147 |
+
|
| 148 |
+
|
| 149 |
+
local rule increase-indent ( )
|
| 150 |
+
{
|
| 151 |
+
.indent += " " ;
|
| 152 |
+
}
|
| 153 |
+
|
| 154 |
+
|
| 155 |
+
local rule decrease-indent ( )
|
| 156 |
+
{
|
| 157 |
+
.indent = $(.indent[2-]) ;
|
| 158 |
+
}
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
# Models a generator.
|
| 162 |
+
#
|
| 163 |
+
class generator
|
| 164 |
+
{
|
| 165 |
+
import generators : indent increase-indent decrease-indent generators.dout ;
|
| 166 |
+
import set ;
|
| 167 |
+
import utility ;
|
| 168 |
+
import feature ;
|
| 169 |
+
import errors ;
|
| 170 |
+
import sequence ;
|
| 171 |
+
import type ;
|
| 172 |
+
import virtual-target ;
|
| 173 |
+
import "class" : new ;
|
| 174 |
+
import property ;
|
| 175 |
+
import path ;
|
| 176 |
+
|
| 177 |
+
EXPORT class@generator : indent increase-indent decrease-indent
|
| 178 |
+
generators.dout ;
|
| 179 |
+
|
| 180 |
+
rule __init__ (
|
| 181 |
+
id # Identifies the generator - should be name
|
| 182 |
+
# of the rule which sets up the build
|
| 183 |
+
# actions.
|
| 184 |
+
|
| 185 |
+
composing ? # Whether generator processes each source
|
| 186 |
+
# target in turn, converting it to required
|
| 187 |
+
# types. Ordinary generators pass all
|
| 188 |
+
# sources together to the recursive
|
| 189 |
+
# generators.construct-types call.
|
| 190 |
+
|
| 191 |
+
: source-types * # Types that this generator can handle. If
|
| 192 |
+
# empty, the generator can consume anything.
|
| 193 |
+
|
| 194 |
+
: target-types-and-names + # Types the generator will create and,
|
| 195 |
+
# optionally, names for created targets.
|
| 196 |
+
# Each element should have the form
|
| 197 |
+
# type["(" name-pattern ")"], for example,
|
| 198 |
+
# obj(%_x). Generated target name will be
|
| 199 |
+
# found by replacing % with the name of
|
| 200 |
+
# source, provided an explicit name was not
|
| 201 |
+
# specified.
|
| 202 |
+
|
| 203 |
+
: requirements *
|
| 204 |
+
)
|
| 205 |
+
{
|
| 206 |
+
self.id = $(id) ;
|
| 207 |
+
self.rule-name = $(id) ;
|
| 208 |
+
self.composing = $(composing) ;
|
| 209 |
+
self.source-types = $(source-types) ;
|
| 210 |
+
self.target-types-and-names = $(target-types-and-names) ;
|
| 211 |
+
self.requirements = $(requirements) ;
|
| 212 |
+
|
| 213 |
+
for local e in $(target-types-and-names)
|
| 214 |
+
{
|
| 215 |
+
# Create three parallel lists: one with the list of target types,
|
| 216 |
+
# and two other with prefixes and postfixes to be added to target
|
| 217 |
+
# name. We use parallel lists for prefix and postfix (as opposed to
|
| 218 |
+
# mapping), because given target type might occur several times, for
|
| 219 |
+
# example "H H(%_symbols)".
|
| 220 |
+
local m = [ MATCH ([^\\(]*)(\\((.*)%(.*)\\))? : $(e) ] ;
|
| 221 |
+
self.target-types += $(m[1]) ;
|
| 222 |
+
self.name-prefix += $(m[3]:E="") ;
|
| 223 |
+
self.name-postfix += $(m[4]:E="") ;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
# Note that 'transform' here, is the same as 'for_each'.
|
| 227 |
+
sequence.transform type.validate : $(self.source-types) ;
|
| 228 |
+
sequence.transform type.validate : $(self.target-types) ;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
################# End of constructor #################
|
| 232 |
+
|
| 233 |
+
rule id ( )
|
| 234 |
+
{
|
| 235 |
+
return $(self.id) ;
|
| 236 |
+
}
|
| 237 |
+
|
| 238 |
+
# Returns the list of target type the generator accepts.
|
| 239 |
+
#
|
| 240 |
+
rule source-types ( )
|
| 241 |
+
{
|
| 242 |
+
return $(self.source-types) ;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
# Returns the list of target types that this generator produces. It is
|
| 246 |
+
# assumed to be always the same -- i.e. it can not change depending on some
|
| 247 |
+
# provided list of sources.
|
| 248 |
+
#
|
| 249 |
+
rule target-types ( )
|
| 250 |
+
{
|
| 251 |
+
return $(self.target-types) ;
|
| 252 |
+
}
|
| 253 |
+
|
| 254 |
+
# Returns the required properties for this generator. Properties in returned
|
| 255 |
+
# set must be present in build properties if this generator is to be used.
|
| 256 |
+
# If result has grist-only element, that build properties must include some
|
| 257 |
+
# value of that feature.
|
| 258 |
+
#
|
| 259 |
+
# XXX: remove this method?
|
| 260 |
+
#
|
| 261 |
+
rule requirements ( )
|
| 262 |
+
{
|
| 263 |
+
return $(self.requirements) ;
|
| 264 |
+
}
|
| 265 |
+
|
| 266 |
+
rule set-rule-name ( rule-name )
|
| 267 |
+
{
|
| 268 |
+
self.rule-name = $(rule-name) ;
|
| 269 |
+
}
|
| 270 |
+
|
| 271 |
+
rule rule-name ( )
|
| 272 |
+
{
|
| 273 |
+
return $(self.rule-name) ;
|
| 274 |
+
}
|
| 275 |
+
|
| 276 |
+
# Returns a true value if the generator can be run with the specified
|
| 277 |
+
# properties.
|
| 278 |
+
#
|
| 279 |
+
rule match-rank ( property-set-to-match )
|
| 280 |
+
{
|
| 281 |
+
# See if generator requirements are satisfied by 'properties'. Treat a
|
| 282 |
+
# feature name in requirements (i.e. grist-only element), as matching
|
| 283 |
+
# any value of the feature.
|
| 284 |
+
local all-requirements = [ requirements ] ;
|
| 285 |
+
|
| 286 |
+
local property-requirements feature-requirements ;
|
| 287 |
+
for local r in $(all-requirements)
|
| 288 |
+
{
|
| 289 |
+
if $(r:G=)
|
| 290 |
+
{
|
| 291 |
+
property-requirements += $(r) ;
|
| 292 |
+
}
|
| 293 |
+
else
|
| 294 |
+
{
|
| 295 |
+
feature-requirements += $(r) ;
|
| 296 |
+
}
|
| 297 |
+
}
|
| 298 |
+
|
| 299 |
+
local properties-to-match = [ $(property-set-to-match).raw ] ;
|
| 300 |
+
if $(property-requirements) in $(properties-to-match) &&
|
| 301 |
+
$(feature-requirements) in $(properties-to-match:G)
|
| 302 |
+
{
|
| 303 |
+
return true ;
|
| 304 |
+
}
|
| 305 |
+
else
|
| 306 |
+
{
|
| 307 |
+
return ;
|
| 308 |
+
}
|
| 309 |
+
}
|
| 310 |
+
|
| 311 |
+
# Returns another generator which differs from $(self) in
|
| 312 |
+
# - id
|
| 313 |
+
# - value to <toolset> feature in properties
|
| 314 |
+
#
|
| 315 |
+
rule clone ( new-id : new-toolset-properties + )
|
| 316 |
+
{
|
| 317 |
+
local g = [ new $(__class__) $(new-id) $(self.composing) :
|
| 318 |
+
$(self.source-types) : $(self.target-types-and-names) :
|
| 319 |
+
# Note: this does not remove any subfeatures of <toolset> which
|
| 320 |
+
# might cause problems.
|
| 321 |
+
[ property.change $(self.requirements) : <toolset> ]
|
| 322 |
+
$(new-toolset-properties) ] ;
|
| 323 |
+
return $(g) ;
|
| 324 |
+
}
|
| 325 |
+
|
| 326 |
+
# Creates another generator that is the same as $(self), except that if
|
| 327 |
+
# 'base' is in target types of $(self), 'type' will in target types of the
|
| 328 |
+
# new generator.
|
| 329 |
+
#
|
| 330 |
+
rule clone-and-change-target-type ( base : type )
|
| 331 |
+
{
|
| 332 |
+
local target-types ;
|
| 333 |
+
for local t in $(self.target-types-and-names)
|
| 334 |
+
{
|
| 335 |
+
local m = [ MATCH ([^\\(]*)(\\(.*\\))? : $(t) ] ;
|
| 336 |
+
if $(m) = $(base)
|
| 337 |
+
{
|
| 338 |
+
target-types += $(type)$(m[2]:E="") ;
|
| 339 |
+
}
|
| 340 |
+
else
|
| 341 |
+
{
|
| 342 |
+
target-types += $(t) ;
|
| 343 |
+
}
|
| 344 |
+
}
|
| 345 |
+
|
| 346 |
+
local g = [ new $(__class__) $(self.id) $(self.composing) :
|
| 347 |
+
$(self.source-types) : $(target-types) : $(self.requirements) ] ;
|
| 348 |
+
if $(self.rule-name)
|
| 349 |
+
{
|
| 350 |
+
$(g).set-rule-name $(self.rule-name) ;
|
| 351 |
+
}
|
| 352 |
+
return $(g) ;
|
| 353 |
+
}
|
| 354 |
+
|
| 355 |
+
# Tries to invoke this generator on the given sources. Returns a list of
|
| 356 |
+
# generated targets (instances of 'virtual-target') and optionally a set of
|
| 357 |
+
# properties to be added to the usage-requirements for all the generated
|
| 358 |
+
# targets. Returning nothing from run indicates that the generator was
|
| 359 |
+
# unable to create the target.
|
| 360 |
+
#
|
| 361 |
+
rule run
|
| 362 |
+
(
|
| 363 |
+
project # Project for which the targets are generated.
|
| 364 |
+
name ? # Used when determining the 'name' attribute for all
|
| 365 |
+
# generated targets. See the 'generated-targets' method.
|
| 366 |
+
: property-set # Desired properties for generated targets.
|
| 367 |
+
: sources + # Source targets.
|
| 368 |
+
)
|
| 369 |
+
{
|
| 370 |
+
generators.dout [ indent ] " ** generator" $(self.id) ;
|
| 371 |
+
generators.dout [ indent ] " composing:" $(self.composing) ;
|
| 372 |
+
|
| 373 |
+
if ! $(self.composing) && $(sources[2]) && $(self.source-types[2])
|
| 374 |
+
{
|
| 375 |
+
errors.error "Unsupported source/source-type combination" ;
|
| 376 |
+
}
|
| 377 |
+
|
| 378 |
+
# We do not run composing generators if no name is specified. The reason
|
| 379 |
+
# is that composing generator combines several targets, which can have
|
| 380 |
+
# different names, and it cannot decide which name to give for produced
|
| 381 |
+
# target. Therefore, the name must be passed.
|
| 382 |
+
#
|
| 383 |
+
# This in effect, means that composing generators are runnable only at
|
| 384 |
+
# the top-level of a transformation graph, or if their name is passed
|
| 385 |
+
# explicitly. Thus, we dissallow composing generators in the middle. For
|
| 386 |
+
# example, the transformation CPP -> OBJ -> STATIC_LIB -> RSP -> EXE
|
| 387 |
+
# will not be allowed as the OBJ -> STATIC_LIB generator is composing.
|
| 388 |
+
if ! $(self.composing) || $(name)
|
| 389 |
+
{
|
| 390 |
+
run-really $(project) $(name) : $(property-set) : $(sources) ;
|
| 391 |
+
}
|
| 392 |
+
}
|
| 393 |
+
|
| 394 |
+
rule run-really ( project name ? : property-set : sources + )
|
| 395 |
+
{
|
| 396 |
+
# Targets that this generator will consume directly.
|
| 397 |
+
local consumed = ;
|
| 398 |
+
# Targets that can not be consumed and will be returned as-is.
|
| 399 |
+
local bypassed = ;
|
| 400 |
+
|
| 401 |
+
if $(self.composing)
|
| 402 |
+
{
|
| 403 |
+
consumed = [ convert-multiple-sources-to-consumable-types $(project)
|
| 404 |
+
: $(property-set) : $(sources) ] ;
|
| 405 |
+
}
|
| 406 |
+
else
|
| 407 |
+
{
|
| 408 |
+
consumed = [ convert-to-consumable-types $(project) $(name)
|
| 409 |
+
: $(property-set) : $(sources) ] ;
|
| 410 |
+
}
|
| 411 |
+
|
| 412 |
+
local result ;
|
| 413 |
+
if $(consumed)
|
| 414 |
+
{
|
| 415 |
+
result = [ construct-result $(consumed) : $(project) $(name) :
|
| 416 |
+
$(property-set) ] ;
|
| 417 |
+
}
|
| 418 |
+
|
| 419 |
+
if $(result)
|
| 420 |
+
{
|
| 421 |
+
generators.dout [ indent ] " SUCCESS: " $(result) ;
|
| 422 |
+
}
|
| 423 |
+
else
|
| 424 |
+
{
|
| 425 |
+
generators.dout [ indent ] " FAILURE" ;
|
| 426 |
+
}
|
| 427 |
+
generators.dout ;
|
| 428 |
+
return $(result) ;
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
# Constructs the dependency graph to be returned by this generator.
|
| 432 |
+
#
|
| 433 |
+
rule construct-result
|
| 434 |
+
(
|
| 435 |
+
consumed + # Already prepared list of consumable targets.
|
| 436 |
+
# Composing generators may receive multiple sources
|
| 437 |
+
# all of which will have types matching those in
|
| 438 |
+
# $(self.source-types). Non-composing generators with
|
| 439 |
+
# multiple $(self.source-types) will receive exactly
|
| 440 |
+
# len $(self.source-types) sources with types matching
|
| 441 |
+
# those in $(self.source-types). And non-composing
|
| 442 |
+
# generators with only a single source type may
|
| 443 |
+
# receive multiple sources with all of them of the
|
| 444 |
+
# type listed in $(self.source-types).
|
| 445 |
+
: project name ?
|
| 446 |
+
: property-set # Properties to be used for all actions created here.
|
| 447 |
+
)
|
| 448 |
+
{
|
| 449 |
+
local result ;
|
| 450 |
+
# If this is 1->1 transformation, apply it to all consumed targets in
|
| 451 |
+
# order.
|
| 452 |
+
if ! $(self.source-types[2]) && ! $(self.composing)
|
| 453 |
+
{
|
| 454 |
+
for local r in $(consumed)
|
| 455 |
+
{
|
| 456 |
+
result += [ generated-targets $(r) : $(property-set) :
|
| 457 |
+
$(project) $(name) ] ;
|
| 458 |
+
}
|
| 459 |
+
}
|
| 460 |
+
else if $(consumed)
|
| 461 |
+
{
|
| 462 |
+
result += [ generated-targets $(consumed) : $(property-set) :
|
| 463 |
+
$(project) $(name) ] ;
|
| 464 |
+
}
|
| 465 |
+
return $(result) ;
|
| 466 |
+
}
|
| 467 |
+
|
| 468 |
+
# Determine target name from fullname (maybe including path components)
|
| 469 |
+
# Place optional prefix and postfix around basename
|
| 470 |
+
#
|
| 471 |
+
rule determine-target-name ( fullname : prefix ? : postfix ? )
|
| 472 |
+
{
|
| 473 |
+
# See if we need to add directory to the target name.
|
| 474 |
+
local dir = $(fullname:D) ;
|
| 475 |
+
local name = $(fullname:B) ;
|
| 476 |
+
|
| 477 |
+
name = $(prefix:E=)$(name) ;
|
| 478 |
+
name = $(name)$(postfix:E=) ;
|
| 479 |
+
|
| 480 |
+
if $(dir) &&
|
| 481 |
+
# Never append '..' to target path.
|
| 482 |
+
! [ MATCH .*(\\.\\.).* : $(dir) ]
|
| 483 |
+
&&
|
| 484 |
+
! [ path.is-rooted $(dir) ]
|
| 485 |
+
{
|
| 486 |
+
# Relative path is always relative to the source
|
| 487 |
+
# directory. Retain it, so that users can have files
|
| 488 |
+
# with the same in two different subdirectories.
|
| 489 |
+
name = $(dir)/$(name) ;
|
| 490 |
+
}
|
| 491 |
+
return $(name) ;
|
| 492 |
+
}
|
| 493 |
+
|
| 494 |
+
# Determine the name of the produced target from the names of the sources.
|
| 495 |
+
#
|
| 496 |
+
rule determine-output-name ( sources + )
|
| 497 |
+
{
|
| 498 |
+
# The simple case if when a name of source has single dot. Then, we take
|
| 499 |
+
# the part before dot. Several dots can be caused by:
|
| 500 |
+
# - using source file like a.host.cpp, or
|
| 501 |
+
# - a type whose suffix has a dot. Say, we can type 'host_cpp' with
|
| 502 |
+
# extension 'host.cpp'.
|
| 503 |
+
# In the first case, we want to take the part up to the last dot. In the
|
| 504 |
+
# second case -- not sure, but for now take the part up to the last dot
|
| 505 |
+
# too.
|
| 506 |
+
name = [ utility.basename [ $(sources[1]).name ] ] ;
|
| 507 |
+
|
| 508 |
+
for local s in $(sources[2])
|
| 509 |
+
{
|
| 510 |
+
local n2 = [ utility.basename [ $(s).name ] ] ;
|
| 511 |
+
if $(n2) != $(name)
|
| 512 |
+
{
|
| 513 |
+
errors.error "$(self.id): source targets have different names: cannot determine target name" ;
|
| 514 |
+
}
|
| 515 |
+
}
|
| 516 |
+
name = [ determine-target-name [ $(sources[1]).name ] ] ;
|
| 517 |
+
return $(name) ;
|
| 518 |
+
}
|
| 519 |
+
|
| 520 |
+
# Constructs targets that are created after consuming 'sources'. The result
|
| 521 |
+
# will be the list of virtual-target, which has the same length as the
|
| 522 |
+
# 'target-types' attribute and with corresponding types.
|
| 523 |
+
#
|
| 524 |
+
# When 'name' is empty, all source targets must have the same 'name'
|
| 525 |
+
# attribute value, which will be used instead of the 'name' argument.
|
| 526 |
+
#
|
| 527 |
+
# The 'name' attribute value for each generated target will be equal to
|
| 528 |
+
# the 'name' parameter if there is no name pattern for this type. Otherwise,
|
| 529 |
+
# the '%' symbol in the name pattern will be replaced with the 'name'
|
| 530 |
+
# parameter to obtain the 'name' attribute.
|
| 531 |
+
#
|
| 532 |
+
# For example, if targets types are T1 and T2 (with name pattern "%_x"),
|
| 533 |
+
# suffixes for T1 and T2 are .t1 and .t2, and source is foo.z, then created
|
| 534 |
+
# files would be "foo.t1" and "foo_x.t2". The 'name' attribute actually
|
| 535 |
+
# determines the basename of a file.
|
| 536 |
+
#
|
| 537 |
+
# Note that this pattern mechanism has nothing to do with implicit patterns
|
| 538 |
+
# in make. It is a way to produce a target whose name is different than the
|
| 539 |
+
# name of its source.
|
| 540 |
+
#
|
| 541 |
+
rule generated-targets ( sources + : property-set : project name ? )
|
| 542 |
+
{
|
| 543 |
+
if ! $(name)
|
| 544 |
+
{
|
| 545 |
+
name = [ determine-output-name $(sources) ] ;
|
| 546 |
+
}
|
| 547 |
+
|
| 548 |
+
# Assign an action for each target.
|
| 549 |
+
local action = [ action-class ] ;
|
| 550 |
+
local a = [ class.new $(action) $(sources) : $(self.rule-name) :
|
| 551 |
+
$(property-set) ] ;
|
| 552 |
+
|
| 553 |
+
# Create generated target for each target type.
|
| 554 |
+
local targets ;
|
| 555 |
+
local pre = $(self.name-prefix) ;
|
| 556 |
+
local post = $(self.name-postfix) ;
|
| 557 |
+
for local t in $(self.target-types)
|
| 558 |
+
{
|
| 559 |
+
local generated-name = $(pre[1])$(name:BS)$(post[1]) ;
|
| 560 |
+
generated-name = $(generated-name:R=$(name:D)) ;
|
| 561 |
+
pre = $(pre[2-]) ;
|
| 562 |
+
post = $(post[2-]) ;
|
| 563 |
+
|
| 564 |
+
targets += [ class.new file-target $(generated-name) : $(t) :
|
| 565 |
+
$(project) : $(a) ] ;
|
| 566 |
+
}
|
| 567 |
+
|
| 568 |
+
return [ sequence.transform virtual-target.register : $(targets) ] ;
|
| 569 |
+
}
|
| 570 |
+
|
| 571 |
+
# Attempts to convert 'sources' to targets of types that this generator can
|
| 572 |
+
# handle. The intention is to produce the set of targets that can be used
|
| 573 |
+
# when the generator is run.
|
| 574 |
+
#
|
| 575 |
+
rule convert-to-consumable-types
|
| 576 |
+
(
|
| 577 |
+
project name ?
|
| 578 |
+
: property-set
|
| 579 |
+
: sources +
|
| 580 |
+
: only-one ? # Convert 'source' to only one of the source types. If
|
| 581 |
+
# there is more that one possibility, report an error.
|
| 582 |
+
)
|
| 583 |
+
{
|
| 584 |
+
local _consumed ;
|
| 585 |
+
local missing-types ;
|
| 586 |
+
|
| 587 |
+
if $(sources[2])
|
| 588 |
+
{
|
| 589 |
+
# Do not know how to handle several sources yet. Just try to pass
|
| 590 |
+
# the request to other generator.
|
| 591 |
+
missing-types = $(self.source-types) ;
|
| 592 |
+
}
|
| 593 |
+
else
|
| 594 |
+
{
|
| 595 |
+
local temp = [ consume-directly $(sources) ] ;
|
| 596 |
+
if $(temp[1])
|
| 597 |
+
{
|
| 598 |
+
_consumed = $(temp[1]) ;
|
| 599 |
+
}
|
| 600 |
+
missing-types = $(temp[2-]) ;
|
| 601 |
+
}
|
| 602 |
+
|
| 603 |
+
# No need to search for transformation if some source type has consumed
|
| 604 |
+
# source and no more source types are needed.
|
| 605 |
+
if $(only-one) && $(_consumed)
|
| 606 |
+
{
|
| 607 |
+
missing-types = ;
|
| 608 |
+
}
|
| 609 |
+
|
| 610 |
+
# TODO: we should check that only one source type if create of
|
| 611 |
+
# 'only-one' is true.
|
| 612 |
+
|
| 613 |
+
if $(missing-types)
|
| 614 |
+
{
|
| 615 |
+
local transformed = [ generators.construct-types $(project) $(name)
|
| 616 |
+
: $(missing-types) : $(property-set) : $(sources) ] ;
|
| 617 |
+
|
| 618 |
+
# Add targets of right type to 'consumed'. Add others to 'bypassed'.
|
| 619 |
+
# The 'generators.construct' rule has done its best to convert
|
| 620 |
+
# everything to the required type. There is no need to rerun it on
|
| 621 |
+
# targets of different types.
|
| 622 |
+
|
| 623 |
+
# NOTE: ignoring usage requirements.
|
| 624 |
+
for local t in $(transformed[2-])
|
| 625 |
+
{
|
| 626 |
+
if [ $(t).type ] in $(missing-types)
|
| 627 |
+
{
|
| 628 |
+
_consumed += $(t) ;
|
| 629 |
+
}
|
| 630 |
+
}
|
| 631 |
+
}
|
| 632 |
+
|
| 633 |
+
return [ sequence.unique $(_consumed) ] ;
|
| 634 |
+
}
|
| 635 |
+
|
| 636 |
+
# Converts several files to consumable types. Called for composing
|
| 637 |
+
# generators only.
|
| 638 |
+
#
|
| 639 |
+
rule convert-multiple-sources-to-consumable-types ( project : property-set :
|
| 640 |
+
sources * )
|
| 641 |
+
{
|
| 642 |
+
local result ;
|
| 643 |
+
# We process each source one-by-one, trying to convert it to a usable
|
| 644 |
+
# type.
|
| 645 |
+
for local source in $(sources)
|
| 646 |
+
{
|
| 647 |
+
local _c = [ convert-to-consumable-types $(project) : $(property-set)
|
| 648 |
+
: $(source) : true ] ;
|
| 649 |
+
if ! $(_c)
|
| 650 |
+
{
|
| 651 |
+
generators.dout [ indent ] " failed to convert " $(source) ;
|
| 652 |
+
}
|
| 653 |
+
result += $(_c) ;
|
| 654 |
+
}
|
| 655 |
+
return $(result) ;
|
| 656 |
+
}
|
| 657 |
+
|
| 658 |
+
rule consume-directly ( source )
|
| 659 |
+
{
|
| 660 |
+
local real-source-type = [ $(source).type ] ;
|
| 661 |
+
|
| 662 |
+
# If there are no source types, we can consume anything.
|
| 663 |
+
local source-types = $(self.source-types) ;
|
| 664 |
+
source-types ?= $(real-source-type) ;
|
| 665 |
+
|
| 666 |
+
local result = "" ;
|
| 667 |
+
local missing-types ;
|
| 668 |
+
|
| 669 |
+
for local st in $(source-types)
|
| 670 |
+
{
|
| 671 |
+
# The 'source' if of the right type already.
|
| 672 |
+
if $(real-source-type) = $(st) || [ type.is-derived
|
| 673 |
+
$(real-source-type) $(st) ]
|
| 674 |
+
{
|
| 675 |
+
result = $(source) ;
|
| 676 |
+
}
|
| 677 |
+
else
|
| 678 |
+
{
|
| 679 |
+
missing-types += $(st) ;
|
| 680 |
+
}
|
| 681 |
+
}
|
| 682 |
+
return $(result) $(missing-types) ;
|
| 683 |
+
}
|
| 684 |
+
|
| 685 |
+
# Returns the class to be used to actions. Default implementation returns
|
| 686 |
+
# "action".
|
| 687 |
+
#
|
| 688 |
+
rule action-class ( )
|
| 689 |
+
{
|
| 690 |
+
return "action" ;
|
| 691 |
+
}
|
| 692 |
+
}
|
| 693 |
+
|
| 694 |
+
|
| 695 |
+
# Registers a new generator instance 'g'.
|
| 696 |
+
#
|
| 697 |
+
rule register ( g )
|
| 698 |
+
{
|
| 699 |
+
.all-generators += $(g) ;
|
| 700 |
+
|
| 701 |
+
# A generator can produce several targets of the same type. We want unique
|
| 702 |
+
# occurrence of that generator in .generators.$(t) in that case, otherwise,
|
| 703 |
+
# it will be tried twice and we will get a false ambiguity.
|
| 704 |
+
for local t in [ sequence.unique [ $(g).target-types ] ]
|
| 705 |
+
{
|
| 706 |
+
.generators.$(t) += $(g) ;
|
| 707 |
+
}
|
| 708 |
+
|
| 709 |
+
# Update the set of generators for toolset.
|
| 710 |
+
|
| 711 |
+
# TODO: should we check that generator with this id is not already
|
| 712 |
+
# registered. For example, the fop.jam module intentionally declared two
|
| 713 |
+
# generators with the same id, so such check will break it.
|
| 714 |
+
local id = [ $(g).id ] ;
|
| 715 |
+
|
| 716 |
+
# Some generators have multiple periods in their name, so a simple $(id:S=)
|
| 717 |
+
# will not generate the right toolset name. E.g. if id = gcc.compile.c++,
|
| 718 |
+
# then .generators-for-toolset.$(id:S=) will append to
|
| 719 |
+
# .generators-for-toolset.gcc.compile, which is a separate value from
|
| 720 |
+
# .generators-for-toolset.gcc. Correcting this makes generator inheritance
|
| 721 |
+
# work properly. See also inherit-generators in the toolset module.
|
| 722 |
+
local base = $(id) ;
|
| 723 |
+
while $(base:S)
|
| 724 |
+
{
|
| 725 |
+
base = $(base:B) ;
|
| 726 |
+
}
|
| 727 |
+
.generators-for-toolset.$(base) += $(g) ;
|
| 728 |
+
|
| 729 |
+
|
| 730 |
+
# After adding a new generator that can construct new target types, we need
|
| 731 |
+
# to clear the related cached viable source target type information for
|
| 732 |
+
# constructing a specific target type or using a specific generator. Cached
|
| 733 |
+
# viable source target type lists affected by this are those containing any
|
| 734 |
+
# of the target types constructed by the new generator or any of their base
|
| 735 |
+
# target types.
|
| 736 |
+
#
|
| 737 |
+
# A more advanced alternative to clearing that cached viable source target
|
| 738 |
+
# type information would be to expand it with additional source types or
|
| 739 |
+
# even better - mark it as needing to be expanded on next use.
|
| 740 |
+
#
|
| 741 |
+
# Also see the http://thread.gmane.org/gmane.comp.lib.boost.build/19077
|
| 742 |
+
# mailing list thread for an even more advanced idea of how we could convert
|
| 743 |
+
# Boost Build's Jamfile processing, target selection and generator selection
|
| 744 |
+
# into separate steps which would prevent these caches from ever being
|
| 745 |
+
# invalidated.
|
| 746 |
+
#
|
| 747 |
+
# For now we just clear all the cached viable source target type information
|
| 748 |
+
# that does not simply state 'all types' and may implement a more detailed
|
| 749 |
+
# algorithm later on if it becomes needed.
|
| 750 |
+
|
| 751 |
+
invalidate-extendable-viable-source-target-type-cache ;
|
| 752 |
+
}
|
| 753 |
+
|
| 754 |
+
|
| 755 |
+
# Creates a new non-composing 'generator' class instance and registers it.
|
| 756 |
+
# Returns the created instance. Rationale: the instance is returned so that it
|
| 757 |
+
# is possible to first register a generator and then call its 'run' method,
|
| 758 |
+
# bypassing the whole generator selection process.
|
| 759 |
+
#
|
| 760 |
+
rule register-standard ( id : source-types * : target-types + : requirements * )
|
| 761 |
+
{
|
| 762 |
+
local g = [ new generator $(id) : $(source-types) : $(target-types) :
|
| 763 |
+
$(requirements) ] ;
|
| 764 |
+
register $(g) ;
|
| 765 |
+
return $(g) ;
|
| 766 |
+
}
|
| 767 |
+
|
| 768 |
+
|
| 769 |
+
# Creates a new composing 'generator' class instance and registers it.
|
| 770 |
+
#
|
| 771 |
+
rule register-composing ( id : source-types * : target-types + : requirements *
|
| 772 |
+
)
|
| 773 |
+
{
|
| 774 |
+
local g = [ new generator $(id) true : $(source-types) : $(target-types) :
|
| 775 |
+
$(requirements) ] ;
|
| 776 |
+
register $(g) ;
|
| 777 |
+
return $(g) ;
|
| 778 |
+
}
|
| 779 |
+
|
| 780 |
+
|
| 781 |
+
# Returns all generators belonging to the given 'toolset', i.e. whose ids are
|
| 782 |
+
# '$(toolset).<something>'.
|
| 783 |
+
#
|
| 784 |
+
rule generators-for-toolset ( toolset )
|
| 785 |
+
{
|
| 786 |
+
return $(.generators-for-toolset.$(toolset)) ;
|
| 787 |
+
}
|
| 788 |
+
|
| 789 |
+
|
| 790 |
+
# Make generator 'overrider-id' be preferred to 'overridee-id'. If, when
|
| 791 |
+
# searching for generators that could produce a target of a certain type, both
|
| 792 |
+
# those generators are among viable generators, the overridden generator is
|
| 793 |
+
# immediately discarded.
|
| 794 |
+
#
|
| 795 |
+
# The overridden generators are discarded immediately after computing the list
|
| 796 |
+
# of viable generators but before running any of them.
|
| 797 |
+
#
|
| 798 |
+
rule override ( overrider-id : overridee-id )
|
| 799 |
+
{
|
| 800 |
+
.override.$(overrider-id) += $(overridee-id) ;
|
| 801 |
+
}
|
| 802 |
+
|
| 803 |
+
|
| 804 |
+
# Returns a list of source type which can possibly be converted to 'target-type'
|
| 805 |
+
# by some chain of generator invocation.
|
| 806 |
+
#
|
| 807 |
+
# More formally, takes all generators for 'target-type' and returns a union of
|
| 808 |
+
# source types for those generators and result of calling itself recursively on
|
| 809 |
+
# source types.
|
| 810 |
+
#
|
| 811 |
+
# Returns '*' in case any type should be considered a viable source type for the
|
| 812 |
+
# given type.
|
| 813 |
+
#
|
| 814 |
+
local rule viable-source-types-real ( target-type )
|
| 815 |
+
{
|
| 816 |
+
local result ;
|
| 817 |
+
|
| 818 |
+
# 't0' is the initial list of target types we need to process to get a list
|
| 819 |
+
# of their viable source target types. New target types will not be added to
|
| 820 |
+
# this list.
|
| 821 |
+
local t0 = [ type.all-bases $(target-type) ] ;
|
| 822 |
+
|
| 823 |
+
# 't' is the list of target types which have not yet been processed to get a
|
| 824 |
+
# list of their viable source target types. This list will get expanded as
|
| 825 |
+
# we locate more target types to process.
|
| 826 |
+
local t = $(t0) ;
|
| 827 |
+
|
| 828 |
+
while $(t)
|
| 829 |
+
{
|
| 830 |
+
# Find all generators for the current type. Unlike
|
| 831 |
+
# 'find-viable-generators' we do not care about the property-set.
|
| 832 |
+
local generators = $(.generators.$(t[1])) ;
|
| 833 |
+
t = $(t[2-]) ;
|
| 834 |
+
|
| 835 |
+
while $(generators)
|
| 836 |
+
{
|
| 837 |
+
local g = $(generators[1]) ;
|
| 838 |
+
generators = $(generators[2-]) ;
|
| 839 |
+
|
| 840 |
+
if ! [ $(g).source-types ]
|
| 841 |
+
{
|
| 842 |
+
# Empty source types -- everything can be accepted.
|
| 843 |
+
result = * ;
|
| 844 |
+
# This will terminate this loop.
|
| 845 |
+
generators = ;
|
| 846 |
+
# This will terminate the outer loop.
|
| 847 |
+
t = ;
|
| 848 |
+
}
|
| 849 |
+
|
| 850 |
+
for local source-type in [ $(g).source-types ]
|
| 851 |
+
{
|
| 852 |
+
if ! $(source-type) in $(result)
|
| 853 |
+
{
|
| 854 |
+
# If a generator accepts a 'source-type' it will also
|
| 855 |
+
# happily accept any type derived from it.
|
| 856 |
+
for local n in [ type.all-derived $(source-type) ]
|
| 857 |
+
{
|
| 858 |
+
if ! $(n) in $(result)
|
| 859 |
+
{
|
| 860 |
+
# Here there is no point in adding target types to
|
| 861 |
+
# the list of types to process in case they are or
|
| 862 |
+
# have already been on that list. We optimize this
|
| 863 |
+
# check by realizing that we only need to avoid the
|
| 864 |
+
# original target type's base types. Other target
|
| 865 |
+
# types that are or have been on the list of target
|
| 866 |
+
# types to process have been added to the 'result'
|
| 867 |
+
# list as well and have thus already been eliminated
|
| 868 |
+
# by the previous if.
|
| 869 |
+
if ! $(n) in $(t0)
|
| 870 |
+
{
|
| 871 |
+
t += $(n) ;
|
| 872 |
+
}
|
| 873 |
+
result += $(n) ;
|
| 874 |
+
}
|
| 875 |
+
}
|
| 876 |
+
}
|
| 877 |
+
}
|
| 878 |
+
}
|
| 879 |
+
}
|
| 880 |
+
|
| 881 |
+
return $(result) ;
|
| 882 |
+
}
|
| 883 |
+
|
| 884 |
+
|
| 885 |
+
# Helper rule, caches the result of 'viable-source-types-real'.
|
| 886 |
+
#
|
| 887 |
+
rule viable-source-types ( target-type )
|
| 888 |
+
{
|
| 889 |
+
local key = .vst.$(target-type) ;
|
| 890 |
+
if ! $($(key))
|
| 891 |
+
{
|
| 892 |
+
.vst-cached-types += $(target-type) ;
|
| 893 |
+
local v = [ viable-source-types-real $(target-type) ] ;
|
| 894 |
+
if ! $(v)
|
| 895 |
+
{
|
| 896 |
+
v = none ;
|
| 897 |
+
}
|
| 898 |
+
$(key) = $(v) ;
|
| 899 |
+
}
|
| 900 |
+
|
| 901 |
+
if $($(key)) != none
|
| 902 |
+
{
|
| 903 |
+
return $($(key)) ;
|
| 904 |
+
}
|
| 905 |
+
}
|
| 906 |
+
|
| 907 |
+
|
| 908 |
+
# Returns the list of source types, which, when passed to 'run' method of
|
| 909 |
+
# 'generator', has some change of being eventually used (probably after
|
| 910 |
+
# conversion by other generators).
|
| 911 |
+
#
|
| 912 |
+
# Returns '*' in case any type should be considered a viable source type for the
|
| 913 |
+
# given generator.
|
| 914 |
+
#
|
| 915 |
+
rule viable-source-types-for-generator-real ( generator )
|
| 916 |
+
{
|
| 917 |
+
local source-types = [ $(generator).source-types ] ;
|
| 918 |
+
if ! $(source-types)
|
| 919 |
+
{
|
| 920 |
+
# If generator does not specify any source types, it might be a special
|
| 921 |
+
# generator like builtin.lib-generator which just relays to other
|
| 922 |
+
# generators. Return '*' to indicate that any source type is possibly
|
| 923 |
+
# OK, since we do not know for sure.
|
| 924 |
+
return * ;
|
| 925 |
+
}
|
| 926 |
+
else
|
| 927 |
+
{
|
| 928 |
+
local result ;
|
| 929 |
+
while $(source-types)
|
| 930 |
+
{
|
| 931 |
+
local s = $(source-types[1]) ;
|
| 932 |
+
source-types = $(source-types[2-]) ;
|
| 933 |
+
local viable-sources = [ generators.viable-source-types $(s) ] ;
|
| 934 |
+
if $(viable-sources) = *
|
| 935 |
+
{
|
| 936 |
+
result = * ;
|
| 937 |
+
source-types = ; # Terminate the loop.
|
| 938 |
+
}
|
| 939 |
+
else
|
| 940 |
+
{
|
| 941 |
+
result += [ type.all-derived $(s) ] $(viable-sources) ;
|
| 942 |
+
}
|
| 943 |
+
}
|
| 944 |
+
return [ sequence.unique $(result) ] ;
|
| 945 |
+
}
|
| 946 |
+
}
|
| 947 |
+
|
| 948 |
+
|
| 949 |
+
# Helper rule, caches the result of 'viable-source-types-for-generator'.
|
| 950 |
+
#
|
| 951 |
+
local rule viable-source-types-for-generator ( generator )
|
| 952 |
+
{
|
| 953 |
+
local key = .vstg.$(generator) ;
|
| 954 |
+
if ! $($(key))
|
| 955 |
+
{
|
| 956 |
+
.vstg-cached-generators += $(generator) ;
|
| 957 |
+
local v = [ viable-source-types-for-generator-real $(generator) ] ;
|
| 958 |
+
if ! $(v)
|
| 959 |
+
{
|
| 960 |
+
v = none ;
|
| 961 |
+
}
|
| 962 |
+
$(key) = $(v) ;
|
| 963 |
+
}
|
| 964 |
+
|
| 965 |
+
if $($(key)) != none
|
| 966 |
+
{
|
| 967 |
+
return $($(key)) ;
|
| 968 |
+
}
|
| 969 |
+
}
|
| 970 |
+
|
| 971 |
+
|
| 972 |
+
# Returns usage requirements + list of created targets.
|
| 973 |
+
#
|
| 974 |
+
local rule try-one-generator-really ( project name ? : generator : target-type
|
| 975 |
+
: property-set : sources * )
|
| 976 |
+
{
|
| 977 |
+
local targets =
|
| 978 |
+
[ $(generator).run $(project) $(name) : $(property-set) : $(sources) ] ;
|
| 979 |
+
|
| 980 |
+
local usage-requirements ;
|
| 981 |
+
local success ;
|
| 982 |
+
|
| 983 |
+
generators.dout [ indent ] returned $(targets) ;
|
| 984 |
+
|
| 985 |
+
if $(targets)
|
| 986 |
+
{
|
| 987 |
+
success = true ;
|
| 988 |
+
|
| 989 |
+
if [ class.is-a $(targets[1]) : property-set ]
|
| 990 |
+
{
|
| 991 |
+
usage-requirements = $(targets[1]) ;
|
| 992 |
+
targets = $(targets[2-]) ;
|
| 993 |
+
}
|
| 994 |
+
else
|
| 995 |
+
{
|
| 996 |
+
usage-requirements = [ property-set.empty ] ;
|
| 997 |
+
}
|
| 998 |
+
}
|
| 999 |
+
|
| 1000 |
+
generators.dout [ indent ] " generator" [ $(generator).id ] " spawned " ;
|
| 1001 |
+
generators.dout [ indent ] " " $(targets) ;
|
| 1002 |
+
if $(usage-requirements)
|
| 1003 |
+
{
|
| 1004 |
+
generators.dout [ indent ] " with usage requirements:" $(x) ;
|
| 1005 |
+
}
|
| 1006 |
+
|
| 1007 |
+
if $(success)
|
| 1008 |
+
{
|
| 1009 |
+
return $(usage-requirements) $(targets) ;
|
| 1010 |
+
}
|
| 1011 |
+
}
|
| 1012 |
+
|
| 1013 |
+
|
| 1014 |
+
# Checks if generator invocation can be pruned, because it is guaranteed to
|
| 1015 |
+
# fail. If so, quickly returns an empty list. Otherwise, calls
|
| 1016 |
+
# try-one-generator-really.
|
| 1017 |
+
#
|
| 1018 |
+
local rule try-one-generator ( project name ? : generator : target-type
|
| 1019 |
+
: property-set : sources * )
|
| 1020 |
+
{
|
| 1021 |
+
local source-types ;
|
| 1022 |
+
for local s in $(sources)
|
| 1023 |
+
{
|
| 1024 |
+
source-types += [ $(s).type ] ;
|
| 1025 |
+
}
|
| 1026 |
+
local viable-source-types = [ viable-source-types-for-generator $(generator)
|
| 1027 |
+
] ;
|
| 1028 |
+
|
| 1029 |
+
if $(source-types) && $(viable-source-types) != * &&
|
| 1030 |
+
! [ set.intersection $(source-types) : $(viable-source-types) ]
|
| 1031 |
+
{
|
| 1032 |
+
local id = [ $(generator).id ] ;
|
| 1033 |
+
generators.dout [ indent ] " ** generator '$(id)' pruned" ;
|
| 1034 |
+
#generators.dout [ indent ] "source-types" '$(source-types)' ;
|
| 1035 |
+
#generators.dout [ indent ] "viable-source-types" '$(viable-source-types)' ;
|
| 1036 |
+
}
|
| 1037 |
+
else
|
| 1038 |
+
{
|
| 1039 |
+
return [ try-one-generator-really $(project) $(name) : $(generator) :
|
| 1040 |
+
$(target-type) : $(property-set) : $(sources) ] ;
|
| 1041 |
+
}
|
| 1042 |
+
}
|
| 1043 |
+
|
| 1044 |
+
|
| 1045 |
+
rule construct-types ( project name ? : target-types + : property-set
|
| 1046 |
+
: sources + )
|
| 1047 |
+
{
|
| 1048 |
+
local result ;
|
| 1049 |
+
local usage-requirements = [ property-set.empty ] ;
|
| 1050 |
+
for local t in $(target-types)
|
| 1051 |
+
{
|
| 1052 |
+
local r = [ construct $(project) $(name) : $(t) : $(property-set) :
|
| 1053 |
+
$(sources) ] ;
|
| 1054 |
+
if $(r)
|
| 1055 |
+
{
|
| 1056 |
+
usage-requirements = [ $(usage-requirements).add $(r[1]) ] ;
|
| 1057 |
+
result += $(r[2-]) ;
|
| 1058 |
+
}
|
| 1059 |
+
}
|
| 1060 |
+
# TODO: have to introduce parameter controlling if several types can be
|
| 1061 |
+
# matched and add appropriate checks.
|
| 1062 |
+
|
| 1063 |
+
# TODO: need to review the documentation for 'construct' to see if it should
|
| 1064 |
+
# return $(source) even if nothing can be done with it. Currents docs seem
|
| 1065 |
+
# to imply that, contrary to the behaviour.
|
| 1066 |
+
if $(result)
|
| 1067 |
+
{
|
| 1068 |
+
return $(usage-requirements) $(result) ;
|
| 1069 |
+
}
|
| 1070 |
+
else
|
| 1071 |
+
{
|
| 1072 |
+
return $(usage-requirements) $(sources) ;
|
| 1073 |
+
}
|
| 1074 |
+
}
|
| 1075 |
+
|
| 1076 |
+
|
| 1077 |
+
# Ensures all 'targets' have their type. If this is not so, exists with error.
|
| 1078 |
+
#
|
| 1079 |
+
local rule ensure-type ( targets * )
|
| 1080 |
+
{
|
| 1081 |
+
for local t in $(targets)
|
| 1082 |
+
{
|
| 1083 |
+
if ! [ $(t).type ]
|
| 1084 |
+
{
|
| 1085 |
+
errors.error "target" [ $(t).str ] "has no type" ;
|
| 1086 |
+
}
|
| 1087 |
+
}
|
| 1088 |
+
}
|
| 1089 |
+
|
| 1090 |
+
|
| 1091 |
+
# Returns generators which can be used to construct target of specified type
|
| 1092 |
+
# with specified properties. Uses the following algorithm:
|
| 1093 |
+
# - iterates over requested target-type and all its bases (in the order returned
|
| 1094 |
+
# by type.all-bases).
|
| 1095 |
+
# - for each type find all generators that generate that type and whose
|
| 1096 |
+
# requirements are satisfied by properties.
|
| 1097 |
+
# - if the set of generators is not empty, returns that set.
|
| 1098 |
+
#
|
| 1099 |
+
# Note: this algorithm explicitly ignores generators for base classes if there
|
| 1100 |
+
# is at least one generator for the requested target-type.
|
| 1101 |
+
#
|
| 1102 |
+
local rule find-viable-generators-aux ( target-type : property-set )
|
| 1103 |
+
{
|
| 1104 |
+
# Select generators that can create the required target type.
|
| 1105 |
+
local viable-generators = ;
|
| 1106 |
+
local generator-rank = ;
|
| 1107 |
+
|
| 1108 |
+
import type ;
|
| 1109 |
+
local t = [ type.all-bases $(target-type) ] ;
|
| 1110 |
+
|
| 1111 |
+
generators.dout [ indent ] find-viable-generators target-type= $(target-type)
|
| 1112 |
+
property-set= [ $(property-set).as-path ] ;
|
| 1113 |
+
|
| 1114 |
+
# Get the list of generators for the requested type. If no generator is
|
| 1115 |
+
# registered, try base type, and so on.
|
| 1116 |
+
local generators ;
|
| 1117 |
+
while $(t[1])
|
| 1118 |
+
{
|
| 1119 |
+
generators.dout [ indent ] "trying type" $(t[1]) ;
|
| 1120 |
+
if $(.generators.$(t[1]))
|
| 1121 |
+
{
|
| 1122 |
+
generators.dout [ indent ] "there are generators for this type" ;
|
| 1123 |
+
generators = $(.generators.$(t[1])) ;
|
| 1124 |
+
|
| 1125 |
+
if $(t[1]) != $(target-type)
|
| 1126 |
+
{
|
| 1127 |
+
# We are here because there were no generators found for
|
| 1128 |
+
# target-type but there are some generators for its base type.
|
| 1129 |
+
# We will try to use them, but they will produce targets of
|
| 1130 |
+
# base type, not of 'target-type'. So, we clone the generators
|
| 1131 |
+
# and modify the list of target types.
|
| 1132 |
+
local generators2 ;
|
| 1133 |
+
for local g in $(generators)
|
| 1134 |
+
{
|
| 1135 |
+
# generators.register adds a generator to the list of
|
| 1136 |
+
# generators for toolsets, which is a bit strange, but
|
| 1137 |
+
# should work. That list is only used when inheriting a
|
| 1138 |
+
# toolset, which should have been done before running
|
| 1139 |
+
# generators.
|
| 1140 |
+
generators2 += [ $(g).clone-and-change-target-type $(t[1]) :
|
| 1141 |
+
$(target-type) ] ;
|
| 1142 |
+
generators.register $(generators2[-1]) ;
|
| 1143 |
+
}
|
| 1144 |
+
generators = $(generators2) ;
|
| 1145 |
+
}
|
| 1146 |
+
t = ;
|
| 1147 |
+
}
|
| 1148 |
+
t = $(t[2-]) ;
|
| 1149 |
+
}
|
| 1150 |
+
|
| 1151 |
+
for local g in $(generators)
|
| 1152 |
+
{
|
| 1153 |
+
generators.dout [ indent ] "trying generator" [ $(g).id ] "(" [ $(g).source-types ] -> [ $(g).target-types ] ")" ;
|
| 1154 |
+
|
| 1155 |
+
local m = [ $(g).match-rank $(property-set) ] ;
|
| 1156 |
+
if $(m)
|
| 1157 |
+
{
|
| 1158 |
+
generators.dout [ indent ] " is viable" ;
|
| 1159 |
+
viable-generators += $(g) ;
|
| 1160 |
+
}
|
| 1161 |
+
}
|
| 1162 |
+
|
| 1163 |
+
return $(viable-generators) ;
|
| 1164 |
+
}
|
| 1165 |
+
|
| 1166 |
+
|
| 1167 |
+
rule find-viable-generators ( target-type : property-set )
|
| 1168 |
+
{
|
| 1169 |
+
local key = $(target-type).$(property-set) ;
|
| 1170 |
+
local l = $(.fv.$(key)) ;
|
| 1171 |
+
if ! $(l)
|
| 1172 |
+
{
|
| 1173 |
+
l = [ find-viable-generators-aux $(target-type) : $(property-set) ] ;
|
| 1174 |
+
if ! $(l)
|
| 1175 |
+
{
|
| 1176 |
+
l = none ;
|
| 1177 |
+
}
|
| 1178 |
+
.fv.$(key) = $(l) ;
|
| 1179 |
+
}
|
| 1180 |
+
|
| 1181 |
+
if $(l) = none
|
| 1182 |
+
{
|
| 1183 |
+
l = ;
|
| 1184 |
+
}
|
| 1185 |
+
|
| 1186 |
+
local viable-generators ;
|
| 1187 |
+
for local g in $(l)
|
| 1188 |
+
{
|
| 1189 |
+
# Avoid trying the same generator twice on different levels.
|
| 1190 |
+
if ! $(g) in $(.active-generators)
|
| 1191 |
+
{
|
| 1192 |
+
viable-generators += $(g) ;
|
| 1193 |
+
}
|
| 1194 |
+
else
|
| 1195 |
+
{
|
| 1196 |
+
generators.dout [ indent ] " generator " [ $(g).id ] "is active, discaring" ;
|
| 1197 |
+
}
|
| 1198 |
+
}
|
| 1199 |
+
|
| 1200 |
+
# Generators which override 'all'.
|
| 1201 |
+
local all-overrides ;
|
| 1202 |
+
# Generators which are overriden.
|
| 1203 |
+
local overriden-ids ;
|
| 1204 |
+
for local g in $(viable-generators)
|
| 1205 |
+
{
|
| 1206 |
+
local id = [ $(g).id ] ;
|
| 1207 |
+
local this-overrides = $(.override.$(id)) ;
|
| 1208 |
+
overriden-ids += $(this-overrides) ;
|
| 1209 |
+
if all in $(this-overrides)
|
| 1210 |
+
{
|
| 1211 |
+
all-overrides += $(g) ;
|
| 1212 |
+
}
|
| 1213 |
+
}
|
| 1214 |
+
if $(all-overrides)
|
| 1215 |
+
{
|
| 1216 |
+
viable-generators = $(all-overrides) ;
|
| 1217 |
+
}
|
| 1218 |
+
local result ;
|
| 1219 |
+
for local g in $(viable-generators)
|
| 1220 |
+
{
|
| 1221 |
+
if ! [ $(g).id ] in $(overriden-ids)
|
| 1222 |
+
{
|
| 1223 |
+
result += $(g) ;
|
| 1224 |
+
}
|
| 1225 |
+
}
|
| 1226 |
+
|
| 1227 |
+
return $(result) ;
|
| 1228 |
+
}
|
| 1229 |
+
|
| 1230 |
+
|
| 1231 |
+
.construct-stack = ;
|
| 1232 |
+
|
| 1233 |
+
|
| 1234 |
+
# Attempts to construct a target by finding viable generators, running them and
|
| 1235 |
+
# selecting the dependency graph.
|
| 1236 |
+
#
|
| 1237 |
+
local rule construct-really ( project name ? : target-type : property-set :
|
| 1238 |
+
sources * )
|
| 1239 |
+
{
|
| 1240 |
+
viable-generators = [ find-viable-generators $(target-type) :
|
| 1241 |
+
$(property-set) ] ;
|
| 1242 |
+
|
| 1243 |
+
generators.dout [ indent ] "*** " [ sequence.length $(viable-generators) ]
|
| 1244 |
+
" viable generators" ;
|
| 1245 |
+
|
| 1246 |
+
local result ;
|
| 1247 |
+
local generators-that-succeeded ;
|
| 1248 |
+
for local g in $(viable-generators)
|
| 1249 |
+
{
|
| 1250 |
+
# This variable will be restored on exit from this scope.
|
| 1251 |
+
local .active-generators = $(g) $(.active-generators) ;
|
| 1252 |
+
|
| 1253 |
+
local r = [ try-one-generator $(project) $(name) : $(g) : $(target-type)
|
| 1254 |
+
: $(property-set) : $(sources) ] ;
|
| 1255 |
+
|
| 1256 |
+
if $(r)
|
| 1257 |
+
{
|
| 1258 |
+
generators-that-succeeded += $(g) ;
|
| 1259 |
+
if $(result)
|
| 1260 |
+
{
|
| 1261 |
+
ECHO "Error: ambiguity found when searching for best transformation" ;
|
| 1262 |
+
ECHO "Trying to produce type '$(target-type)' from: " ;
|
| 1263 |
+
for local s in $(sources)
|
| 1264 |
+
{
|
| 1265 |
+
ECHO " - " [ $(s).str ] ;
|
| 1266 |
+
}
|
| 1267 |
+
ECHO "Generators that succeeded:" ;
|
| 1268 |
+
for local g in $(generators-that-succeeded)
|
| 1269 |
+
{
|
| 1270 |
+
ECHO " - " [ $(g).id ] ;
|
| 1271 |
+
}
|
| 1272 |
+
ECHO "First generator produced: " ;
|
| 1273 |
+
for local t in $(result[2-])
|
| 1274 |
+
{
|
| 1275 |
+
ECHO " - " [ $(t).str ] ;
|
| 1276 |
+
}
|
| 1277 |
+
ECHO "Second generator produced: " ;
|
| 1278 |
+
for local t in $(r[2-])
|
| 1279 |
+
{
|
| 1280 |
+
ECHO " - " [ $(t).str ] ;
|
| 1281 |
+
}
|
| 1282 |
+
EXIT ;
|
| 1283 |
+
}
|
| 1284 |
+
else
|
| 1285 |
+
{
|
| 1286 |
+
result = $(r) ;
|
| 1287 |
+
}
|
| 1288 |
+
}
|
| 1289 |
+
}
|
| 1290 |
+
|
| 1291 |
+
return $(result) ;
|
| 1292 |
+
}
|
| 1293 |
+
|
| 1294 |
+
|
| 1295 |
+
# Attempts to create a target of 'target-type' with 'properties' from 'sources'.
|
| 1296 |
+
# The 'sources' are treated as a collection of *possible* ingridients, i.e.
|
| 1297 |
+
# there is no obligation to consume them all.
|
| 1298 |
+
#
|
| 1299 |
+
# Returns a list of targets. When this invocation is first instance of
|
| 1300 |
+
# 'construct' in stack, returns only targets of requested 'target-type',
|
| 1301 |
+
# otherwise, returns also unused sources and additionally generated targets.
|
| 1302 |
+
#
|
| 1303 |
+
# If 'top-level' is set, does not suppress generators that are already
|
| 1304 |
+
# used in the stack. This may be useful in cases where a generator
|
| 1305 |
+
# has to build a metatargets -- for example a target corresponding to
|
| 1306 |
+
# built tool.
|
| 1307 |
+
#
|
| 1308 |
+
rule construct ( project name ? : target-type : property-set * : sources * : top-level ? )
|
| 1309 |
+
{
|
| 1310 |
+
local saved-stack ;
|
| 1311 |
+
if $(top-level)
|
| 1312 |
+
{
|
| 1313 |
+
saved-active = $(.active-generators) ;
|
| 1314 |
+
.active-generators = ;
|
| 1315 |
+
}
|
| 1316 |
+
|
| 1317 |
+
if (.construct-stack)
|
| 1318 |
+
{
|
| 1319 |
+
ensure-type $(sources) ;
|
| 1320 |
+
}
|
| 1321 |
+
|
| 1322 |
+
.construct-stack += 1 ;
|
| 1323 |
+
|
| 1324 |
+
increase-indent ;
|
| 1325 |
+
|
| 1326 |
+
if $(.debug)
|
| 1327 |
+
{
|
| 1328 |
+
generators.dout [ indent ] "*** construct" $(target-type) ;
|
| 1329 |
+
|
| 1330 |
+
for local s in $(sources)
|
| 1331 |
+
{
|
| 1332 |
+
generators.dout [ indent ] " from" $(s) ;
|
| 1333 |
+
}
|
| 1334 |
+
generators.dout [ indent ] " properties:" [ $(property-set).raw ] ;
|
| 1335 |
+
}
|
| 1336 |
+
|
| 1337 |
+
local result = [ construct-really $(project) $(name) : $(target-type) :
|
| 1338 |
+
$(property-set) : $(sources) ] ;
|
| 1339 |
+
|
| 1340 |
+
decrease-indent ;
|
| 1341 |
+
|
| 1342 |
+
.construct-stack = $(.construct-stack[2-]) ;
|
| 1343 |
+
|
| 1344 |
+
if $(top-level)
|
| 1345 |
+
{
|
| 1346 |
+
.active-generators = $(saved-active) ;
|
| 1347 |
+
}
|
| 1348 |
+
|
| 1349 |
+
return $(result) ;
|
| 1350 |
+
}
|
| 1351 |
+
|
| 1352 |
+
# Given 'result', obtained from some generator or generators.construct, adds
|
| 1353 |
+
# 'raw-properties' as usage requirements to it. If result already contains usage
|
| 1354 |
+
# requirements -- that is the first element of result of an instance of the
|
| 1355 |
+
# property-set class, the existing usage requirements and 'raw-properties' are
|
| 1356 |
+
# combined.
|
| 1357 |
+
#
|
| 1358 |
+
rule add-usage-requirements ( result * : raw-properties * )
|
| 1359 |
+
{
|
| 1360 |
+
if $(result)
|
| 1361 |
+
{
|
| 1362 |
+
if [ class.is-a $(result[1]) : property-set ]
|
| 1363 |
+
{
|
| 1364 |
+
return [ $(result[1]).add-raw $(raw-properties) ] $(result[2-]) ;
|
| 1365 |
+
}
|
| 1366 |
+
else
|
| 1367 |
+
{
|
| 1368 |
+
return [ property-set.create $(raw-properties) ] $(result) ;
|
| 1369 |
+
}
|
| 1370 |
+
}
|
| 1371 |
+
}
|
| 1372 |
+
|
| 1373 |
+
rule dump ( )
|
| 1374 |
+
{
|
| 1375 |
+
for local g in $(.all-generators)
|
| 1376 |
+
{
|
| 1377 |
+
ECHO [ $(g).id ] ":" [ $(g).source-types ] -> [ $(g).target-types ] ;
|
| 1378 |
+
}
|
| 1379 |
+
}
|
| 1380 |
+
|
mosesdecoder/jam-files/boost-build/build/modifiers.jam
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2003 Rene Rivera
|
| 2 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 3 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 4 |
+
|
| 5 |
+
# Modifiers are generalized generators that mutate targets in specific ways.
|
| 6 |
+
# This structure allows for grouping a variety of functionality in an
|
| 7 |
+
# orthogonal way to the functionality in toolsets, and without specifying
|
| 8 |
+
# more target variations. In turn the modifiers can be used as building
|
| 9 |
+
# blocks to implement simple requests, like the <version> feature.
|
| 10 |
+
|
| 11 |
+
import modules ;
|
| 12 |
+
import feature ;
|
| 13 |
+
import errors ;
|
| 14 |
+
import type ;
|
| 15 |
+
import "class" : new ;
|
| 16 |
+
import generators ;
|
| 17 |
+
import property ;
|
| 18 |
+
import virtual-target ;
|
| 19 |
+
import numbers ;
|
| 20 |
+
import sequence ;
|
| 21 |
+
import symlink ;
|
| 22 |
+
import property-set ;
|
| 23 |
+
|
| 24 |
+
# Base generator for creating targets that are modifications of existing
|
| 25 |
+
# targets.
|
| 26 |
+
#
|
| 27 |
+
class modifier : generator
|
| 28 |
+
{
|
| 29 |
+
rule __init__ (
|
| 30 |
+
id
|
| 31 |
+
composing ?
|
| 32 |
+
: source-types *
|
| 33 |
+
: target-types-and-names +
|
| 34 |
+
: requirements *
|
| 35 |
+
)
|
| 36 |
+
{
|
| 37 |
+
generator.__init__ $(id) $(composing)
|
| 38 |
+
: $(source-types)
|
| 39 |
+
: $(target-types-and-names)
|
| 40 |
+
: $(requirements) ;
|
| 41 |
+
|
| 42 |
+
self.targets-in-progress = ;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
# Wraps the generation of the target to call before and after rules to
|
| 46 |
+
# affect the real target.
|
| 47 |
+
#
|
| 48 |
+
rule run ( project name ? : property-set : sources + )
|
| 49 |
+
{
|
| 50 |
+
local result ;
|
| 51 |
+
local current-target = $(project)^$(name) ;
|
| 52 |
+
if ! $(current-target) in $(self.targets-in-progress)
|
| 53 |
+
{
|
| 54 |
+
# Before modifications...
|
| 55 |
+
local project_ =
|
| 56 |
+
[ modify-project-before
|
| 57 |
+
$(project) $(name) : $(property-set) : $(sources) ] ;
|
| 58 |
+
local name_ =
|
| 59 |
+
[ modify-name-before
|
| 60 |
+
$(project) $(name) : $(property-set) : $(sources) ] ;
|
| 61 |
+
local property-set_ =
|
| 62 |
+
[ modify-properties-before
|
| 63 |
+
$(project) $(name) : $(property-set) : $(sources) ] ;
|
| 64 |
+
local sources_ =
|
| 65 |
+
[ modify-sources-before
|
| 66 |
+
$(project) $(name) : $(property-set) : $(sources) ] ;
|
| 67 |
+
project = $(project_) ;
|
| 68 |
+
name = $(name_) ;
|
| 69 |
+
property-set = $(property-set_) ;
|
| 70 |
+
sources = $(sources_) ;
|
| 71 |
+
|
| 72 |
+
# Generate the real target...
|
| 73 |
+
local target-type-p =
|
| 74 |
+
[ property.select <main-target-type> : [ $(property-set).raw ] ] ;
|
| 75 |
+
self.targets-in-progress += $(current-target) ;
|
| 76 |
+
result =
|
| 77 |
+
[ generators.construct $(project) $(name)
|
| 78 |
+
: $(target-type-p:G=)
|
| 79 |
+
: $(property-set)
|
| 80 |
+
: $(sources) ] ;
|
| 81 |
+
self.targets-in-progress = $(self.targets-in-progress[1--2]) ;
|
| 82 |
+
|
| 83 |
+
# After modifications...
|
| 84 |
+
result =
|
| 85 |
+
[ modify-target-after $(result)
|
| 86 |
+
: $(project) $(name)
|
| 87 |
+
: $(property-set)
|
| 88 |
+
: $(sources) ] ;
|
| 89 |
+
}
|
| 90 |
+
return $(result) ;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
rule modify-project-before ( project name ? : property-set : sources + )
|
| 94 |
+
{
|
| 95 |
+
return $(project) ;
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
rule modify-name-before ( project name ? : property-set : sources + )
|
| 99 |
+
{
|
| 100 |
+
return $(name) ;
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
rule modify-properties-before ( project name ? : property-set : sources + )
|
| 104 |
+
{
|
| 105 |
+
return $(property-set) ;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
rule modify-sources-before ( project name ? : property-set : sources + )
|
| 109 |
+
{
|
| 110 |
+
return $(sources) ;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
rule modify-target-after ( target : project name ? : property-set : sources + )
|
| 114 |
+
{
|
| 115 |
+
return $(target) ;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
# Utility, clones a file-target with optional changes to the name, type and
|
| 119 |
+
# project of the target.
|
| 120 |
+
# NOTE: This functionality should be moved, and generalized, to
|
| 121 |
+
# virtual-targets.
|
| 122 |
+
#
|
| 123 |
+
rule clone-file-target ( target : new-name ? : new-type ? : new-project ? )
|
| 124 |
+
{
|
| 125 |
+
# Need a MUTCH better way to clone a target...
|
| 126 |
+
new-name ?= [ $(target).name ] ;
|
| 127 |
+
new-type ?= [ $(target).type ] ;
|
| 128 |
+
new-project ?= [ $(target).project ] ;
|
| 129 |
+
local result = [ new file-target $(new-name) : $(new-type) : $(new-project) ] ;
|
| 130 |
+
|
| 131 |
+
if [ $(target).dependencies ] { $(result).depends [ $(target).dependencies ] ; }
|
| 132 |
+
$(result).root [ $(target).root ] ;
|
| 133 |
+
$(result).set-usage-requirements [ $(target).usage-requirements ] ;
|
| 134 |
+
|
| 135 |
+
local action = [ $(target).action ] ;
|
| 136 |
+
local action-class = [ modules.peek $(action) : __class__ ] ;
|
| 137 |
+
|
| 138 |
+
local ps = [ $(action).properties ] ;
|
| 139 |
+
local cloned-action = [ new $(action-class) $(result) :
|
| 140 |
+
[ $(action).sources ] : [ $(action).action-name ] : $(ps) ] ;
|
| 141 |
+
$(result).action $(cloned-action) ;
|
| 142 |
+
|
| 143 |
+
return $(result) ;
|
| 144 |
+
}
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
|
| 148 |
+
# A modifier that changes the name of a target, after it's generated, given a
|
| 149 |
+
# regular expression to split the name, and a set of token to insert between the
|
| 150 |
+
# split tokens of the name. This also exposes the target for other uses with a
|
| 151 |
+
# symlink to the original name (optionally).
|
| 152 |
+
#
|
| 153 |
+
class name-modifier : modifier
|
| 154 |
+
{
|
| 155 |
+
rule __init__ ( )
|
| 156 |
+
{
|
| 157 |
+
# Apply ourselves to EXE targets, for now.
|
| 158 |
+
modifier.__init__ name.modifier : : EXE LIB : <name-modify>yes ;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
# Modifies the name, by cloning the target with the new name.
|
| 162 |
+
#
|
| 163 |
+
rule modify-target-after ( target : project name ? : property-set : sources + )
|
| 164 |
+
{
|
| 165 |
+
local result = $(target) ;
|
| 166 |
+
|
| 167 |
+
local name-mod-p = [ property.select <name-modifier> : [ $(property-set).raw ] ] ;
|
| 168 |
+
if $(name-mod-p)
|
| 169 |
+
{
|
| 170 |
+
local new-name = [ modify-name [ $(target).name ] : $(name-mod-p:G=) ] ;
|
| 171 |
+
if $(new-name) != [ $(target).name ]
|
| 172 |
+
{
|
| 173 |
+
result = [ clone-file-target $(target) : $(new-name) ] ;
|
| 174 |
+
}
|
| 175 |
+
local expose-original-as-symlink = [ MATCH "<symlink>(.*)" : $(name-mod-p) ] ;
|
| 176 |
+
if $(expose-original-as-symlink)
|
| 177 |
+
{
|
| 178 |
+
local symlink-t = [ new symlink-targets $(project) : $(name) : [ $(result).name ] ] ;
|
| 179 |
+
result = [ $(symlink-t).construct $(result)
|
| 180 |
+
: [ property-set.create [ $(property-set).raw ] <symlink-location>build-relative ] ] ;
|
| 181 |
+
}
|
| 182 |
+
}
|
| 183 |
+
|
| 184 |
+
return $(result) ;
|
| 185 |
+
}
|
| 186 |
+
|
| 187 |
+
# Do the transformation of the name.
|
| 188 |
+
#
|
| 189 |
+
rule modify-name ( name : modifier-spec + )
|
| 190 |
+
{
|
| 191 |
+
local match = [ MATCH "<match>(.*)" : $(modifier-spec) ] ;
|
| 192 |
+
local name-parts = [ MATCH $(match) : $(name) ] ;
|
| 193 |
+
local insertions = [ sequence.insertion-sort [ MATCH "(<[0123456789]+>.*)" : $(modifier-spec) ] ] ;
|
| 194 |
+
local new-name-parts ;
|
| 195 |
+
local insert-position = 1 ;
|
| 196 |
+
while $(insertions)
|
| 197 |
+
{
|
| 198 |
+
local insertion = [ MATCH "<$(insert-position)>(.*)" : $(insertions[1]) ] ;
|
| 199 |
+
if $(insertion)
|
| 200 |
+
{
|
| 201 |
+
new-name-parts += $(insertion) ;
|
| 202 |
+
insertions = $(insertions[2-]) ;
|
| 203 |
+
}
|
| 204 |
+
new-name-parts += $(name-parts[1]) ;
|
| 205 |
+
name-parts = $(name-parts[2-]) ;
|
| 206 |
+
insert-position = [ numbers.increment $(insert-position) ] ;
|
| 207 |
+
}
|
| 208 |
+
new-name-parts += $(name-parts) ;
|
| 209 |
+
return [ sequence.join $(new-name-parts) ] ;
|
| 210 |
+
}
|
| 211 |
+
|
| 212 |
+
rule optional-properties ( )
|
| 213 |
+
{
|
| 214 |
+
return <name-modify>yes ;
|
| 215 |
+
}
|
| 216 |
+
}
|
| 217 |
+
feature.feature name-modifier : : free ;
|
| 218 |
+
feature.feature name-modify : no yes : incidental optional ;
|
| 219 |
+
generators.register [ new name-modifier ] ;
|
| 220 |
+
|
| 221 |
+
# Translates <version> property to a set of modification properties
|
| 222 |
+
# that are applied by the name-modifier, and symlink-modifier.
|
| 223 |
+
#
|
| 224 |
+
rule version-to-modifier ( property : properties * )
|
| 225 |
+
{
|
| 226 |
+
return
|
| 227 |
+
<name-modify>yes
|
| 228 |
+
<name-modifier><match>"^([^.]*)(.*)" <name-modifier><2>.$(property:G=)
|
| 229 |
+
<name-modifier><symlink>yes
|
| 230 |
+
;
|
| 231 |
+
}
|
| 232 |
+
feature.action <version> : version-to-modifier ;
|
mosesdecoder/jam-files/boost-build/build/property.jam
ADDED
|
@@ -0,0 +1,788 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2001, 2002, 2003 Dave Abrahams
|
| 2 |
+
# Copyright 2006 Rene Rivera
|
| 3 |
+
# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
|
| 4 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 5 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 6 |
+
|
| 7 |
+
import errors ;
|
| 8 |
+
import feature ;
|
| 9 |
+
import indirect ;
|
| 10 |
+
import path ;
|
| 11 |
+
import regex ;
|
| 12 |
+
import string ;
|
| 13 |
+
import sequence ;
|
| 14 |
+
import set ;
|
| 15 |
+
import utility ;
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
# Refines 'properties' by overriding any non-free and non-conditional properties
|
| 19 |
+
# for which a different value is specified in 'requirements'. Returns the
|
| 20 |
+
# resulting list of properties.
|
| 21 |
+
#
|
| 22 |
+
rule refine ( properties * : requirements * )
|
| 23 |
+
{
|
| 24 |
+
local result ;
|
| 25 |
+
local error ;
|
| 26 |
+
|
| 27 |
+
# All the 'requirements' elements should be present in the result. Record
|
| 28 |
+
# them so that we can handle 'properties'.
|
| 29 |
+
for local r in $(requirements)
|
| 30 |
+
{
|
| 31 |
+
# Do not consider conditional requirements.
|
| 32 |
+
if ! [ MATCH (:) : $(r:G=) ]
|
| 33 |
+
{
|
| 34 |
+
# Note: cannot use a local variable here, so use an ugly name.
|
| 35 |
+
__require__$(r:G) = $(r:G=) ;
|
| 36 |
+
}
|
| 37 |
+
}
|
| 38 |
+
|
| 39 |
+
for local p in $(properties)
|
| 40 |
+
{
|
| 41 |
+
if [ MATCH (:) : $(p:G=) ]
|
| 42 |
+
{
|
| 43 |
+
# Do not modify conditional properties.
|
| 44 |
+
result += $(p) ;
|
| 45 |
+
}
|
| 46 |
+
else if free in [ feature.attributes $(p:G) ]
|
| 47 |
+
{
|
| 48 |
+
# Do not modify free properties.
|
| 49 |
+
result += $(p) ;
|
| 50 |
+
}
|
| 51 |
+
else
|
| 52 |
+
{
|
| 53 |
+
local required-value = $(__require__$(p:G)) ;
|
| 54 |
+
if $(required-value)
|
| 55 |
+
{
|
| 56 |
+
if $(p:G=) != $(required-value)
|
| 57 |
+
{
|
| 58 |
+
result += $(p:G)$(required-value) ;
|
| 59 |
+
}
|
| 60 |
+
else
|
| 61 |
+
{
|
| 62 |
+
result += $(p) ;
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
else
|
| 66 |
+
{
|
| 67 |
+
result += $(p) ;
|
| 68 |
+
}
|
| 69 |
+
}
|
| 70 |
+
}
|
| 71 |
+
|
| 72 |
+
# Unset our ugly map.
|
| 73 |
+
for local r in $(requirements)
|
| 74 |
+
{
|
| 75 |
+
__require__$(r:G) = ;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
if $(error)
|
| 79 |
+
{
|
| 80 |
+
return $(error) ;
|
| 81 |
+
}
|
| 82 |
+
else
|
| 83 |
+
{
|
| 84 |
+
return [ sequence.unique $(result) $(requirements) ] ;
|
| 85 |
+
}
|
| 86 |
+
}
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
# Removes all conditional properties whose conditions are not met. For those
|
| 90 |
+
# with met conditions, removes the condition. Properties in conditions are
|
| 91 |
+
# looked up in 'context'.
|
| 92 |
+
#
|
| 93 |
+
rule evaluate-conditionals-in-context ( properties * : context * )
|
| 94 |
+
{
|
| 95 |
+
local base ;
|
| 96 |
+
local conditionals ;
|
| 97 |
+
for local p in $(properties)
|
| 98 |
+
{
|
| 99 |
+
if [ MATCH (:<) : $(p) ]
|
| 100 |
+
{
|
| 101 |
+
conditionals += $(p) ;
|
| 102 |
+
}
|
| 103 |
+
else
|
| 104 |
+
{
|
| 105 |
+
base += $(p) ;
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
local result = $(base) ;
|
| 110 |
+
for local p in $(conditionals)
|
| 111 |
+
{
|
| 112 |
+
# Separate condition and property.
|
| 113 |
+
local s = [ MATCH (.*):(<.*) : $(p) ] ;
|
| 114 |
+
# Split condition into individual properties.
|
| 115 |
+
local condition = [ regex.split $(s[1]) "," ] ;
|
| 116 |
+
# Evaluate condition.
|
| 117 |
+
if ! [ MATCH (!).* : $(condition:G=) ]
|
| 118 |
+
{
|
| 119 |
+
# Only positive checks
|
| 120 |
+
if $(condition) in $(context)
|
| 121 |
+
{
|
| 122 |
+
result += $(s[2]) ;
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
else
|
| 126 |
+
{
|
| 127 |
+
# Have negative checks
|
| 128 |
+
local fail ;
|
| 129 |
+
while $(condition)
|
| 130 |
+
{
|
| 131 |
+
local c = $(condition[1]) ;
|
| 132 |
+
local m = [ MATCH !(.*) : $(c) ] ;
|
| 133 |
+
if $(m)
|
| 134 |
+
{
|
| 135 |
+
local p = $(m:G=$(c:G)) ;
|
| 136 |
+
if $(p) in $(context)
|
| 137 |
+
{
|
| 138 |
+
fail = true ;
|
| 139 |
+
c = ;
|
| 140 |
+
}
|
| 141 |
+
}
|
| 142 |
+
else
|
| 143 |
+
{
|
| 144 |
+
if ! $(c) in $(context)
|
| 145 |
+
{
|
| 146 |
+
fail = true ;
|
| 147 |
+
c = ;
|
| 148 |
+
}
|
| 149 |
+
}
|
| 150 |
+
condition = $(condition[2-]) ;
|
| 151 |
+
}
|
| 152 |
+
if ! $(fail)
|
| 153 |
+
{
|
| 154 |
+
result += $(s[2]) ;
|
| 155 |
+
}
|
| 156 |
+
}
|
| 157 |
+
}
|
| 158 |
+
return $(result) ;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
|
| 162 |
+
rule expand-subfeatures-in-conditions ( properties * )
|
| 163 |
+
{
|
| 164 |
+
local result ;
|
| 165 |
+
for local p in $(properties)
|
| 166 |
+
{
|
| 167 |
+
local s = [ MATCH (.*):(<.*) : $(p) ] ;
|
| 168 |
+
if ! $(s)
|
| 169 |
+
{
|
| 170 |
+
result += $(p) ;
|
| 171 |
+
}
|
| 172 |
+
else
|
| 173 |
+
{
|
| 174 |
+
local condition = $(s[1]) ;
|
| 175 |
+
local value = $(s[2]) ;
|
| 176 |
+
# Condition might include several elements.
|
| 177 |
+
condition = [ regex.split $(condition) "," ] ;
|
| 178 |
+
local e ;
|
| 179 |
+
for local c in $(condition)
|
| 180 |
+
{
|
| 181 |
+
# It is common for a condition to include a toolset or
|
| 182 |
+
# subfeatures that have not been defined. In that case we want
|
| 183 |
+
# the condition to simply 'never be satisfied' and validation
|
| 184 |
+
# would only produce a spurious error so we prevent it by
|
| 185 |
+
# passing 'true' as the second parameter.
|
| 186 |
+
e += [ feature.expand-subfeatures $(c) : true ] ;
|
| 187 |
+
}
|
| 188 |
+
if $(e) = $(condition)
|
| 189 |
+
{
|
| 190 |
+
# (todo)
|
| 191 |
+
# This is just an optimization and possibly a premature one at
|
| 192 |
+
# that.
|
| 193 |
+
# (todo) (12.07.2008.) (Jurko)
|
| 194 |
+
result += $(p) ;
|
| 195 |
+
}
|
| 196 |
+
else
|
| 197 |
+
{
|
| 198 |
+
result += $(e:J=,):$(value) ;
|
| 199 |
+
}
|
| 200 |
+
}
|
| 201 |
+
}
|
| 202 |
+
return $(result) ;
|
| 203 |
+
}
|
| 204 |
+
|
| 205 |
+
|
| 206 |
+
# Helper for as-path, below. Orders properties with the implicit ones first, and
|
| 207 |
+
# within the two sections in alphabetical order of feature name.
|
| 208 |
+
#
|
| 209 |
+
local rule path-order ( x y )
|
| 210 |
+
{
|
| 211 |
+
if $(y:G) && ! $(x:G)
|
| 212 |
+
{
|
| 213 |
+
return true ;
|
| 214 |
+
}
|
| 215 |
+
else if $(x:G) && ! $(y:G)
|
| 216 |
+
{
|
| 217 |
+
return ;
|
| 218 |
+
}
|
| 219 |
+
else
|
| 220 |
+
{
|
| 221 |
+
if ! $(x:G)
|
| 222 |
+
{
|
| 223 |
+
x = [ feature.expand-subfeatures $(x) ] ;
|
| 224 |
+
y = [ feature.expand-subfeatures $(y) ] ;
|
| 225 |
+
}
|
| 226 |
+
|
| 227 |
+
if $(x[1]) < $(y[1])
|
| 228 |
+
{
|
| 229 |
+
return true ;
|
| 230 |
+
}
|
| 231 |
+
}
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
|
| 235 |
+
local rule abbreviate-dashed ( string )
|
| 236 |
+
{
|
| 237 |
+
local r ;
|
| 238 |
+
for local part in [ regex.split $(string) - ]
|
| 239 |
+
{
|
| 240 |
+
r += [ string.abbreviate $(part) ] ;
|
| 241 |
+
}
|
| 242 |
+
return $(r:J=-) ;
|
| 243 |
+
}
|
| 244 |
+
|
| 245 |
+
|
| 246 |
+
local rule identity ( string )
|
| 247 |
+
{
|
| 248 |
+
return $(string) ;
|
| 249 |
+
}
|
| 250 |
+
|
| 251 |
+
|
| 252 |
+
if --abbreviate-paths in [ modules.peek : ARGV ]
|
| 253 |
+
{
|
| 254 |
+
.abbrev = abbreviate-dashed ;
|
| 255 |
+
}
|
| 256 |
+
else
|
| 257 |
+
{
|
| 258 |
+
.abbrev = identity ;
|
| 259 |
+
}
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
# Returns a path representing the given expanded property set.
|
| 263 |
+
#
|
| 264 |
+
rule as-path ( properties * )
|
| 265 |
+
{
|
| 266 |
+
local entry = .result.$(properties:J=-) ;
|
| 267 |
+
|
| 268 |
+
if ! $($(entry))
|
| 269 |
+
{
|
| 270 |
+
# Trim redundancy.
|
| 271 |
+
properties = [ feature.minimize $(properties) ] ;
|
| 272 |
+
|
| 273 |
+
# Sort according to path-order.
|
| 274 |
+
properties = [ sequence.insertion-sort $(properties) : path-order ] ;
|
| 275 |
+
|
| 276 |
+
local components ;
|
| 277 |
+
for local p in $(properties)
|
| 278 |
+
{
|
| 279 |
+
if $(p:G)
|
| 280 |
+
{
|
| 281 |
+
local f = [ utility.ungrist $(p:G) ] ;
|
| 282 |
+
p = $(f)-$(p:G=) ;
|
| 283 |
+
}
|
| 284 |
+
components += [ $(.abbrev) $(p) ] ;
|
| 285 |
+
}
|
| 286 |
+
|
| 287 |
+
$(entry) = $(components:J=/) ;
|
| 288 |
+
}
|
| 289 |
+
|
| 290 |
+
return $($(entry)) ;
|
| 291 |
+
}
|
| 292 |
+
|
| 293 |
+
|
| 294 |
+
# Exit with error if property is not valid.
|
| 295 |
+
#
|
| 296 |
+
local rule validate1 ( property )
|
| 297 |
+
{
|
| 298 |
+
local msg ;
|
| 299 |
+
if $(property:G)
|
| 300 |
+
{
|
| 301 |
+
local feature = $(property:G) ;
|
| 302 |
+
local value = $(property:G=) ;
|
| 303 |
+
|
| 304 |
+
if ! [ feature.valid $(feature) ]
|
| 305 |
+
{
|
| 306 |
+
# Ungrist for better error messages.
|
| 307 |
+
feature = [ utility.ungrist $(property:G) ] ;
|
| 308 |
+
msg = "unknown feature '$(feature)'" ;
|
| 309 |
+
}
|
| 310 |
+
else if $(value) && ! free in [ feature.attributes $(feature) ]
|
| 311 |
+
{
|
| 312 |
+
feature.validate-value-string $(feature) $(value) ;
|
| 313 |
+
}
|
| 314 |
+
else if ! ( $(value) || ( optional in [ feature.attributes $(feature) ] ) )
|
| 315 |
+
{
|
| 316 |
+
# Ungrist for better error messages.
|
| 317 |
+
feature = [ utility.ungrist $(property:G) ] ;
|
| 318 |
+
msg = "No value specified for feature '$(feature)'" ;
|
| 319 |
+
}
|
| 320 |
+
}
|
| 321 |
+
else
|
| 322 |
+
{
|
| 323 |
+
local feature = [ feature.implied-feature $(property) ] ;
|
| 324 |
+
feature.validate-value-string $(feature) $(property) ;
|
| 325 |
+
}
|
| 326 |
+
if $(msg)
|
| 327 |
+
{
|
| 328 |
+
errors.error "Invalid property "'$(property:J=" ")'": "$(msg:J=" "). ;
|
| 329 |
+
}
|
| 330 |
+
}
|
| 331 |
+
|
| 332 |
+
|
| 333 |
+
rule validate ( properties * )
|
| 334 |
+
{
|
| 335 |
+
for local p in $(properties)
|
| 336 |
+
{
|
| 337 |
+
validate1 $(p) ;
|
| 338 |
+
}
|
| 339 |
+
}
|
| 340 |
+
|
| 341 |
+
|
| 342 |
+
rule validate-property-sets ( property-sets * )
|
| 343 |
+
{
|
| 344 |
+
for local s in $(property-sets)
|
| 345 |
+
{
|
| 346 |
+
validate [ feature.split $(s) ] ;
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
|
| 351 |
+
# Expands any implicit property values in the given property 'specification' so
|
| 352 |
+
# they explicitly state their feature.
|
| 353 |
+
#
|
| 354 |
+
rule make ( specification * )
|
| 355 |
+
{
|
| 356 |
+
local result ;
|
| 357 |
+
for local e in $(specification)
|
| 358 |
+
{
|
| 359 |
+
if $(e:G)
|
| 360 |
+
{
|
| 361 |
+
result += $(e) ;
|
| 362 |
+
}
|
| 363 |
+
else if [ feature.is-implicit-value $(e) ]
|
| 364 |
+
{
|
| 365 |
+
local feature = [ feature.implied-feature $(e) ] ;
|
| 366 |
+
result += $(feature)$(e) ;
|
| 367 |
+
}
|
| 368 |
+
else
|
| 369 |
+
{
|
| 370 |
+
errors.error "'$(e)' is not a valid property specification" ;
|
| 371 |
+
}
|
| 372 |
+
}
|
| 373 |
+
return $(result) ;
|
| 374 |
+
}
|
| 375 |
+
|
| 376 |
+
|
| 377 |
+
# Returns a property set containing all the elements in 'properties' that do not
|
| 378 |
+
# have their attributes listed in 'attributes'.
|
| 379 |
+
#
|
| 380 |
+
rule remove ( attributes + : properties * )
|
| 381 |
+
{
|
| 382 |
+
local result ;
|
| 383 |
+
for local e in $(properties)
|
| 384 |
+
{
|
| 385 |
+
if ! [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
|
| 386 |
+
{
|
| 387 |
+
result += $(e) ;
|
| 388 |
+
}
|
| 389 |
+
}
|
| 390 |
+
return $(result) ;
|
| 391 |
+
}
|
| 392 |
+
|
| 393 |
+
|
| 394 |
+
# Returns a property set containing all the elements in 'properties' that have
|
| 395 |
+
# their attributes listed in 'attributes'.
|
| 396 |
+
#
|
| 397 |
+
rule take ( attributes + : properties * )
|
| 398 |
+
{
|
| 399 |
+
local result ;
|
| 400 |
+
for local e in $(properties)
|
| 401 |
+
{
|
| 402 |
+
if [ set.intersection $(attributes) : [ feature.attributes $(e:G) ] ]
|
| 403 |
+
{
|
| 404 |
+
result += $(e) ;
|
| 405 |
+
}
|
| 406 |
+
}
|
| 407 |
+
return $(result) ;
|
| 408 |
+
}
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
# Selects properties corresponding to any of the given features.
|
| 412 |
+
#
|
| 413 |
+
rule select ( features * : properties * )
|
| 414 |
+
{
|
| 415 |
+
local result ;
|
| 416 |
+
|
| 417 |
+
# Add any missing angle brackets.
|
| 418 |
+
local empty = "" ;
|
| 419 |
+
features = $(empty:G=$(features)) ;
|
| 420 |
+
|
| 421 |
+
for local p in $(properties)
|
| 422 |
+
{
|
| 423 |
+
if $(p:G) in $(features)
|
| 424 |
+
{
|
| 425 |
+
result += $(p) ;
|
| 426 |
+
}
|
| 427 |
+
}
|
| 428 |
+
return $(result) ;
|
| 429 |
+
}
|
| 430 |
+
|
| 431 |
+
|
| 432 |
+
# Returns a modified version of properties with all values of the given feature
|
| 433 |
+
# replaced by the given value. If 'value' is empty the feature will be removed.
|
| 434 |
+
#
|
| 435 |
+
rule change ( properties * : feature value ? )
|
| 436 |
+
{
|
| 437 |
+
local result ;
|
| 438 |
+
for local p in $(properties)
|
| 439 |
+
{
|
| 440 |
+
if $(p:G) = $(feature)
|
| 441 |
+
{
|
| 442 |
+
result += $(value:G=$(feature)) ;
|
| 443 |
+
}
|
| 444 |
+
else
|
| 445 |
+
{
|
| 446 |
+
result += $(p) ;
|
| 447 |
+
}
|
| 448 |
+
}
|
| 449 |
+
return $(result) ;
|
| 450 |
+
}
|
| 451 |
+
|
| 452 |
+
|
| 453 |
+
# If 'property' is a conditional property, returns the condition and the
|
| 454 |
+
# property. E.g. <variant>debug,<toolset>gcc:<inlining>full will become
|
| 455 |
+
# <variant>debug,<toolset>gcc <inlining>full. Otherwise, returns an empty
|
| 456 |
+
# string.
|
| 457 |
+
#
|
| 458 |
+
rule split-conditional ( property )
|
| 459 |
+
{
|
| 460 |
+
local m = [ MATCH "(.+):<(.+)" : $(property) ] ;
|
| 461 |
+
if $(m)
|
| 462 |
+
{
|
| 463 |
+
return $(m[1]) <$(m[2]) ;
|
| 464 |
+
}
|
| 465 |
+
}
|
| 466 |
+
|
| 467 |
+
|
| 468 |
+
# Interpret all path properties in 'properties' as relative to 'path'. The
|
| 469 |
+
# property values are assumed to be in system-specific form, and will be
|
| 470 |
+
# translated into normalized form.
|
| 471 |
+
#
|
| 472 |
+
rule translate-paths ( properties * : path )
|
| 473 |
+
{
|
| 474 |
+
local result ;
|
| 475 |
+
for local p in $(properties)
|
| 476 |
+
{
|
| 477 |
+
local split = [ split-conditional $(p) ] ;
|
| 478 |
+
local condition = "" ;
|
| 479 |
+
if $(split)
|
| 480 |
+
{
|
| 481 |
+
condition = $(split[1]): ;
|
| 482 |
+
p = $(split[2]) ;
|
| 483 |
+
}
|
| 484 |
+
|
| 485 |
+
if path in [ feature.attributes $(p:G) ]
|
| 486 |
+
{
|
| 487 |
+
local values = [ regex.split $(p:TG=) "&&" ] ;
|
| 488 |
+
local t ;
|
| 489 |
+
for local v in $(values)
|
| 490 |
+
{
|
| 491 |
+
t += [ path.root [ path.make $(v) ] $(path) ] ;
|
| 492 |
+
}
|
| 493 |
+
t = $(t:J="&&") ;
|
| 494 |
+
result += $(condition)$(t:TG=$(p:G)) ;
|
| 495 |
+
}
|
| 496 |
+
else
|
| 497 |
+
{
|
| 498 |
+
result += $(condition)$(p) ;
|
| 499 |
+
}
|
| 500 |
+
}
|
| 501 |
+
return $(result) ;
|
| 502 |
+
}
|
| 503 |
+
|
| 504 |
+
|
| 505 |
+
# Assumes that all feature values that start with '@' are names of rules, used
|
| 506 |
+
# in 'context-module'. Such rules can be either local to the module or global.
|
| 507 |
+
# Converts such values into 'indirect-rule' format (see indirect.jam), so they
|
| 508 |
+
# can be called from other modules. Does nothing for such values that are
|
| 509 |
+
# already in the 'indirect-rule' format.
|
| 510 |
+
#
|
| 511 |
+
rule translate-indirect ( specification * : context-module )
|
| 512 |
+
{
|
| 513 |
+
local result ;
|
| 514 |
+
for local p in $(specification)
|
| 515 |
+
{
|
| 516 |
+
local m = [ MATCH ^@(.+) : $(p:G=) ] ;
|
| 517 |
+
if $(m)
|
| 518 |
+
{
|
| 519 |
+
local v ;
|
| 520 |
+
if [ MATCH "^([^%]*)%([^%]+)$" : $(m) ]
|
| 521 |
+
{
|
| 522 |
+
# Rule is already in the 'indirect-rule' format.
|
| 523 |
+
v = $(m) ;
|
| 524 |
+
}
|
| 525 |
+
else
|
| 526 |
+
{
|
| 527 |
+
if ! [ MATCH ".*([.]).*" : $(m) ]
|
| 528 |
+
{
|
| 529 |
+
# This is an unqualified rule name. The user might want to
|
| 530 |
+
# set flags on this rule name and toolset.flag
|
| 531 |
+
# auto-qualifies it. Need to do the same here so flag
|
| 532 |
+
# setting works. We can arrange for toolset.flag to *not*
|
| 533 |
+
# auto-qualify the argument but then two rules defined in
|
| 534 |
+
# two Jamfiles would conflict.
|
| 535 |
+
m = $(context-module).$(m) ;
|
| 536 |
+
}
|
| 537 |
+
v = [ indirect.make $(m) : $(context-module) ] ;
|
| 538 |
+
}
|
| 539 |
+
|
| 540 |
+
v = @$(v) ;
|
| 541 |
+
result += $(v:G=$(p:G)) ;
|
| 542 |
+
}
|
| 543 |
+
else
|
| 544 |
+
{
|
| 545 |
+
result += $(p) ;
|
| 546 |
+
}
|
| 547 |
+
}
|
| 548 |
+
return $(result) ;
|
| 549 |
+
}
|
| 550 |
+
|
| 551 |
+
|
| 552 |
+
# Binds all dependency properties in a list relative to the given project.
|
| 553 |
+
# Targets with absolute paths will be left unchanged and targets which have a
|
| 554 |
+
# project specified will have the path to the project interpreted relative to
|
| 555 |
+
# the specified location.
|
| 556 |
+
#
|
| 557 |
+
rule translate-dependencies ( specification * : project-id : location )
|
| 558 |
+
{
|
| 559 |
+
local result ;
|
| 560 |
+
for local p in $(specification)
|
| 561 |
+
{
|
| 562 |
+
local split = [ split-conditional $(p) ] ;
|
| 563 |
+
local condition = "" ;
|
| 564 |
+
if $(split)
|
| 565 |
+
{
|
| 566 |
+
condition = $(split[1]): ;
|
| 567 |
+
p = $(split[2]) ;
|
| 568 |
+
}
|
| 569 |
+
if dependency in [ feature.attributes $(p:G) ]
|
| 570 |
+
{
|
| 571 |
+
local split-target = [ regex.match (.*)//(.*) : $(p:G=) ] ;
|
| 572 |
+
if $(split-target)
|
| 573 |
+
{
|
| 574 |
+
local rooted = [ path.root [ path.make $(split-target[1]) ]
|
| 575 |
+
[ path.root $(location) [ path.pwd ] ] ] ;
|
| 576 |
+
result += $(condition)$(p:G)$(rooted)//$(split-target[2]) ;
|
| 577 |
+
}
|
| 578 |
+
else if [ path.is-rooted $(p:G=) ]
|
| 579 |
+
{
|
| 580 |
+
result += $(condition)$(p) ;
|
| 581 |
+
}
|
| 582 |
+
else
|
| 583 |
+
{
|
| 584 |
+
result += $(condition)$(p:G)$(project-id)//$(p:G=) ;
|
| 585 |
+
}
|
| 586 |
+
}
|
| 587 |
+
else
|
| 588 |
+
{
|
| 589 |
+
result += $(condition)$(p) ;
|
| 590 |
+
}
|
| 591 |
+
}
|
| 592 |
+
return $(result) ;
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
|
| 596 |
+
# Class maintaining a property set -> string mapping.
|
| 597 |
+
#
|
| 598 |
+
class property-map
|
| 599 |
+
{
|
| 600 |
+
import errors ;
|
| 601 |
+
import numbers ;
|
| 602 |
+
import sequence ;
|
| 603 |
+
|
| 604 |
+
rule __init__ ( )
|
| 605 |
+
{
|
| 606 |
+
self.next-flag = 1 ;
|
| 607 |
+
}
|
| 608 |
+
|
| 609 |
+
# Associate 'value' with 'properties'.
|
| 610 |
+
#
|
| 611 |
+
rule insert ( properties + : value )
|
| 612 |
+
{
|
| 613 |
+
self.all-flags += $(self.next-flag) ;
|
| 614 |
+
self.properties.$(self.next-flag) = $(properties) ;
|
| 615 |
+
self.value.$(self.next-flag) = $(value) ;
|
| 616 |
+
|
| 617 |
+
self.next-flag = [ numbers.increment $(self.next-flag) ] ;
|
| 618 |
+
}
|
| 619 |
+
|
| 620 |
+
# Returns the value associated with 'properties' or any subset of it. If
|
| 621 |
+
# more than one subset has a value assigned to it, returns the value for the
|
| 622 |
+
# longest subset, if it is unique.
|
| 623 |
+
#
|
| 624 |
+
rule find ( properties + )
|
| 625 |
+
{
|
| 626 |
+
return [ find-replace $(properties) ] ;
|
| 627 |
+
}
|
| 628 |
+
|
| 629 |
+
# Returns the value associated with 'properties'. If 'value' parameter is
|
| 630 |
+
# given, replaces the found value.
|
| 631 |
+
#
|
| 632 |
+
rule find-replace ( properties + : value ? )
|
| 633 |
+
{
|
| 634 |
+
# First find all matches.
|
| 635 |
+
local matches ;
|
| 636 |
+
local match-ranks ;
|
| 637 |
+
for local i in $(self.all-flags)
|
| 638 |
+
{
|
| 639 |
+
if $(self.properties.$(i)) in $(properties)
|
| 640 |
+
{
|
| 641 |
+
matches += $(i) ;
|
| 642 |
+
match-ranks += [ sequence.length $(self.properties.$(i)) ] ;
|
| 643 |
+
}
|
| 644 |
+
}
|
| 645 |
+
local best = [ sequence.select-highest-ranked $(matches)
|
| 646 |
+
: $(match-ranks) ] ;
|
| 647 |
+
if $(best[2])
|
| 648 |
+
{
|
| 649 |
+
errors.error "Ambiguous key $(properties:J= :E=)" ;
|
| 650 |
+
}
|
| 651 |
+
local original = $(self.value.$(best)) ;
|
| 652 |
+
if $(value)
|
| 653 |
+
{
|
| 654 |
+
self.value.$(best) = $(value) ;
|
| 655 |
+
}
|
| 656 |
+
return $(original) ;
|
| 657 |
+
}
|
| 658 |
+
}
|
| 659 |
+
|
| 660 |
+
|
| 661 |
+
rule __test__ ( )
|
| 662 |
+
{
|
| 663 |
+
import assert ;
|
| 664 |
+
import "class" : new ;
|
| 665 |
+
import errors : try catch ;
|
| 666 |
+
import feature ;
|
| 667 |
+
|
| 668 |
+
# Local rules must be explicitly re-imported.
|
| 669 |
+
import property : path-order abbreviate-dashed ;
|
| 670 |
+
|
| 671 |
+
feature.prepare-test property-test-temp ;
|
| 672 |
+
|
| 673 |
+
feature.feature toolset : gcc : implicit symmetric ;
|
| 674 |
+
feature.subfeature toolset gcc : version : 2.95.2 2.95.3 2.95.4 3.0 3.0.1
|
| 675 |
+
3.0.2 : optional ;
|
| 676 |
+
feature.feature define : : free ;
|
| 677 |
+
feature.feature runtime-link : dynamic static : symmetric link-incompatible ;
|
| 678 |
+
feature.feature optimization : on off ;
|
| 679 |
+
feature.feature variant : debug release : implicit composite symmetric ;
|
| 680 |
+
feature.feature rtti : on off : link-incompatible ;
|
| 681 |
+
|
| 682 |
+
feature.compose <variant>debug : <define>_DEBUG <optimization>off ;
|
| 683 |
+
feature.compose <variant>release : <define>NDEBUG <optimization>on ;
|
| 684 |
+
|
| 685 |
+
validate <toolset>gcc <toolset>gcc-3.0.1 : $(test-space) ;
|
| 686 |
+
|
| 687 |
+
assert.true path-order $(test-space) debug <define>foo ;
|
| 688 |
+
assert.false path-order $(test-space) <define>foo debug ;
|
| 689 |
+
assert.true path-order $(test-space) gcc debug ;
|
| 690 |
+
assert.false path-order $(test-space) debug gcc ;
|
| 691 |
+
assert.true path-order $(test-space) <optimization>on <rtti>on ;
|
| 692 |
+
assert.false path-order $(test-space) <rtti>on <optimization>on ;
|
| 693 |
+
|
| 694 |
+
assert.result-set-equal <toolset>gcc <rtti>off <define>FOO
|
| 695 |
+
: refine <toolset>gcc <rtti>off
|
| 696 |
+
: <define>FOO
|
| 697 |
+
: $(test-space) ;
|
| 698 |
+
|
| 699 |
+
assert.result-set-equal <toolset>gcc <optimization>on
|
| 700 |
+
: refine <toolset>gcc <optimization>off
|
| 701 |
+
: <optimization>on
|
| 702 |
+
: $(test-space) ;
|
| 703 |
+
|
| 704 |
+
assert.result-set-equal <toolset>gcc <rtti>off
|
| 705 |
+
: refine <toolset>gcc : <rtti>off : $(test-space) ;
|
| 706 |
+
|
| 707 |
+
assert.result-set-equal <toolset>gcc <rtti>off <rtti>off:<define>FOO
|
| 708 |
+
: refine <toolset>gcc : <rtti>off <rtti>off:<define>FOO
|
| 709 |
+
: $(test-space) ;
|
| 710 |
+
|
| 711 |
+
assert.result-set-equal <toolset>gcc:<define>foo <toolset>gcc:<define>bar
|
| 712 |
+
: refine <toolset>gcc:<define>foo : <toolset>gcc:<define>bar
|
| 713 |
+
: $(test-space) ;
|
| 714 |
+
|
| 715 |
+
assert.result <define>MY_RELEASE
|
| 716 |
+
: evaluate-conditionals-in-context
|
| 717 |
+
<variant>release,<rtti>off:<define>MY_RELEASE
|
| 718 |
+
: <toolset>gcc <variant>release <rtti>off ;
|
| 719 |
+
|
| 720 |
+
assert.result debug
|
| 721 |
+
: as-path <optimization>off <variant>debug
|
| 722 |
+
: $(test-space) ;
|
| 723 |
+
|
| 724 |
+
assert.result gcc/debug/rtti-off
|
| 725 |
+
: as-path <toolset>gcc <optimization>off <rtti>off <variant>debug
|
| 726 |
+
: $(test-space) ;
|
| 727 |
+
|
| 728 |
+
assert.result optmz-off : abbreviate-dashed optimization-off ;
|
| 729 |
+
assert.result rntm-lnk-sttc : abbreviate-dashed runtime-link-static ;
|
| 730 |
+
|
| 731 |
+
try ;
|
| 732 |
+
validate <feature>value : $(test-space) ;
|
| 733 |
+
catch "Invalid property '<feature>value': unknown feature 'feature'." ;
|
| 734 |
+
|
| 735 |
+
try ;
|
| 736 |
+
validate <rtti>default : $(test-space) ;
|
| 737 |
+
catch \"default\" is not a known value of feature <rtti> ;
|
| 738 |
+
|
| 739 |
+
validate <define>WHATEVER : $(test-space) ;
|
| 740 |
+
|
| 741 |
+
try ;
|
| 742 |
+
validate <rtti> : $(test-space) ;
|
| 743 |
+
catch "Invalid property '<rtti>': No value specified for feature 'rtti'." ;
|
| 744 |
+
|
| 745 |
+
try ;
|
| 746 |
+
validate value : $(test-space) ;
|
| 747 |
+
catch "value" is not a value of an implicit feature ;
|
| 748 |
+
|
| 749 |
+
assert.result-set-equal <rtti>on
|
| 750 |
+
: remove free implicit : <toolset>gcc <define>foo <rtti>on : $(test-space) ;
|
| 751 |
+
|
| 752 |
+
assert.result-set-equal <include>a
|
| 753 |
+
: select include : <include>a <toolset>gcc ;
|
| 754 |
+
|
| 755 |
+
assert.result-set-equal <include>a
|
| 756 |
+
: select include bar : <include>a <toolset>gcc ;
|
| 757 |
+
|
| 758 |
+
assert.result-set-equal <include>a <toolset>gcc
|
| 759 |
+
: select include <bar> <toolset> : <include>a <toolset>gcc ;
|
| 760 |
+
|
| 761 |
+
assert.result-set-equal <toolset>kylix <include>a
|
| 762 |
+
: change <toolset>gcc <include>a : <toolset> kylix ;
|
| 763 |
+
|
| 764 |
+
pm = [ new property-map ] ;
|
| 765 |
+
$(pm).insert <toolset>gcc : o ;
|
| 766 |
+
$(pm).insert <toolset>gcc <os>NT : obj ;
|
| 767 |
+
$(pm).insert <toolset>gcc <os>CYGWIN : obj ;
|
| 768 |
+
|
| 769 |
+
assert.equal o : [ $(pm).find <toolset>gcc ] ;
|
| 770 |
+
|
| 771 |
+
assert.equal obj : [ $(pm).find <toolset>gcc <os>NT ] ;
|
| 772 |
+
|
| 773 |
+
try ;
|
| 774 |
+
$(pm).find <toolset>gcc <os>NT <os>CYGWIN ;
|
| 775 |
+
catch "Ambiguous key <toolset>gcc <os>NT <os>CYGWIN" ;
|
| 776 |
+
|
| 777 |
+
# Test ordinary properties.
|
| 778 |
+
assert.result : split-conditional <toolset>gcc ;
|
| 779 |
+
|
| 780 |
+
# Test properties with ":".
|
| 781 |
+
assert.result : split-conditional <define>FOO=A::B ;
|
| 782 |
+
|
| 783 |
+
# Test conditional feature.
|
| 784 |
+
assert.result-set-equal <toolset>gcc,<toolset-gcc:version>3.0 <define>FOO
|
| 785 |
+
: split-conditional <toolset>gcc,<toolset-gcc:version>3.0:<define>FOO ;
|
| 786 |
+
|
| 787 |
+
feature.finish-test property-test-temp ;
|
| 788 |
+
}
|
mosesdecoder/jam-files/boost-build/build/scanner.jam
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2003 Dave Abrahams
|
| 2 |
+
# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
|
| 3 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 4 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 5 |
+
|
| 6 |
+
# Implements scanners: objects that compute implicit dependencies for
|
| 7 |
+
# files, such as includes in C++.
|
| 8 |
+
#
|
| 9 |
+
# Scanner has a regular expression used to find dependencies, some
|
| 10 |
+
# data needed to interpret those dependencies (for example, include
|
| 11 |
+
# paths), and a code which actually established needed relationship
|
| 12 |
+
# between actual jam targets.
|
| 13 |
+
#
|
| 14 |
+
# Scanner objects are created by actions, when they try to actualize
|
| 15 |
+
# virtual targets, passed to 'virtual-target.actualize' method and are
|
| 16 |
+
# then associated with actual targets. It is possible to use
|
| 17 |
+
# several scanners for a virtual-target. For example, a single source
|
| 18 |
+
# might be used by to compile actions, with different include paths.
|
| 19 |
+
# In this case, two different actual targets will be created, each
|
| 20 |
+
# having scanner of its own.
|
| 21 |
+
#
|
| 22 |
+
# Typically, scanners are created from target type and action's
|
| 23 |
+
# properties, using the rule 'get' in this module. Directly creating
|
| 24 |
+
# scanners is not recommended, because it might create many equvivalent
|
| 25 |
+
# but different instances, and lead in unneeded duplication of
|
| 26 |
+
# actual targets. However, actions can also create scanners in a special
|
| 27 |
+
# way, instead of relying on just target type.
|
| 28 |
+
|
| 29 |
+
import "class" : new ;
|
| 30 |
+
import property virtual-target property-set ;
|
| 31 |
+
import errors : error ;
|
| 32 |
+
|
| 33 |
+
# Base scanner class.
|
| 34 |
+
class scanner
|
| 35 |
+
{
|
| 36 |
+
rule __init__ ( )
|
| 37 |
+
{
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
# Returns a pattern to use for scanning
|
| 41 |
+
rule pattern ( )
|
| 42 |
+
{
|
| 43 |
+
error "method must be overriden" ;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
# Establish necessary relationship between targets,
|
| 47 |
+
# given actual target beeing scanned, and a list of
|
| 48 |
+
# pattern matches in that file.
|
| 49 |
+
rule process ( target : matches * )
|
| 50 |
+
{
|
| 51 |
+
error "method must be overriden" ;
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
# Registers a new generator class, specifying a set of
|
| 56 |
+
# properties relevant to this scanner. Ctor for that class
|
| 57 |
+
# should have one parameter: list of properties.
|
| 58 |
+
rule register ( scanner-class : relevant-properties * )
|
| 59 |
+
{
|
| 60 |
+
.registered += $(scanner-class) ;
|
| 61 |
+
.relevant-properties.$(scanner-class) = $(relevant-properties) ;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
# Common scanner class, which can be used when there's only one
|
| 65 |
+
# kind of includes (unlike C, where "" and <> includes have different
|
| 66 |
+
# search paths).
|
| 67 |
+
class common-scanner : scanner
|
| 68 |
+
{
|
| 69 |
+
import scanner ;
|
| 70 |
+
rule __init__ ( includes * )
|
| 71 |
+
{
|
| 72 |
+
scanner.__init__ ;
|
| 73 |
+
self.includes = $(includes) ;
|
| 74 |
+
}
|
| 75 |
+
|
| 76 |
+
rule process ( target : matches * : binding )
|
| 77 |
+
{
|
| 78 |
+
local target_path = [ NORMALIZE_PATH $(binding:D) ] ;
|
| 79 |
+
|
| 80 |
+
NOCARE $(matches) ;
|
| 81 |
+
INCLUDES $(target) : $(matches) ;
|
| 82 |
+
SEARCH on $(matches) = $(target_path) $(self.includes:G=) ;
|
| 83 |
+
ISFILE $(matches) ;
|
| 84 |
+
|
| 85 |
+
scanner.propagate $(__name__) : $(matches) : $(target) ;
|
| 86 |
+
}
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
|
| 90 |
+
# Returns an instance of previously registered scanner,
|
| 91 |
+
# with the specified properties.
|
| 92 |
+
rule get ( scanner-class : property-set )
|
| 93 |
+
{
|
| 94 |
+
if ! $(scanner-class) in $(.registered)
|
| 95 |
+
{
|
| 96 |
+
error "attempt to get unregisted scanner" ;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
local r = $(.rv-cache.$(property-set)) ;
|
| 100 |
+
if ! $(r)
|
| 101 |
+
{
|
| 102 |
+
r = [ property-set.create
|
| 103 |
+
[ property.select $(.relevant-properties.$(scanner-class)) :
|
| 104 |
+
[ $(property-set).raw ] ] ] ;
|
| 105 |
+
.rv-cache.$(property-set) = $(r) ;
|
| 106 |
+
}
|
| 107 |
+
|
| 108 |
+
if ! $(scanner.$(scanner-class).$(r:J=-))
|
| 109 |
+
{
|
| 110 |
+
scanner.$(scanner-class).$(r:J=-) = [ new $(scanner-class) [ $(r).raw ] ] ;
|
| 111 |
+
}
|
| 112 |
+
return $(scanner.$(scanner-class).$(r:J=-)) ;
|
| 113 |
+
}
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
# Installs the specified scanner on actual target 'target'.
|
| 117 |
+
rule install ( scanner : target
|
| 118 |
+
vtarget # virtual target from which 'target' was actualized
|
| 119 |
+
)
|
| 120 |
+
{
|
| 121 |
+
HDRSCAN on $(target) = [ $(scanner).pattern ] ;
|
| 122 |
+
SCANNER on $(target) = $(scanner) ;
|
| 123 |
+
HDRRULE on $(target) = scanner.hdrrule ;
|
| 124 |
+
|
| 125 |
+
# scanner reflects difference in properties affecting
|
| 126 |
+
# binding of 'target', which will be known when processing
|
| 127 |
+
# includes for it, will give information on how to
|
| 128 |
+
# interpret quoted includes.
|
| 129 |
+
HDRGRIST on $(target) = $(scanner) ;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
# Propagate scanner setting from 'including-target' to 'targets'.
|
| 133 |
+
rule propagate ( scanner : targets * : including-target )
|
| 134 |
+
{
|
| 135 |
+
HDRSCAN on $(targets) = [ on $(including-target) return $(HDRSCAN) ] ;
|
| 136 |
+
SCANNER on $(targets) = $(scanner) ;
|
| 137 |
+
HDRRULE on $(targets) = scanner.hdrrule ;
|
| 138 |
+
HDRGRIST on $(targets) = [ on $(including-target) return $(HDRGRIST) ] ;
|
| 139 |
+
}
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
rule hdrrule ( target : matches * : binding )
|
| 143 |
+
{
|
| 144 |
+
local scanner = [ on $(target) return $(SCANNER) ] ;
|
| 145 |
+
$(scanner).process $(target) : $(matches) : $(binding) ;
|
| 146 |
+
}
|
| 147 |
+
# hdrrule must be available at global scope so that it can be invoked
|
| 148 |
+
# by header scanning
|
| 149 |
+
IMPORT scanner : hdrrule : : scanner.hdrrule ;
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
|
| 153 |
+
|
mosesdecoder/jam-files/boost-build/build/toolset.jam
ADDED
|
@@ -0,0 +1,575 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2003 Dave Abrahams
|
| 2 |
+
# Copyright 2005 Rene Rivera
|
| 3 |
+
# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
|
| 4 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 5 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 6 |
+
|
| 7 |
+
# Support for toolset definition.
|
| 8 |
+
|
| 9 |
+
import errors ;
|
| 10 |
+
import feature ;
|
| 11 |
+
import generators ;
|
| 12 |
+
import numbers ;
|
| 13 |
+
import path ;
|
| 14 |
+
import property ;
|
| 15 |
+
import regex ;
|
| 16 |
+
import sequence ;
|
| 17 |
+
import set ;
|
| 18 |
+
import property-set ;
|
| 19 |
+
|
| 20 |
+
|
| 21 |
+
.flag-no = 1 ;
|
| 22 |
+
|
| 23 |
+
.ignore-requirements = ;
|
| 24 |
+
|
| 25 |
+
# This is used only for testing, to make sure we do not get random extra
|
| 26 |
+
# elements in paths.
|
| 27 |
+
if --ignore-toolset-requirements in [ modules.peek : ARGV ]
|
| 28 |
+
{
|
| 29 |
+
.ignore-requirements = 1 ;
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
# Initializes an additional toolset-like module. First load the 'toolset-module'
|
| 34 |
+
# and then calls its 'init' rule with trailing arguments.
|
| 35 |
+
#
|
| 36 |
+
rule using ( toolset-module : * )
|
| 37 |
+
{
|
| 38 |
+
import $(toolset-module) ;
|
| 39 |
+
$(toolset-module).init $(2) : $(3) : $(4) : $(5) : $(6) : $(7) : $(8) : $(9) ;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
|
| 43 |
+
# Expands subfeatures in each property sets, e.g. '<toolset>gcc-3.2' will be
|
| 44 |
+
# converted to '<toolset>gcc/<toolset-version>3.2'.
|
| 45 |
+
#
|
| 46 |
+
local rule normalize-condition ( property-sets * )
|
| 47 |
+
{
|
| 48 |
+
local result ;
|
| 49 |
+
for local p in $(property-sets)
|
| 50 |
+
{
|
| 51 |
+
local split = [ feature.split $(p) ] ;
|
| 52 |
+
local expanded = [ feature.expand-subfeatures [ feature.split $(p) ] ] ;
|
| 53 |
+
result += $(expanded:J=/) ;
|
| 54 |
+
}
|
| 55 |
+
return $(result) ;
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
|
| 59 |
+
# Specifies if the 'flags' rule should check that the invoking module is the
|
| 60 |
+
# same as the module we are setting the flag for. 'v' can be either 'checked' or
|
| 61 |
+
# 'unchecked'. Subsequent call to 'pop-checking-for-flags-module' will restore
|
| 62 |
+
# the setting that was in effect before calling this rule.
|
| 63 |
+
#
|
| 64 |
+
rule push-checking-for-flags-module ( v )
|
| 65 |
+
{
|
| 66 |
+
.flags-module-checking = $(v) $(.flags-module-checking) ;
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
rule pop-checking-for-flags-module ( )
|
| 70 |
+
{
|
| 71 |
+
.flags-module-checking = $(.flags-module-checking[2-]) ;
|
| 72 |
+
}
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
# Specifies the flags (variables) that must be set on targets under certain
|
| 76 |
+
# conditions, described by arguments.
|
| 77 |
+
#
|
| 78 |
+
rule flags (
|
| 79 |
+
rule-or-module # If contains a dot, should be a rule name. The flags will
|
| 80 |
+
# be applied when that rule is used to set up build
|
| 81 |
+
# actions.
|
| 82 |
+
#
|
| 83 |
+
# If does not contain dot, should be a module name. The
|
| 84 |
+
# flag will be applied for all rules in that module. If
|
| 85 |
+
# module for rule is different from the calling module, an
|
| 86 |
+
# error is issued.
|
| 87 |
+
|
| 88 |
+
variable-name # Variable that should be set on target.
|
| 89 |
+
condition * : # A condition when this flag should be applied. Should be a
|
| 90 |
+
# set of property sets. If one of those property sets is
|
| 91 |
+
# contained in the build properties, the flag will be used.
|
| 92 |
+
# Implied values are not allowed: "<toolset>gcc" should be
|
| 93 |
+
# used, not just "gcc". Subfeatures, like in
|
| 94 |
+
# "<toolset>gcc-3.2" are allowed. If left empty, the flag
|
| 95 |
+
# will be used unconditionally.
|
| 96 |
+
#
|
| 97 |
+
# Propery sets may use value-less properties ('<a>' vs.
|
| 98 |
+
# '<a>value') to match absent properties. This allows to
|
| 99 |
+
# separately match:
|
| 100 |
+
#
|
| 101 |
+
# <architecture>/<address-model>64
|
| 102 |
+
# <architecture>ia64/<address-model>
|
| 103 |
+
#
|
| 104 |
+
# Where both features are optional. Without this syntax
|
| 105 |
+
# we would be forced to define "default" values.
|
| 106 |
+
|
| 107 |
+
values * : # The value to add to variable. If <feature> is specified,
|
| 108 |
+
# then the value of 'feature' will be added.
|
| 109 |
+
unchecked ? # If value 'unchecked' is passed, will not test that flags
|
| 110 |
+
# are set for the calling module.
|
| 111 |
+
: hack-hack ? # For
|
| 112 |
+
# flags rule OPTIONS <cxx-abi> : -model ansi
|
| 113 |
+
# Treat <cxx-abi> as condition
|
| 114 |
+
# FIXME: ugly hack.
|
| 115 |
+
)
|
| 116 |
+
{
|
| 117 |
+
local caller = [ CALLER_MODULE ] ;
|
| 118 |
+
if ! [ MATCH ".*([.]).*" : $(rule-or-module) ]
|
| 119 |
+
&& [ MATCH "(Jamfile<.*)" : $(caller) ]
|
| 120 |
+
{
|
| 121 |
+
# Unqualified rule name, used inside Jamfile. Most likely used with
|
| 122 |
+
# 'make' or 'notfile' rules. This prevents setting flags on the entire
|
| 123 |
+
# Jamfile module (this will be considered as rule), but who cares?
|
| 124 |
+
# Probably, 'flags' rule should be split into 'flags' and
|
| 125 |
+
# 'flags-on-module'.
|
| 126 |
+
rule-or-module = $(caller).$(rule-or-module) ;
|
| 127 |
+
}
|
| 128 |
+
else
|
| 129 |
+
{
|
| 130 |
+
local module_ = [ MATCH "([^.]*).*" : $(rule-or-module) ] ;
|
| 131 |
+
if $(unchecked) != unchecked
|
| 132 |
+
&& $(.flags-module-checking[1]) != unchecked
|
| 133 |
+
&& $(module_) != $(caller)
|
| 134 |
+
{
|
| 135 |
+
errors.error "Module $(caller) attempted to set flags for module $(module_)" ;
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
if $(condition) && ! $(condition:G=) && ! $(hack-hack)
|
| 140 |
+
{
|
| 141 |
+
# We have condition in the form '<feature>', that is, without value.
|
| 142 |
+
# That is an older syntax:
|
| 143 |
+
# flags gcc.link RPATH <dll-path> ;
|
| 144 |
+
# for compatibility, convert it to
|
| 145 |
+
# flags gcc.link RPATH : <dll-path> ;
|
| 146 |
+
values = $(condition) ;
|
| 147 |
+
condition = ;
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
if $(condition)
|
| 151 |
+
{
|
| 152 |
+
property.validate-property-sets $(condition) ;
|
| 153 |
+
condition = [ normalize-condition $(condition) ] ;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
add-flag $(rule-or-module) : $(variable-name) : $(condition) : $(values) ;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
# Adds a new flag setting with the specified values. Does no checking.
|
| 161 |
+
#
|
| 162 |
+
local rule add-flag ( rule-or-module : variable-name : condition * : values * )
|
| 163 |
+
{
|
| 164 |
+
.$(rule-or-module).flags += $(.flag-no) ;
|
| 165 |
+
|
| 166 |
+
# Store all flags for a module.
|
| 167 |
+
local module_ = [ MATCH "([^.]*).*" : $(rule-or-module) ] ;
|
| 168 |
+
.module-flags.$(module_) += $(.flag-no) ;
|
| 169 |
+
# Store flag-no -> rule-or-module mapping.
|
| 170 |
+
.rule-or-module.$(.flag-no) = $(rule-or-module) ;
|
| 171 |
+
|
| 172 |
+
.$(rule-or-module).variable.$(.flag-no) += $(variable-name) ;
|
| 173 |
+
.$(rule-or-module).values.$(.flag-no) += $(values) ;
|
| 174 |
+
.$(rule-or-module).condition.$(.flag-no) += $(condition) ;
|
| 175 |
+
|
| 176 |
+
.flag-no = [ numbers.increment $(.flag-no) ] ;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
# Returns the first element of 'property-sets' which is a subset of
|
| 181 |
+
# 'properties' or an empty list if no such element exists.
|
| 182 |
+
#
|
| 183 |
+
rule find-property-subset ( property-sets * : properties * )
|
| 184 |
+
{
|
| 185 |
+
# Cut property values off.
|
| 186 |
+
local prop-keys = $(properties:G) ;
|
| 187 |
+
|
| 188 |
+
local result ;
|
| 189 |
+
for local s in $(property-sets)
|
| 190 |
+
{
|
| 191 |
+
if ! $(result)
|
| 192 |
+
{
|
| 193 |
+
# Handle value-less properties like '<architecture>' (compare with
|
| 194 |
+
# '<architecture>x86').
|
| 195 |
+
|
| 196 |
+
local set = [ feature.split $(s) ] ;
|
| 197 |
+
|
| 198 |
+
# Find the set of features that
|
| 199 |
+
# - have no property specified in required property set
|
| 200 |
+
# - are omitted in the build property set.
|
| 201 |
+
local default-props ;
|
| 202 |
+
for local i in $(set)
|
| 203 |
+
{
|
| 204 |
+
# If $(i) is a value-less property it should match default value
|
| 205 |
+
# of an optional property. See the first line in the example
|
| 206 |
+
# below:
|
| 207 |
+
#
|
| 208 |
+
# property set properties result
|
| 209 |
+
# <a> <b>foo <b>foo match
|
| 210 |
+
# <a> <b>foo <a>foo <b>foo no match
|
| 211 |
+
# <a>foo <b>foo <b>foo no match
|
| 212 |
+
# <a>foo <b>foo <a>foo <b>foo match
|
| 213 |
+
if ! ( $(i:G=) || ( $(i:G) in $(prop-keys) ) )
|
| 214 |
+
{
|
| 215 |
+
default-props += $(i) ;
|
| 216 |
+
}
|
| 217 |
+
}
|
| 218 |
+
|
| 219 |
+
if $(set) in $(properties) $(default-props)
|
| 220 |
+
{
|
| 221 |
+
result = $(s) ;
|
| 222 |
+
}
|
| 223 |
+
}
|
| 224 |
+
}
|
| 225 |
+
return $(result) ;
|
| 226 |
+
}
|
| 227 |
+
|
| 228 |
+
|
| 229 |
+
# Returns a value to be added to some flag for some target based on the flag's
|
| 230 |
+
# value definition and the given target's property set.
|
| 231 |
+
#
|
| 232 |
+
rule handle-flag-value ( value * : properties * )
|
| 233 |
+
{
|
| 234 |
+
local result ;
|
| 235 |
+
if $(value:G)
|
| 236 |
+
{
|
| 237 |
+
local matches = [ property.select $(value) : $(properties) ] ;
|
| 238 |
+
for local p in $(matches)
|
| 239 |
+
{
|
| 240 |
+
local att = [ feature.attributes $(p:G) ] ;
|
| 241 |
+
if dependency in $(att)
|
| 242 |
+
{
|
| 243 |
+
# The value of a dependency feature is a target and needs to be
|
| 244 |
+
# actualized.
|
| 245 |
+
result += [ $(p:G=).actualize ] ;
|
| 246 |
+
}
|
| 247 |
+
else if path in $(att) || free in $(att)
|
| 248 |
+
{
|
| 249 |
+
local values ;
|
| 250 |
+
# Treat features with && in the value specially -- each
|
| 251 |
+
# &&-separated element is considered a separate value. This is
|
| 252 |
+
# needed to handle searched libraries or include paths, which
|
| 253 |
+
# may need to be in a specific order.
|
| 254 |
+
if ! [ MATCH (&&) : $(p:G=) ]
|
| 255 |
+
{
|
| 256 |
+
values = $(p:G=) ;
|
| 257 |
+
}
|
| 258 |
+
else
|
| 259 |
+
{
|
| 260 |
+
values = [ regex.split $(p:G=) "&&" ] ;
|
| 261 |
+
}
|
| 262 |
+
if path in $(att)
|
| 263 |
+
{
|
| 264 |
+
result += [ sequence.transform path.native : $(values) ] ;
|
| 265 |
+
}
|
| 266 |
+
else
|
| 267 |
+
{
|
| 268 |
+
result += $(values) ;
|
| 269 |
+
}
|
| 270 |
+
}
|
| 271 |
+
else
|
| 272 |
+
{
|
| 273 |
+
result += $(p:G=) ;
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
else
|
| 278 |
+
{
|
| 279 |
+
result += $(value) ;
|
| 280 |
+
}
|
| 281 |
+
return $(result) ;
|
| 282 |
+
}
|
| 283 |
+
|
| 284 |
+
|
| 285 |
+
# Given a rule name and a property set, returns a list of interleaved variables
|
| 286 |
+
# names and values which must be set on targets for that rule/property-set
|
| 287 |
+
# combination.
|
| 288 |
+
#
|
| 289 |
+
rule set-target-variables-aux ( rule-or-module : property-set )
|
| 290 |
+
{
|
| 291 |
+
local result ;
|
| 292 |
+
properties = [ $(property-set).raw ] ;
|
| 293 |
+
for local f in $(.$(rule-or-module).flags)
|
| 294 |
+
{
|
| 295 |
+
local variable = $(.$(rule-or-module).variable.$(f)) ;
|
| 296 |
+
local condition = $(.$(rule-or-module).condition.$(f)) ;
|
| 297 |
+
local values = $(.$(rule-or-module).values.$(f)) ;
|
| 298 |
+
|
| 299 |
+
if ! $(condition) ||
|
| 300 |
+
[ find-property-subset $(condition) : $(properties) ]
|
| 301 |
+
{
|
| 302 |
+
local processed ;
|
| 303 |
+
for local v in $(values)
|
| 304 |
+
{
|
| 305 |
+
# The value might be <feature-name> so needs special treatment.
|
| 306 |
+
processed += [ handle-flag-value $(v) : $(properties) ] ;
|
| 307 |
+
}
|
| 308 |
+
for local r in $(processed)
|
| 309 |
+
{
|
| 310 |
+
result += $(variable) $(r) ;
|
| 311 |
+
}
|
| 312 |
+
}
|
| 313 |
+
}
|
| 314 |
+
|
| 315 |
+
# Strip away last dot separated part and recurse.
|
| 316 |
+
local next = [ MATCH ^(.+)\\.([^\\.])* : $(rule-or-module) ] ;
|
| 317 |
+
if $(next)
|
| 318 |
+
{
|
| 319 |
+
result += [ set-target-variables-aux $(next[1]) : $(property-set) ] ;
|
| 320 |
+
}
|
| 321 |
+
return $(result) ;
|
| 322 |
+
}
|
| 323 |
+
|
| 324 |
+
rule relevant-features ( rule-or-module )
|
| 325 |
+
{
|
| 326 |
+
local result ;
|
| 327 |
+
if ! $(.relevant-features.$(rule-or-module))
|
| 328 |
+
{
|
| 329 |
+
for local f in $(.$(rule-or-module).flags)
|
| 330 |
+
{
|
| 331 |
+
local condition = $(.$(rule-or-module).condition.$(f)) ;
|
| 332 |
+
local values = $(.$(rule-or-module).values.$(f)) ;
|
| 333 |
+
|
| 334 |
+
for local c in $(condition)
|
| 335 |
+
{
|
| 336 |
+
for local p in [ feature.split $(c) ]
|
| 337 |
+
{
|
| 338 |
+
if $(p:G)
|
| 339 |
+
{
|
| 340 |
+
result += $(p:G) ;
|
| 341 |
+
}
|
| 342 |
+
else
|
| 343 |
+
{
|
| 344 |
+
local temp = [ feature.expand-subfeatures $(p) ] ;
|
| 345 |
+
result += $(temp:G) ;
|
| 346 |
+
}
|
| 347 |
+
}
|
| 348 |
+
}
|
| 349 |
+
|
| 350 |
+
for local v in $(values)
|
| 351 |
+
{
|
| 352 |
+
if $(v:G)
|
| 353 |
+
{
|
| 354 |
+
result += $(v:G) ;
|
| 355 |
+
}
|
| 356 |
+
}
|
| 357 |
+
}
|
| 358 |
+
|
| 359 |
+
# Strip away last dot separated part and recurse.
|
| 360 |
+
local next = [ MATCH ^(.+)\\.([^\\.])* : $(rule-or-module) ] ;
|
| 361 |
+
if $(next)
|
| 362 |
+
{
|
| 363 |
+
result += [ relevant-features $(next[1]) ] ;
|
| 364 |
+
}
|
| 365 |
+
result = [ sequence.unique $(result) ] ;
|
| 366 |
+
if $(result[1]) = ""
|
| 367 |
+
{
|
| 368 |
+
result = $(result) ;
|
| 369 |
+
}
|
| 370 |
+
.relevant-features.$(rule-or-module) = $(result) ;
|
| 371 |
+
return $(result) ;
|
| 372 |
+
}
|
| 373 |
+
else
|
| 374 |
+
{
|
| 375 |
+
return $(.relevant-features.$(rule-or-module)) ;
|
| 376 |
+
}
|
| 377 |
+
}
|
| 378 |
+
|
| 379 |
+
rule filter-property-set ( rule-or-module : property-set )
|
| 380 |
+
{
|
| 381 |
+
if ! $(.filtered.property-set.$(rule-or-module).$(property-set))
|
| 382 |
+
{
|
| 383 |
+
local relevant = [ relevant-features $(rule-or-module) ] ;
|
| 384 |
+
local result ;
|
| 385 |
+
for local p in [ $(property-set).raw ]
|
| 386 |
+
{
|
| 387 |
+
if $(p:G) in $(relevant)
|
| 388 |
+
{
|
| 389 |
+
result += $(p) ;
|
| 390 |
+
}
|
| 391 |
+
}
|
| 392 |
+
.filtered.property-set.$(rule-or-module).$(property-set) = [ property-set.create $(result) ] ;
|
| 393 |
+
}
|
| 394 |
+
return $(.filtered.property-set.$(rule-or-module).$(property-set)) ;
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
rule set-target-variables ( rule-or-module targets + : property-set )
|
| 398 |
+
{
|
| 399 |
+
property-set = [ filter-property-set $(rule-or-module) : $(property-set) ] ;
|
| 400 |
+
local key = $(rule-or-module).$(property-set) ;
|
| 401 |
+
local settings = $(.stv.$(key)) ;
|
| 402 |
+
if ! $(settings)
|
| 403 |
+
{
|
| 404 |
+
settings = [ set-target-variables-aux $(rule-or-module) :
|
| 405 |
+
$(property-set) ] ;
|
| 406 |
+
|
| 407 |
+
if ! $(settings)
|
| 408 |
+
{
|
| 409 |
+
settings = none ;
|
| 410 |
+
}
|
| 411 |
+
.stv.$(key) = $(settings) ;
|
| 412 |
+
}
|
| 413 |
+
|
| 414 |
+
if $(settings) != none
|
| 415 |
+
{
|
| 416 |
+
local var-name = ;
|
| 417 |
+
for local name-or-value in $(settings)
|
| 418 |
+
{
|
| 419 |
+
if $(var-name)
|
| 420 |
+
{
|
| 421 |
+
$(var-name) on $(targets) += $(name-or-value) ;
|
| 422 |
+
var-name = ;
|
| 423 |
+
}
|
| 424 |
+
else
|
| 425 |
+
{
|
| 426 |
+
var-name = $(name-or-value) ;
|
| 427 |
+
}
|
| 428 |
+
}
|
| 429 |
+
}
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
|
| 433 |
+
# Make toolset 'toolset', defined in a module of the same name, inherit from
|
| 434 |
+
# 'base'.
|
| 435 |
+
# 1. The 'init' rule from 'base' is imported into 'toolset' with full name.
|
| 436 |
+
# Another 'init' is called, which forwards to the base one.
|
| 437 |
+
# 2. All generators from 'base' are cloned. The ids are adjusted and <toolset>
|
| 438 |
+
# property in requires is adjusted too.
|
| 439 |
+
# 3. All flags are inherited.
|
| 440 |
+
# 4. All rules are imported.
|
| 441 |
+
#
|
| 442 |
+
rule inherit ( toolset : base )
|
| 443 |
+
{
|
| 444 |
+
import $(base) ;
|
| 445 |
+
inherit-generators $(toolset) : $(base) ;
|
| 446 |
+
inherit-flags $(toolset) : $(base) ;
|
| 447 |
+
inherit-rules $(toolset) : $(base) ;
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
|
| 451 |
+
rule inherit-generators ( toolset properties * : base : generators-to-ignore * )
|
| 452 |
+
{
|
| 453 |
+
properties ?= <toolset>$(toolset) ;
|
| 454 |
+
local base-generators = [ generators.generators-for-toolset $(base) ] ;
|
| 455 |
+
for local g in $(base-generators)
|
| 456 |
+
{
|
| 457 |
+
local id = [ $(g).id ] ;
|
| 458 |
+
|
| 459 |
+
if ! $(id) in $(generators-to-ignore)
|
| 460 |
+
{
|
| 461 |
+
# Some generator names have multiple periods in their name, so
|
| 462 |
+
# $(id:B=$(toolset)) does not generate the right new-id name. E.g.
|
| 463 |
+
# if id = gcc.compile.c++ then $(id:B=darwin) = darwin.c++, which is
|
| 464 |
+
# not what we want. Manually parse the base and suffix. If there is
|
| 465 |
+
# a better way to do this, I would love to see it. See also the
|
| 466 |
+
# register() rule in the generators module.
|
| 467 |
+
local base = $(id) ;
|
| 468 |
+
local suffix = "" ;
|
| 469 |
+
while $(base:S)
|
| 470 |
+
{
|
| 471 |
+
suffix = $(base:S)$(suffix) ;
|
| 472 |
+
base = $(base:B) ;
|
| 473 |
+
}
|
| 474 |
+
local new-id = $(toolset)$(suffix) ;
|
| 475 |
+
|
| 476 |
+
generators.register [ $(g).clone $(new-id) : $(properties) ] ;
|
| 477 |
+
}
|
| 478 |
+
}
|
| 479 |
+
}
|
| 480 |
+
|
| 481 |
+
|
| 482 |
+
# Brings all flag definitions from the 'base' toolset into the 'toolset'
|
| 483 |
+
# toolset. Flag definitions whose conditions make use of properties in
|
| 484 |
+
# 'prohibited-properties' are ignored. Do not confuse property and feature, for
|
| 485 |
+
# example <debug-symbols>on and <debug-symbols>off, so blocking one of them does
|
| 486 |
+
# not block the other one.
|
| 487 |
+
#
|
| 488 |
+
# The flag conditions are not altered at all, so if a condition includes a name,
|
| 489 |
+
# or version of a base toolset, it will not ever match the inheriting toolset.
|
| 490 |
+
# When such flag settings must be inherited, define a rule in base toolset
|
| 491 |
+
# module and call it as needed.
|
| 492 |
+
#
|
| 493 |
+
rule inherit-flags ( toolset : base : prohibited-properties * : prohibited-vars * )
|
| 494 |
+
{
|
| 495 |
+
for local f in $(.module-flags.$(base))
|
| 496 |
+
{
|
| 497 |
+
local rule-or-module = $(.rule-or-module.$(f)) ;
|
| 498 |
+
if ( [ set.difference
|
| 499 |
+
$(.$(rule-or-module).condition.$(f)) :
|
| 500 |
+
$(prohibited-properties) ]
|
| 501 |
+
|| ! $(.$(rule-or-module).condition.$(f))
|
| 502 |
+
) && ( ! $(.$(rule-or-module).variable.$(f)) in $(prohibited-vars) )
|
| 503 |
+
{
|
| 504 |
+
local rule_ = [ MATCH "[^.]*\.(.*)" : $(rule-or-module) ] ;
|
| 505 |
+
local new-rule-or-module ;
|
| 506 |
+
if $(rule_)
|
| 507 |
+
{
|
| 508 |
+
new-rule-or-module = $(toolset).$(rule_) ;
|
| 509 |
+
}
|
| 510 |
+
else
|
| 511 |
+
{
|
| 512 |
+
new-rule-or-module = $(toolset) ;
|
| 513 |
+
}
|
| 514 |
+
|
| 515 |
+
add-flag
|
| 516 |
+
$(new-rule-or-module)
|
| 517 |
+
: $(.$(rule-or-module).variable.$(f))
|
| 518 |
+
: $(.$(rule-or-module).condition.$(f))
|
| 519 |
+
: $(.$(rule-or-module).values.$(f)) ;
|
| 520 |
+
}
|
| 521 |
+
}
|
| 522 |
+
}
|
| 523 |
+
|
| 524 |
+
|
| 525 |
+
rule inherit-rules ( toolset : base : localize ? )
|
| 526 |
+
{
|
| 527 |
+
# It appears that "action" creates a local rule.
|
| 528 |
+
local base-generators = [ generators.generators-for-toolset $(base) ] ;
|
| 529 |
+
local rules ;
|
| 530 |
+
for local g in $(base-generators)
|
| 531 |
+
{
|
| 532 |
+
rules += [ MATCH "[^.]*\.(.*)" : [ $(g).rule-name ] ] ;
|
| 533 |
+
}
|
| 534 |
+
rules = [ sequence.unique $(rules) ] ;
|
| 535 |
+
IMPORT $(base) : $(rules) : $(toolset) : $(rules) : $(localize) ;
|
| 536 |
+
IMPORT $(toolset) : $(rules) : : $(toolset).$(rules) ;
|
| 537 |
+
}
|
| 538 |
+
|
| 539 |
+
|
| 540 |
+
# Return the list of global 'toolset requirements'. Those requirements will be
|
| 541 |
+
# automatically added to the requirements of any main target.
|
| 542 |
+
#
|
| 543 |
+
rule requirements ( )
|
| 544 |
+
{
|
| 545 |
+
return $(.requirements) ;
|
| 546 |
+
}
|
| 547 |
+
|
| 548 |
+
|
| 549 |
+
# Adds elements to the list of global 'toolset requirements'. The requirements
|
| 550 |
+
# will be automatically added to the requirements for all main targets, as if
|
| 551 |
+
# they were specified literally. For best results, all requirements added should
|
| 552 |
+
# be conditional or indirect conditional.
|
| 553 |
+
#
|
| 554 |
+
rule add-requirements ( requirements * )
|
| 555 |
+
{
|
| 556 |
+
if ! $(.ignore-requirements)
|
| 557 |
+
{
|
| 558 |
+
.requirements += $(requirements) ;
|
| 559 |
+
}
|
| 560 |
+
}
|
| 561 |
+
|
| 562 |
+
|
| 563 |
+
rule __test__ ( )
|
| 564 |
+
{
|
| 565 |
+
import assert ;
|
| 566 |
+
local p = <b>0 <c>1 <d>2 <e>3 <f>4 ;
|
| 567 |
+
assert.result <c>1/<d>2/<e>3 : find-property-subset <c>1/<d>2/<e>3 <a>0/<b>0/<c>1 <d>2/<e>5 <a>9 : $(p) ;
|
| 568 |
+
assert.result : find-property-subset <a>0/<b>0/<c>9/<d>9/<e>5 <a>9 : $(p) ;
|
| 569 |
+
|
| 570 |
+
local p-set = <a>/<b> <a>0/<b> <a>/<b>1 <a>0/<b>1 ;
|
| 571 |
+
assert.result <a>/<b> : find-property-subset $(p-set) : ;
|
| 572 |
+
assert.result <a>0/<b> : find-property-subset $(p-set) : <a>0 <c>2 ;
|
| 573 |
+
assert.result <a>/<b>1 : find-property-subset $(p-set) : <b>1 <c>2 ;
|
| 574 |
+
assert.result <a>0/<b>1 : find-property-subset $(p-set) : <a>0 <b>1 ;
|
| 575 |
+
}
|
mosesdecoder/jam-files/boost-build/build/type.jam
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Copyright 2002, 2003 Dave Abrahams
|
| 2 |
+
# Copyright 2002, 2003, 2004, 2005, 2006 Vladimir Prus
|
| 3 |
+
# Distributed under the Boost Software License, Version 1.0.
|
| 4 |
+
# (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
|
| 5 |
+
|
| 6 |
+
# Deals with target type declaration and defines target class which supports
|
| 7 |
+
# typed targets.
|
| 8 |
+
|
| 9 |
+
import "class" : new ;
|
| 10 |
+
import errors ;
|
| 11 |
+
import feature ;
|
| 12 |
+
import generators : * ;
|
| 13 |
+
import project ;
|
| 14 |
+
import property ;
|
| 15 |
+
import scanner ;
|
| 16 |
+
import os ;
|
| 17 |
+
|
| 18 |
+
# The following import would create a circular dependency:
|
| 19 |
+
# project -> project-root -> builtin -> type -> targets -> project
|
| 20 |
+
# import targets ;
|
| 21 |
+
|
| 22 |
+
# The feature is optional so it would never get added implicitly. It is used
|
| 23 |
+
# only for internal purposes and in all cases we want to use it explicitly.
|
| 24 |
+
feature.feature target-type : : composite optional ;
|
| 25 |
+
|
| 26 |
+
feature.feature main-target-type : : optional incidental ;
|
| 27 |
+
feature.feature base-target-type : : composite optional free ;
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
# Registers a target type, possible derived from a 'base-type'. Providing a list
|
| 31 |
+
# of 'suffixes' here is a shortcut for separately calling the register-suffixes
|
| 32 |
+
# rule with the given suffixes and the set-generated-target-suffix rule with the
|
| 33 |
+
# first given suffix.
|
| 34 |
+
#
|
| 35 |
+
rule register ( type : suffixes * : base-type ? )
|
| 36 |
+
{
|
| 37 |
+
# Type names cannot contain hyphens, because when used as feature-values
|
| 38 |
+
# they would be interpreted as composite features which need to be
|
| 39 |
+
# decomposed.
|
| 40 |
+
switch $(type)
|
| 41 |
+
{
|
| 42 |
+
case *-* : errors.error "type name \"$(type)\" contains a hyphen" ;
|
| 43 |
+
}
|
| 44 |
+
|
| 45 |
+
if $(type) in $(.types)
|
| 46 |
+
{
|
| 47 |
+
errors.error "Type $(type) is already registered." ;
|
| 48 |
+
}
|
| 49 |
+
else
|
| 50 |
+
{
|
| 51 |
+
.types += $(type) ;
|
| 52 |
+
.base.$(type) = $(base-type) ;
|
| 53 |
+
.derived.$(base-type) += $(type) ;
|
| 54 |
+
|
| 55 |
+
if $(suffixes)-is-not-empty
|
| 56 |
+
{
|
| 57 |
+
# Specify mapping from suffixes to type.
|
| 58 |
+
register-suffixes $(suffixes) : $(type) ;
|
| 59 |
+
# By default generated targets of 'type' will use the first of
|
| 60 |
+
#'suffixes'. This may be overriden.
|
| 61 |
+
set-generated-target-suffix $(type) : : $(suffixes[1]) ;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
feature.extend target-type : $(type) ;
|
| 65 |
+
feature.extend main-target-type : $(type) ;
|
| 66 |
+
feature.extend base-target-type : $(type) ;
|
| 67 |
+
|
| 68 |
+
feature.compose <target-type>$(type) : $(base-type:G=<base-target-type>) ;
|
| 69 |
+
feature.compose <base-target-type>$(type) : <base-target-type>$(base-type) ;
|
| 70 |
+
|
| 71 |
+
# We used to declare the main target rule only when a 'main' parameter
|
| 72 |
+
# has been specified. However, it is hard to decide that a type will
|
| 73 |
+
# *never* need a main target rule and so from time to time we needed to
|
| 74 |
+
# make yet another type 'main'. So now a main target rule is defined for
|
| 75 |
+
# each type.
|
| 76 |
+
main-rule-name = [ type-to-rule-name $(type) ] ;
|
| 77 |
+
.main-target-type.$(main-rule-name) = $(type) ;
|
| 78 |
+
IMPORT $(__name__) : main-target-rule : : $(main-rule-name) ;
|
| 79 |
+
|
| 80 |
+
# Adding a new derived type affects generator selection so we need to
|
| 81 |
+
# make the generator selection module update any of its cached
|
| 82 |
+
# information related to a new derived type being defined.
|
| 83 |
+
generators.update-cached-information-with-a-new-type $(type) ;
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
# Given a type, returns the name of the main target rule which creates targets
|
| 89 |
+
# of that type.
|
| 90 |
+
#
|
| 91 |
+
rule type-to-rule-name ( type )
|
| 92 |
+
{
|
| 93 |
+
# Lowercase everything. Convert underscores to dashes.
|
| 94 |
+
import regex ;
|
| 95 |
+
local n = [ regex.split $(type:L) "_" ] ;
|
| 96 |
+
return $(n:J=-) ;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
|
| 100 |
+
# Given a main target rule name, returns the type for which it creates targets.
|
| 101 |
+
#
|
| 102 |
+
rule type-from-rule-name ( rule-name )
|
| 103 |
+
{
|
| 104 |
+
return $(.main-target-type.$(rule-name)) ;
|
| 105 |
+
}
|
| 106 |
+
|
| 107 |
+
|
| 108 |
+
# Specifies that files with suffix from 'suffixes' be recognized as targets of
|
| 109 |
+
# type 'type'. Issues an error if a different type is already specified for any
|
| 110 |
+
# of the suffixes.
|
| 111 |
+
#
|
| 112 |
+
rule register-suffixes ( suffixes + : type )
|
| 113 |
+
{
|
| 114 |
+
for local s in $(suffixes)
|
| 115 |
+
{
|
| 116 |
+
if ! $(.type.$(s))
|
| 117 |
+
{
|
| 118 |
+
.type.$(s) = $(type) ;
|
| 119 |
+
}
|
| 120 |
+
else if $(.type.$(s)) != $(type)
|
| 121 |
+
{
|
| 122 |
+
errors.error Attempting to specify multiple types for suffix
|
| 123 |
+
\"$(s)\" : "Old type $(.type.$(s)), New type $(type)" ;
|
| 124 |
+
}
|
| 125 |
+
}
|
| 126 |
+
}
|
| 127 |
+
|
| 128 |
+
|
| 129 |
+
# Returns true iff type has been registered.
|
| 130 |
+
#
|
| 131 |
+
rule registered ( type )
|
| 132 |
+
{
|
| 133 |
+
if $(type) in $(.types)
|
| 134 |
+
{
|
| 135 |
+
return true ;
|
| 136 |
+
}
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
# Issues an error if 'type' is unknown.
|
| 141 |
+
#
|
| 142 |
+
rule validate ( type )
|
| 143 |
+
{
|
| 144 |
+
if ! [ registered $(type) ]
|
| 145 |
+
{
|
| 146 |
+
errors.error "Unknown target type $(type)" ;
|
| 147 |
+
}
|
| 148 |
+
}
|
| 149 |
+
|
| 150 |
+
|
| 151 |
+
# Sets a scanner class that will be used for this 'type'.
|
| 152 |
+
#
|
| 153 |
+
rule set-scanner ( type : scanner )
|
| 154 |
+
{
|
| 155 |
+
validate $(type) ;
|
| 156 |
+
.scanner.$(type) = $(scanner) ;
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
|
| 160 |
+
# Returns a scanner instance appropriate to 'type' and 'properties'.
|
| 161 |
+
#
|
| 162 |
+
rule get-scanner ( type : property-set )
|
| 163 |
+
{
|
| 164 |
+
if $(.scanner.$(type))
|
| 165 |
+
{
|
| 166 |
+
return [ scanner.get $(.scanner.$(type)) : $(property-set) ] ;
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
|
| 171 |
+
# Returns a base type for the given type or nothing in case the given type is
|
| 172 |
+
# not derived.
|
| 173 |
+
#
|
| 174 |
+
rule base ( type )
|
| 175 |
+
{
|
| 176 |
+
return $(.base.$(type)) ;
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
|
| 180 |
+
# Returns the given type and all of its base types in order of their distance
|
| 181 |
+
# from type.
|
| 182 |
+
#
|
| 183 |
+
rule all-bases ( type )
|
| 184 |
+
{
|
| 185 |
+
local result = $(type) ;
|
| 186 |
+
while $(type)
|
| 187 |
+
{
|
| 188 |
+
type = [ base $(type) ] ;
|
| 189 |
+
result += $(type) ;
|
| 190 |
+
}
|
| 191 |
+
return $(result) ;
|
| 192 |
+
}
|
| 193 |
+
|
| 194 |
+
|
| 195 |
+
# Returns the given type and all of its derived types in order of their distance
|
| 196 |
+
# from type.
|
| 197 |
+
#
|
| 198 |
+
rule all-derived ( type )
|
| 199 |
+
{
|
| 200 |
+
local result = $(type) ;
|
| 201 |
+
for local d in $(.derived.$(type))
|
| 202 |
+
{
|
| 203 |
+
result += [ all-derived $(d) ] ;
|
| 204 |
+
}
|
| 205 |
+
return $(result) ;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
# Returns true if 'type' is equal to 'base' or has 'base' as its direct or
|
| 210 |
+
# indirect base.
|
| 211 |
+
#
|
| 212 |
+
rule is-derived ( type base )
|
| 213 |
+
{
|
| 214 |
+
if $(base) in [ all-bases $(type) ]
|
| 215 |
+
{
|
| 216 |
+
return true ;
|
| 217 |
+
}
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
# Returns true if 'type' is either derived from or is equal to 'base'.
|
| 221 |
+
#
|
| 222 |
+
# TODO: It might be that is-derived and is-subtype were meant to be different
|
| 223 |
+
# rules - one returning true for type = base and one not, but as currently
|
| 224 |
+
# implemented they are actually the same. Clean this up.
|
| 225 |
+
#
|
| 226 |
+
rule is-subtype ( type base )
|
| 227 |
+
{
|
| 228 |
+
return [ is-derived $(type) $(base) ] ;
|
| 229 |
+
}
|
| 230 |
+
|
| 231 |
+
|
| 232 |
+
# Store suffixes for generated targets.
|
| 233 |
+
.suffixes = [ new property-map ] ;
|
| 234 |
+
|
| 235 |
+
# Store prefixes for generated targets (e.g. "lib" for library).
|
| 236 |
+
.prefixes = [ new property-map ] ;
|
| 237 |
+
|
| 238 |
+
|
| 239 |
+
# Sets a file suffix to be used when generating a target of 'type' with the
|
| 240 |
+
# specified properties. Can be called with no properties if no suffix has
|
| 241 |
+
# already been specified for the 'type'. The 'suffix' parameter can be an empty
|
| 242 |
+
# string ("") to indicate that no suffix should be used.
|
| 243 |
+
#
|
| 244 |
+
# Note that this does not cause files with 'suffix' to be automatically
|
| 245 |
+
# recognized as being of 'type'. Two different types can use the same suffix for
|
| 246 |
+
# their generated files but only one type can be auto-detected for a file with
|
| 247 |
+
# that suffix. User should explicitly specify which one using the
|
| 248 |
+
# register-suffixes rule.
|
| 249 |
+
#
|
| 250 |
+
rule set-generated-target-suffix ( type : properties * : suffix )
|
| 251 |
+
{
|
| 252 |
+
set-generated-target-ps suffix : $(type) : $(properties) : $(suffix) ;
|
| 253 |
+
}
|
| 254 |
+
|
| 255 |
+
|
| 256 |
+
# Change the suffix previously registered for this type/properties combination.
|
| 257 |
+
# If suffix is not yet specified, sets it.
|
| 258 |
+
#
|
| 259 |
+
rule change-generated-target-suffix ( type : properties * : suffix )
|
| 260 |
+
{
|
| 261 |
+
change-generated-target-ps suffix : $(type) : $(properties) : $(suffix) ;
|
| 262 |
+
}
|
| 263 |
+
|
| 264 |
+
|
| 265 |
+
# Returns the suffix used when generating a file of 'type' with the given
|
| 266 |
+
# properties.
|
| 267 |
+
#
|
| 268 |
+
rule generated-target-suffix ( type : property-set )
|
| 269 |
+
{
|
| 270 |
+
return [ generated-target-ps suffix : $(type) : $(property-set) ] ;
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
|
| 274 |
+
# Sets a target prefix that should be used when generating targets of 'type'
|
| 275 |
+
# with the specified properties. Can be called with empty properties if no
|
| 276 |
+
# prefix for 'type' has been specified yet.
|
| 277 |
+
#
|
| 278 |
+
# The 'prefix' parameter can be empty string ("") to indicate that no prefix
|
| 279 |
+
# should be used.
|
| 280 |
+
#
|
| 281 |
+
# Usage example: library names use the "lib" prefix on unix.
|
| 282 |
+
#
|
| 283 |
+
rule set-generated-target-prefix ( type : properties * : prefix )
|
| 284 |
+
{
|
| 285 |
+
set-generated-target-ps prefix : $(type) : $(properties) : $(prefix) ;
|
| 286 |
+
}
|
| 287 |
+
|
| 288 |
+
|
| 289 |
+
# Change the prefix previously registered for this type/properties combination.
|
| 290 |
+
# If prefix is not yet specified, sets it.
|
| 291 |
+
#
|
| 292 |
+
rule change-generated-target-prefix ( type : properties * : prefix )
|
| 293 |
+
{
|
| 294 |
+
change-generated-target-ps prefix : $(type) : $(properties) : $(prefix) ;
|
| 295 |
+
}
|
| 296 |
+
|
| 297 |
+
|
| 298 |
+
rule generated-target-prefix ( type : property-set )
|
| 299 |
+
{
|
| 300 |
+
return [ generated-target-ps prefix : $(type) : $(property-set) ] ;
|
| 301 |
+
}
|
| 302 |
+
|
| 303 |
+
|
| 304 |
+
# Common rules for prefix/suffix provisioning follow.
|
| 305 |
+
|
| 306 |
+
local rule set-generated-target-ps ( ps : type : properties * : psval )
|
| 307 |
+
{
|
| 308 |
+
properties = <target-type>$(type) $(properties) ;
|
| 309 |
+
$(.$(ps)es).insert $(properties) : $(psval) ;
|
| 310 |
+
}
|
| 311 |
+
|
| 312 |
+
|
| 313 |
+
local rule change-generated-target-ps ( ps : type : properties * : psval )
|
| 314 |
+
{
|
| 315 |
+
properties = <target-type>$(type) $(properties) ;
|
| 316 |
+
local prev = [ $(.$(ps)es).find-replace $(properties) : $(psval) ] ;
|
| 317 |
+
if ! $(prev)
|
| 318 |
+
{
|
| 319 |
+
set-generated-target-ps $(ps) : $(type) : $(properties) : $(psval) ;
|
| 320 |
+
}
|
| 321 |
+
}
|
| 322 |
+
|
| 323 |
+
|
| 324 |
+
# Returns either prefix or suffix (as indicated by 'ps') that should be used
|
| 325 |
+
# when generating a target of 'type' with the specified properties. Parameter
|
| 326 |
+
# 'ps' can be either "prefix" or "suffix". If no prefix/suffix is specified for
|
| 327 |
+
# 'type', returns prefix/suffix for base type, if any.
|
| 328 |
+
#
|
| 329 |
+
local rule generated-target-ps-real ( ps : type : properties * )
|
| 330 |
+
{
|
| 331 |
+
local result ;
|
| 332 |
+
local found ;
|
| 333 |
+
while $(type) && ! $(found)
|
| 334 |
+
{
|
| 335 |
+
result = [ $(.$(ps)es).find <target-type>$(type) $(properties) ] ;
|
| 336 |
+
# If the prefix/suffix is explicitly set to an empty string, we consider
|
| 337 |
+
# prefix/suffix to be found. If we were not to compare with "", there
|
| 338 |
+
# would be no way to specify an empty prefix/suffix.
|
| 339 |
+
if $(result)-is-not-empty
|
| 340 |
+
{
|
| 341 |
+
found = true ;
|
| 342 |
+
}
|
| 343 |
+
type = $(.base.$(type)) ;
|
| 344 |
+
}
|
| 345 |
+
if $(result) = ""
|
| 346 |
+
{
|
| 347 |
+
result = ;
|
| 348 |
+
}
|
| 349 |
+
return $(result) ;
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
|
| 353 |
+
local rule generated-target-ps ( ps : type : property-set )
|
| 354 |
+
{
|
| 355 |
+
local key = .$(ps).$(type).$(property-set) ;
|
| 356 |
+
local v = $($(key)) ;
|
| 357 |
+
if ! $(v)
|
| 358 |
+
{
|
| 359 |
+
v = [ generated-target-ps-real $(ps) : $(type) : [ $(property-set).raw ]
|
| 360 |
+
] ;
|
| 361 |
+
if ! $(v)
|
| 362 |
+
{
|
| 363 |
+
v = none ;
|
| 364 |
+
}
|
| 365 |
+
$(key) = $(v) ;
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
if $(v) != none
|
| 369 |
+
{
|
| 370 |
+
return $(v) ;
|
| 371 |
+
}
|
| 372 |
+
}
|
| 373 |
+
|
| 374 |
+
|
| 375 |
+
# Returns file type given its name. If there are several dots in filename, tries
|
| 376 |
+
# each suffix. E.g. for name of "file.so.1.2" suffixes "2", "1", and "so" will
|
| 377 |
+
# be tried.
|
| 378 |
+
#
|
| 379 |
+
rule type ( filename )
|
| 380 |
+
{
|
| 381 |
+
if [ os.name ] in NT CYGWIN
|
| 382 |
+
{
|
| 383 |
+
filename = $(filename:L) ;
|
| 384 |
+
}
|
| 385 |
+
local type ;
|
| 386 |
+
while ! $(type) && $(filename:S)
|
| 387 |
+
{
|
| 388 |
+
local suffix = $(filename:S) ;
|
| 389 |
+
type = $(.type$(suffix)) ;
|
| 390 |
+
filename = $(filename:S=) ;
|
| 391 |
+
}
|
| 392 |
+
return $(type) ;
|
| 393 |
+
}
|
| 394 |
+
|
| 395 |
+
|
| 396 |
+
# Rule used to construct all main targets. Note that this rule gets imported
|
| 397 |
+
# into the global namespace under different alias names and the exact target
|
| 398 |
+
# type to construct is selected based on the alias used to actually invoke this
|
| 399 |
+
# rule.
|
| 400 |
+
#
|
| 401 |
+
rule main-target-rule ( name : sources * : requirements * : default-build * :
|
| 402 |
+
usage-requirements * )
|
| 403 |
+
{
|
| 404 |
+
# First discover the required target type based on the exact alias used to
|
| 405 |
+
# invoke this rule.
|
| 406 |
+
local bt = [ BACKTRACE 1 ] ;
|
| 407 |
+
local rulename = $(bt[4]) ;
|
| 408 |
+
local target-type = [ type-from-rule-name $(rulename) ] ;
|
| 409 |
+
|
| 410 |
+
# This is a circular module dependency and so must be imported here.
|
| 411 |
+
import targets ;
|
| 412 |
+
|
| 413 |
+
return [ targets.create-typed-target $(target-type) : [ project.current ] :
|
| 414 |
+
$(name) : $(sources) : $(requirements) : $(default-build) :
|
| 415 |
+
$(usage-requirements) ] ;
|
| 416 |
+
}
|
| 417 |
+
|
| 418 |
+
|
| 419 |
+
rule __test__ ( )
|
| 420 |
+
{
|
| 421 |
+
import assert ;
|
| 422 |
+
|
| 423 |
+
# TODO: Add tests for all the is-derived, is-base & related type relation
|
| 424 |
+
# checking rules.
|
| 425 |
+
}
|
mosesdecoder/jam-files/engine/boehm_gc/NT_X64_STATIC_THREADS_MAKEFILE
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Makefile for Windows NT. Assumes Microsoft compiler.
|
| 2 |
+
# DLLs are included in the root set under NT, but not under win32S.
|
| 3 |
+
# Use "nmake nodebug=1 all" for optimized versions of library, gctest and editor.
|
| 4 |
+
|
| 5 |
+
MY_CPU=AMD64
|
| 6 |
+
CPU=$(MY_CPU)
|
| 7 |
+
!include <ntwin32.mak>
|
| 8 |
+
|
| 9 |
+
# Make sure that .cc is not viewed as a suffix. It is for VC++2005, but
|
| 10 |
+
# not earlier versions. We can deal with either, but not inconsistency.
|
| 11 |
+
.SUFFIXES:
|
| 12 |
+
.SUFFIXES: .obj .cpp .c
|
| 13 |
+
|
| 14 |
+
# Atomic_ops installation directory. For win32, the source directory
|
| 15 |
+
# should do, since we only need the headers.
|
| 16 |
+
# We assume this was manually unpacked, since I'm not sure there is
|
| 17 |
+
# a Windows standard command line tool to do this.
|
| 18 |
+
AO_VERSION=1.2
|
| 19 |
+
AO_SRC_DIR=libatomic_ops-$(AO_VERSION)/src
|
| 20 |
+
AO_INCLUDE_DIR=$(AO_SRC_DIR)
|
| 21 |
+
|
| 22 |
+
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
|
| 23 |
+
|
| 24 |
+
all: gctest.exe cord\de.exe test_cpp.exe
|
| 25 |
+
|
| 26 |
+
.c.obj:
|
| 27 |
+
$(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
|
| 28 |
+
# Disable "may not be initialized" warnings. They're too approximate.
|
| 29 |
+
# Disable crt security warnings, since unfortunately they warn about all sorts
|
| 30 |
+
# of safe uses of strncpy. It would be nice to leave the rest enabled.
|
| 31 |
+
|
| 32 |
+
.cpp.obj:
|
| 33 |
+
$(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
|
| 34 |
+
|
| 35 |
+
$(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
|
| 36 |
+
|
| 37 |
+
gc.lib: $(OBJS)
|
| 38 |
+
lib /MACHINE:X64 /out:gc.lib $(OBJS)
|
| 39 |
+
|
| 40 |
+
gctest.exe: tests\test.obj gc.lib
|
| 41 |
+
# This produces a "GUI" applications that opens no windows and writes to the log file
|
| 42 |
+
# "gc.log". This was done to make the result runnable under win32s and
|
| 43 |
+
# should be fixed.
|
| 44 |
+
$(link) $(ldebug) $(guiflags) -stack:131072 -out:$*.exe tests\test.obj $(guilibs) gc.lib
|
| 45 |
+
|
| 46 |
+
cord\de_win.rbj: cord\de_win.res
|
| 47 |
+
cvtres /MACHINE:$(MY_CPU) /OUT:cord\de_win.rbj cord\de_win.res
|
| 48 |
+
|
| 49 |
+
cord\de.obj cord\de_win.obj: include\cord.h include\private\cord_pos.h cord\de_win.h cord\de_cmds.h
|
| 50 |
+
|
| 51 |
+
cord\de_win.res: cord\de_win.rc cord\de_win.h cord\de_cmds.h
|
| 52 |
+
$(rc) $(rcvars) -r -fo cord\de_win.res cord\de_win.rc
|
| 53 |
+
|
| 54 |
+
# Cord/de is a real win32 gui application.
|
| 55 |
+
cord\de.exe: cord\cordbscs.obj cord\cordxtra.obj cord\de.obj cord\de_win.obj cord\de_win.rbj gc.lib
|
| 56 |
+
$(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)
|
| 57 |
+
|
| 58 |
+
gc_cpp.obj: include\gc_cpp.h include\gc.h
|
| 59 |
+
|
| 60 |
+
gc_cpp.cpp: gc_cpp.cc
|
| 61 |
+
copy gc_cpp.cc gc_cpp.cpp
|
| 62 |
+
|
| 63 |
+
test_cpp.cpp: tests\test_cpp.cc
|
| 64 |
+
copy tests\test_cpp.cc test_cpp.cpp
|
| 65 |
+
|
| 66 |
+
# This generates the C++ test executable. The executable expects
|
| 67 |
+
# a single numeric argument, which is the number of iterations.
|
| 68 |
+
# The output appears in the file "gc.log".
|
| 69 |
+
test_cpp.exe: test_cpp.obj include\gc_cpp.h include\gc.h gc.lib
|
| 70 |
+
$(link) $(ldebug) $(guiflags) -stack:16384 -out:test_cpp.exe test_cpp.obj gc.lib $(guilibs)
|
| 71 |
+
|
| 72 |
+
AO_SCR_DIR:
|
| 73 |
+
tar xvfz $(AO_SRC_DIR).tar.gz;
|
| 74 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/SMakefile.amiga
ADDED
|
@@ -0,0 +1,177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
# Rewritten smakefile for amiga / sas/c. -Kjetil M.
|
| 3 |
+
# Dont use the cord-package if you define parm=both or parm=reg.
|
| 4 |
+
|
| 5 |
+
|
| 6 |
+
#----------------TOOLS--------------------------------
|
| 7 |
+
CC=sc
|
| 8 |
+
LINKER=slink
|
| 9 |
+
LIBER=oml
|
| 10 |
+
|
| 11 |
+
#----------------CPU OPTIONS--------------------------
|
| 12 |
+
|
| 13 |
+
CPU=68060
|
| 14 |
+
|
| 15 |
+
#----------------FPU OPTIONS--------------------------
|
| 16 |
+
|
| 17 |
+
MATH=8
|
| 18 |
+
MATHLIB=LIB:scm881.lib
|
| 19 |
+
|
| 20 |
+
#----------------COMPILER OPTIONS---------------------
|
| 21 |
+
|
| 22 |
+
IGNORE= IGNORE=85 IGNORE=154 IGNORE=161 IGNORE=100
|
| 23 |
+
|
| 24 |
+
OPTIMIZE=optimize optimizetime optglobal optimizerdepth=100 optimizerpeephole optloop OPTSCHED optimizerinlocal optimizerrecurdepth=100
|
| 25 |
+
# optimizerinline optimizercomplexity=100
|
| 26 |
+
|
| 27 |
+
OPT= $(OPTIMIZE) CPU=$(CPU) math=$(MATH) NOSTACKCHECK VERBOSE \
|
| 28 |
+
MAPHUNK NOVERSION NOICONS nodebug \
|
| 29 |
+
parm=reg \
|
| 30 |
+
DEFINE __USE_SYSBASE
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
SOPT= $(OPT) $(IGNORE) \
|
| 34 |
+
DEFINE AMIGA_SKIP_SEG \
|
| 35 |
+
DEFINE ATOMIC_UNCOLLECTABLE \
|
| 36 |
+
DEFINE GC_AMIGA_FASTALLOC \
|
| 37 |
+
DEFINE GC_AMIGA_RETRY \
|
| 38 |
+
DEFINE GC_AMIGA_PRINTSTATS \
|
| 39 |
+
DEFINE GC_AMIGA_GC
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
#DEFINE ALL_INTERIOR_POINTERS \
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
SCOPT= $(SOPT) define GC_AMIGA_MAKINGLIB
|
| 46 |
+
|
| 47 |
+
CSCOPT= $(OPT) DEFINE AMIGA IGNORE=100 IGNORE=161
|
| 48 |
+
|
| 49 |
+
#------------------LINKING----------------------------
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
all: gctest setjmp_t cord/cordtest
|
| 53 |
+
|
| 54 |
+
clean:
|
| 55 |
+
delete *.lib gctest setjmp_t *.o *.lnk cord/*.o cord/*.lib cord/*.lnk cord/cordtest
|
| 56 |
+
smake
|
| 57 |
+
|
| 58 |
+
test: setjmp_t gctest cord/cordtest
|
| 59 |
+
setjmp_t
|
| 60 |
+
gctest
|
| 61 |
+
cord/cordtest
|
| 62 |
+
|
| 63 |
+
gctest: gc$(CPU).lib GCAmigaOS$(CPU).lib test.o
|
| 64 |
+
$(LINKER) LIB:c.o test.o TO gctest LIB gc$(CPU).lib LIB:sc.lib $(MATHLIB)
|
| 65 |
+
|
| 66 |
+
setjmp_t: setjmp_t.o gc.h
|
| 67 |
+
$(LINKER) LIB:c.o setjmp_t.o to setjmp_t lib LIB:sc.lib
|
| 68 |
+
|
| 69 |
+
cord/cordtest: cord/cordtest.o cord/cord$(CPU).lib gc$(CPU).lib
|
| 70 |
+
slink LIB:c.o cord/cordtest.o LIB $(MATHLIB) gc$(CPU).lib cord/cord$(CPU).lib LIB:sc.lib TO cord/cordtest
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
#------------------LIBBING----------------------------
|
| 74 |
+
|
| 75 |
+
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
|
| 76 |
+
|
| 77 |
+
gc$(CPU).lib: $(OBJS)
|
| 78 |
+
$(LIBER) gc$(CPU).lib r $(OBJS)
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
COBJS = cord/cordbscs.o cord/cordprnt.o cord/cordxtra.o
|
| 82 |
+
|
| 83 |
+
cord/cord$(CPU).lib: $(COBJS)
|
| 84 |
+
oml cord/cord$(CPU).lib r $(COBJS)
|
| 85 |
+
|
| 86 |
+
#------------------COMPILING--------------------------
|
| 87 |
+
|
| 88 |
+
INC= gc_private.h gc_hdrs.h gc.h gcconfig.h
|
| 89 |
+
|
| 90 |
+
alloc.o : alloc.c $(INC)
|
| 91 |
+
$(CC) alloc.c $(SCOPT) ignore=7
|
| 92 |
+
|
| 93 |
+
reclaim.o : reclaim.c $(INC)
|
| 94 |
+
$(CC) reclaim.c $(SCOPT)
|
| 95 |
+
|
| 96 |
+
allchblk.o : allchblk.c $(INC)
|
| 97 |
+
$(CC) allchblk.c $(SCOPT)
|
| 98 |
+
|
| 99 |
+
misc.o : misc.c $(INC)
|
| 100 |
+
$(CC) misc.c $(SCOPT)
|
| 101 |
+
|
| 102 |
+
os_dep.o : os_dep.c $(INC) AmigaOS.c
|
| 103 |
+
$(CC) os_dep.c $(SCOPT)
|
| 104 |
+
|
| 105 |
+
mark_rts.o : mark_rts.c $(INC)
|
| 106 |
+
$(CC) mark_rts.c $(SCOPT)
|
| 107 |
+
|
| 108 |
+
headers.o : headers.c $(INC)
|
| 109 |
+
$(CC) headers.c $(SCOPT)
|
| 110 |
+
|
| 111 |
+
mark.o : mark.c $(INC)
|
| 112 |
+
$(CC) mark.c $(SCOPT)
|
| 113 |
+
|
| 114 |
+
obj_map.o : obj_map.c $(INC)
|
| 115 |
+
$(CC) obj_map.c $(SCOPT)
|
| 116 |
+
|
| 117 |
+
blacklst.o : blacklst.c $(INC)
|
| 118 |
+
$(CC) blacklst.c $(SCOPT)
|
| 119 |
+
|
| 120 |
+
finalize.o : finalize.c $(INC)
|
| 121 |
+
$(CC) finalize.c $(SCOPT) noopt #Could sas/c still have problems with this one? Gctest sometimes fails to finalize all.
|
| 122 |
+
|
| 123 |
+
new_hblk.o : new_hblk.c $(INC)
|
| 124 |
+
$(CC) new_hblk.c $(SCOPT)
|
| 125 |
+
|
| 126 |
+
real_malloc.o : real_malloc.c $(INC)
|
| 127 |
+
$(CC) real_malloc.c $(SCOPT)
|
| 128 |
+
|
| 129 |
+
dyn_load.o : dyn_load.c $(INC)
|
| 130 |
+
$(CC) dyn_load.c $(SCOPT)
|
| 131 |
+
|
| 132 |
+
dbg_mlc.o : dbg_mlc.c $(INC)
|
| 133 |
+
$(CC) dbg_mlc.c $(SCOPT)
|
| 134 |
+
|
| 135 |
+
malloc.o : malloc.c $(INC)
|
| 136 |
+
$(CC) malloc.c $(SCOPT)
|
| 137 |
+
|
| 138 |
+
mallocx.o : mallocx.c $(INC)
|
| 139 |
+
$(CC) mallocx.c $(SCOPT)
|
| 140 |
+
|
| 141 |
+
stubborn.o : stubborn.c $(INC)
|
| 142 |
+
$(CC) stubborn.c $(SCOPT)
|
| 143 |
+
|
| 144 |
+
checksums.o : checksums.c $(INC)
|
| 145 |
+
$(CC) checksums.c $(SCOPT)
|
| 146 |
+
|
| 147 |
+
typd_mlc.o: typd_mlc.c $(INC)
|
| 148 |
+
$(CC) typd_mlc.c $(SCOPT)
|
| 149 |
+
|
| 150 |
+
mach_dep.o : mach_dep.c $(INC)
|
| 151 |
+
$(CC) mach_dep.c $(SCOPT)
|
| 152 |
+
|
| 153 |
+
ptr_chck.o: ptr_chck.c $(INC)
|
| 154 |
+
$(CC) ptr_chck.c $(SCOPT)
|
| 155 |
+
|
| 156 |
+
test.o : test.c $(INC)
|
| 157 |
+
$(CC) test.c $(SOPT)
|
| 158 |
+
|
| 159 |
+
setjmp_t: setjmp_t.c gc.h
|
| 160 |
+
$(CC) setjmp_t.c $(SOPT)
|
| 161 |
+
|
| 162 |
+
|
| 163 |
+
# cords:
|
| 164 |
+
|
| 165 |
+
cord/cordbscs.o: cord/cordbscs.c
|
| 166 |
+
sc cord/cordbscs.c $(CSCOPT)
|
| 167 |
+
|
| 168 |
+
cord/cordprnt.o: cord/cordprnt.c
|
| 169 |
+
sc cord/cordprnt.c $(CSCOPT)
|
| 170 |
+
|
| 171 |
+
cord/cordxtra.o: cord/cordxtra.c
|
| 172 |
+
sc cord/cordxtra.c $(CSCOPT)
|
| 173 |
+
|
| 174 |
+
cord/cordtest.o: cord/cordtest.c
|
| 175 |
+
sc cord/cordtest.c $(CSCOPT)
|
| 176 |
+
|
| 177 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/alpha_mach_dep.S
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.arch ev6
|
| 2 |
+
|
| 3 |
+
.text
|
| 4 |
+
.align 4
|
| 5 |
+
.globl GC_push_regs
|
| 6 |
+
.ent GC_push_regs 2
|
| 7 |
+
GC_push_regs:
|
| 8 |
+
ldgp $gp, 0($27)
|
| 9 |
+
lda $sp, -16($sp)
|
| 10 |
+
stq $26, 0($sp)
|
| 11 |
+
.mask 0x04000000, 0
|
| 12 |
+
.frame $sp, 16, $26, 0
|
| 13 |
+
|
| 14 |
+
/* $0 integer result */
|
| 15 |
+
/* $1-$8 temp regs - not preserved cross calls */
|
| 16 |
+
/* $9-$15 call saved regs */
|
| 17 |
+
/* $16-$21 argument regs - not preserved cross calls */
|
| 18 |
+
/* $22-$28 temp regs - not preserved cross calls */
|
| 19 |
+
/* $29 global pointer - not preserved cross calls */
|
| 20 |
+
/* $30 stack pointer */
|
| 21 |
+
|
| 22 |
+
# define call_push(x) \
|
| 23 |
+
mov x, $16; \
|
| 24 |
+
jsr $26, GC_push_one; \
|
| 25 |
+
ldgp $gp, 0($26)
|
| 26 |
+
|
| 27 |
+
call_push($9)
|
| 28 |
+
call_push($10)
|
| 29 |
+
call_push($11)
|
| 30 |
+
call_push($12)
|
| 31 |
+
call_push($13)
|
| 32 |
+
call_push($14)
|
| 33 |
+
call_push($15)
|
| 34 |
+
|
| 35 |
+
/* $f0-$f1 floating point results */
|
| 36 |
+
/* $f2-$f9 call saved regs */
|
| 37 |
+
/* $f10-$f30 temp regs - not preserved cross calls */
|
| 38 |
+
|
| 39 |
+
/* Use the most efficient transfer method for this hardware. */
|
| 40 |
+
/* Bit 1 detects the FIX extension, which includes ftoit. */
|
| 41 |
+
amask 2, $0
|
| 42 |
+
bne $0, $use_stack
|
| 43 |
+
|
| 44 |
+
#undef call_push
|
| 45 |
+
#define call_push(x) \
|
| 46 |
+
ftoit x, $16; \
|
| 47 |
+
jsr $26, GC_push_one; \
|
| 48 |
+
ldgp $gp, 0($26)
|
| 49 |
+
|
| 50 |
+
call_push($f2)
|
| 51 |
+
call_push($f3)
|
| 52 |
+
call_push($f4)
|
| 53 |
+
call_push($f5)
|
| 54 |
+
call_push($f6)
|
| 55 |
+
call_push($f7)
|
| 56 |
+
call_push($f8)
|
| 57 |
+
call_push($f9)
|
| 58 |
+
|
| 59 |
+
ldq $26, 0($sp)
|
| 60 |
+
lda $sp, 16($sp)
|
| 61 |
+
ret $31, ($26), 1
|
| 62 |
+
|
| 63 |
+
.align 4
|
| 64 |
+
$use_stack:
|
| 65 |
+
|
| 66 |
+
#undef call_push
|
| 67 |
+
#define call_push(x) \
|
| 68 |
+
stt x, 8($sp); \
|
| 69 |
+
ldq $16, 8($sp); \
|
| 70 |
+
jsr $26, GC_push_one; \
|
| 71 |
+
ldgp $gp, 0($26)
|
| 72 |
+
|
| 73 |
+
call_push($f2)
|
| 74 |
+
call_push($f3)
|
| 75 |
+
call_push($f4)
|
| 76 |
+
call_push($f5)
|
| 77 |
+
call_push($f6)
|
| 78 |
+
call_push($f7)
|
| 79 |
+
call_push($f8)
|
| 80 |
+
call_push($f9)
|
| 81 |
+
|
| 82 |
+
ldq $26, 0($sp)
|
| 83 |
+
lda $sp, 16($sp)
|
| 84 |
+
ret $31, ($26), 1
|
| 85 |
+
|
| 86 |
+
.end GC_push_regs
|
mosesdecoder/jam-files/engine/boehm_gc/backgraph.c
ADDED
|
@@ -0,0 +1,469 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright (c) 2001 by Hewlett-Packard Company. All rights reserved.
|
| 3 |
+
*
|
| 4 |
+
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 5 |
+
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 6 |
+
*
|
| 7 |
+
* Permission is hereby granted to use or copy this program
|
| 8 |
+
* for any purpose, provided the above notices are retained on all copies.
|
| 9 |
+
* Permission to modify the code and to distribute modified code is granted,
|
| 10 |
+
* provided the above notices are retained, and a notice that the code was
|
| 11 |
+
* modified is included with the above copyright notice.
|
| 12 |
+
*
|
| 13 |
+
*/
|
| 14 |
+
|
| 15 |
+
/*
|
| 16 |
+
* This implements a full, though not well-tuned, representation of the
|
| 17 |
+
* backwards points-to graph. This is used to test for non-GC-robust
|
| 18 |
+
* data structures; the code is not used during normal garbage collection.
|
| 19 |
+
*
|
| 20 |
+
* One restriction is that we drop all back-edges from nodes with very
|
| 21 |
+
* high in-degree, and simply add them add them to a list of such
|
| 22 |
+
* nodes. They are then treated as permanent roots. Id this by itself
|
| 23 |
+
* doesn't introduce a space leak, then such nodes can't contribute to
|
| 24 |
+
* a growing space leak.
|
| 25 |
+
*/
|
| 26 |
+
|
| 27 |
+
#ifdef MAKE_BACK_GRAPH
|
| 28 |
+
|
| 29 |
+
#define MAX_IN 10 /* Maximum in-degree we handle directly */
|
| 30 |
+
|
| 31 |
+
#include "private/dbg_mlc.h"
|
| 32 |
+
#include <unistd.h>
|
| 33 |
+
|
| 34 |
+
#if !defined(DBG_HDRS_ALL) || (ALIGNMENT != CPP_WORDSZ/8) || !defined(UNIX_LIKE)
|
| 35 |
+
# error Configuration doesnt support MAKE_BACK_GRAPH
|
| 36 |
+
#endif
|
| 37 |
+
|
| 38 |
+
/* We store single back pointers directly in the object's oh_bg_ptr field. */
|
| 39 |
+
/* If there is more than one ptr to an object, we store q | FLAG_MANY, */
|
| 40 |
+
/* where q is a pointer to a back_edges object. */
|
| 41 |
+
/* Every once in a while we use a back_edges object even for a single */
|
| 42 |
+
/* pointer, since we need the other fields in the back_edges structure to */
|
| 43 |
+
/* be present in some fraction of the objects. Otherwise we get serious */
|
| 44 |
+
/* performance issues. */
|
| 45 |
+
#define FLAG_MANY 2
|
| 46 |
+
|
| 47 |
+
typedef struct back_edges_struct {
|
| 48 |
+
word n_edges; /* Number of edges, including those in continuation */
|
| 49 |
+
/* structures. */
|
| 50 |
+
unsigned short flags;
|
| 51 |
+
# define RETAIN 1 /* Directly points to a reachable object; */
|
| 52 |
+
/* retain for next GC. */
|
| 53 |
+
unsigned short height_gc_no;
|
| 54 |
+
/* If height > 0, then the GC_gc_no value when it */
|
| 55 |
+
/* was computed. If it was computed this cycle, then */
|
| 56 |
+
/* it is current. If it was computed during the */
|
| 57 |
+
/* last cycle, then it represents the old height, */
|
| 58 |
+
/* which is only saved for live objects referenced by */
|
| 59 |
+
/* dead ones. This may grow due to refs from newly */
|
| 60 |
+
/* dead objects. */
|
| 61 |
+
signed_word height;
|
| 62 |
+
/* Longest path through unreachable nodes to this node */
|
| 63 |
+
/* that we found using depth first search. */
|
| 64 |
+
|
| 65 |
+
# define HEIGHT_UNKNOWN ((signed_word)(-2))
|
| 66 |
+
# define HEIGHT_IN_PROGRESS ((signed_word)(-1))
|
| 67 |
+
ptr_t edges[MAX_IN];
|
| 68 |
+
struct back_edges_struct *cont;
|
| 69 |
+
/* Pointer to continuation structure; we use only the */
|
| 70 |
+
/* edges field in the continuation. */
|
| 71 |
+
/* also used as free list link. */
|
| 72 |
+
} back_edges;
|
| 73 |
+
|
| 74 |
+
/* Allocate a new back edge structure. Should be more sophisticated */
|
| 75 |
+
/* if this were production code. */
|
| 76 |
+
#define MAX_BACK_EDGE_STRUCTS 100000
|
| 77 |
+
static back_edges *back_edge_space = 0;
|
| 78 |
+
int GC_n_back_edge_structs = 0; /* Serves as pointer to never used */
|
| 79 |
+
/* back_edges space. */
|
| 80 |
+
static back_edges *avail_back_edges = 0;
|
| 81 |
+
/* Pointer to free list of deallocated */
|
| 82 |
+
/* back_edges structures. */
|
| 83 |
+
|
| 84 |
+
static back_edges * new_back_edges(void)
|
| 85 |
+
{
|
| 86 |
+
if (0 == back_edge_space) {
|
| 87 |
+
back_edge_space = (back_edges *)
|
| 88 |
+
GET_MEM(MAX_BACK_EDGE_STRUCTS*sizeof(back_edges));
|
| 89 |
+
}
|
| 90 |
+
if (0 != avail_back_edges) {
|
| 91 |
+
back_edges * result = avail_back_edges;
|
| 92 |
+
avail_back_edges = result -> cont;
|
| 93 |
+
result -> cont = 0;
|
| 94 |
+
return result;
|
| 95 |
+
}
|
| 96 |
+
if (GC_n_back_edge_structs >= MAX_BACK_EDGE_STRUCTS - 1) {
|
| 97 |
+
ABORT("needed too much space for back edges: adjust "
|
| 98 |
+
"MAX_BACK_EDGE_STRUCTS");
|
| 99 |
+
}
|
| 100 |
+
return back_edge_space + (GC_n_back_edge_structs++);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
/* Deallocate p and its associated continuation structures. */
|
| 104 |
+
static void deallocate_back_edges(back_edges *p)
|
| 105 |
+
{
|
| 106 |
+
back_edges *last = p;
|
| 107 |
+
|
| 108 |
+
while (0 != last -> cont) last = last -> cont;
|
| 109 |
+
last -> cont = avail_back_edges;
|
| 110 |
+
avail_back_edges = p;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
/* Table of objects that are currently on the depth-first search */
|
| 114 |
+
/* stack. Only objects with in-degree one are in this table. */
|
| 115 |
+
/* Other objects are identified using HEIGHT_IN_PROGRESS. */
|
| 116 |
+
/* FIXME: This data structure NEEDS IMPROVEMENT. */
|
| 117 |
+
#define INITIAL_IN_PROGRESS 10000
|
| 118 |
+
static ptr_t * in_progress_space = 0;
|
| 119 |
+
static size_t in_progress_size = 0;
|
| 120 |
+
static size_t n_in_progress = 0;
|
| 121 |
+
|
| 122 |
+
static void push_in_progress(ptr_t p)
|
| 123 |
+
{
|
| 124 |
+
if (n_in_progress >= in_progress_size)
|
| 125 |
+
if (in_progress_size == 0) {
|
| 126 |
+
in_progress_size = INITIAL_IN_PROGRESS;
|
| 127 |
+
in_progress_space = (ptr_t *)GET_MEM(in_progress_size * sizeof(ptr_t));
|
| 128 |
+
} else {
|
| 129 |
+
ptr_t * new_in_progress_space;
|
| 130 |
+
in_progress_size *= 2;
|
| 131 |
+
new_in_progress_space = (ptr_t *)
|
| 132 |
+
GET_MEM(in_progress_size * sizeof(ptr_t));
|
| 133 |
+
BCOPY(in_progress_space, new_in_progress_space,
|
| 134 |
+
n_in_progress * sizeof(ptr_t));
|
| 135 |
+
in_progress_space = new_in_progress_space;
|
| 136 |
+
/* FIXME: This just drops the old space. */
|
| 137 |
+
}
|
| 138 |
+
if (in_progress_space == 0)
|
| 139 |
+
ABORT("MAKE_BACK_GRAPH: Out of in-progress space: "
|
| 140 |
+
"Huge linear data structure?");
|
| 141 |
+
in_progress_space[n_in_progress++] = p;
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
static GC_bool is_in_progress(ptr_t p)
|
| 145 |
+
{
|
| 146 |
+
int i;
|
| 147 |
+
for (i = 0; i < n_in_progress; ++i) {
|
| 148 |
+
if (in_progress_space[i] == p) return TRUE;
|
| 149 |
+
}
|
| 150 |
+
return FALSE;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
static void pop_in_progress(ptr_t p)
|
| 154 |
+
{
|
| 155 |
+
--n_in_progress;
|
| 156 |
+
GC_ASSERT(in_progress_space[n_in_progress] == p);
|
| 157 |
+
}
|
| 158 |
+
|
| 159 |
+
#define GET_OH_BG_PTR(p) \
|
| 160 |
+
(ptr_t)REVEAL_POINTER(((oh *)(p)) -> oh_bg_ptr)
|
| 161 |
+
#define SET_OH_BG_PTR(p,q) (((oh *)(p)) -> oh_bg_ptr) = HIDE_POINTER(q)
|
| 162 |
+
|
| 163 |
+
/* Execute s once for each predecessor q of p in the points-to graph. */
|
| 164 |
+
/* s should be a bracketed statement. We declare q. */
|
| 165 |
+
#define FOR_EACH_PRED(q, p, s) \
|
| 166 |
+
{ \
|
| 167 |
+
ptr_t q = GET_OH_BG_PTR(p); \
|
| 168 |
+
if (!((word)q & FLAG_MANY)) { \
|
| 169 |
+
if (q && !((word)q & 1)) s \
|
| 170 |
+
/* !((word)q & 1) checks for a misnterpreted freelist link */ \
|
| 171 |
+
} else { \
|
| 172 |
+
back_edges *orig_be_ = (back_edges *)((word)q & ~FLAG_MANY); \
|
| 173 |
+
back_edges *be_ = orig_be_; \
|
| 174 |
+
int total_, local_; \
|
| 175 |
+
int n_edges_ = be_ -> n_edges; \
|
| 176 |
+
for (total_ = 0, local_ = 0; total_ < n_edges_; ++local_, ++total_) { \
|
| 177 |
+
if (local_ == MAX_IN) { \
|
| 178 |
+
be_ = be_ -> cont; \
|
| 179 |
+
local_ = 0; \
|
| 180 |
+
} \
|
| 181 |
+
q = be_ -> edges[local_]; s \
|
| 182 |
+
} \
|
| 183 |
+
} \
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
/* Ensure that p has a back_edges structure associated with it. */
|
| 187 |
+
static void ensure_struct(ptr_t p)
|
| 188 |
+
{
|
| 189 |
+
ptr_t old_back_ptr = GET_OH_BG_PTR(p);
|
| 190 |
+
|
| 191 |
+
if (!((word)old_back_ptr & FLAG_MANY)) {
|
| 192 |
+
back_edges *be = new_back_edges();
|
| 193 |
+
be -> flags = 0;
|
| 194 |
+
if (0 == old_back_ptr) {
|
| 195 |
+
be -> n_edges = 0;
|
| 196 |
+
} else {
|
| 197 |
+
be -> n_edges = 1;
|
| 198 |
+
be -> edges[0] = old_back_ptr;
|
| 199 |
+
}
|
| 200 |
+
be -> height = HEIGHT_UNKNOWN;
|
| 201 |
+
be -> height_gc_no = GC_gc_no - 1;
|
| 202 |
+
GC_ASSERT(be >= back_edge_space);
|
| 203 |
+
SET_OH_BG_PTR(p, (word)be | FLAG_MANY);
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
/* Add the (forward) edge from p to q to the backward graph. Both p */
|
| 208 |
+
/* q are pointers to the object base, i.e. pointers to an oh. */
|
| 209 |
+
static void add_edge(ptr_t p, ptr_t q)
|
| 210 |
+
{
|
| 211 |
+
ptr_t old_back_ptr = GET_OH_BG_PTR(q);
|
| 212 |
+
back_edges * be, *be_cont;
|
| 213 |
+
word i;
|
| 214 |
+
static unsigned random_number = 13;
|
| 215 |
+
# define GOT_LUCKY_NUMBER (((++random_number) & 0x7f) == 0)
|
| 216 |
+
/* A not very random number we use to occasionally allocate a */
|
| 217 |
+
/* back_edges structure even for a single backward edge. This */
|
| 218 |
+
/* prevents us from repeatedly tracing back through very long */
|
| 219 |
+
/* chains, since we will have some place to store height and */
|
| 220 |
+
/* in_progress flags along the way. */
|
| 221 |
+
|
| 222 |
+
GC_ASSERT(p == GC_base(p) && q == GC_base(q));
|
| 223 |
+
if (!GC_HAS_DEBUG_INFO(q) || !GC_HAS_DEBUG_INFO(p)) {
|
| 224 |
+
/* This is really a misinterpreted free list link, since we saw */
|
| 225 |
+
/* a pointer to a free list. Dont overwrite it! */
|
| 226 |
+
return;
|
| 227 |
+
}
|
| 228 |
+
if (0 == old_back_ptr) {
|
| 229 |
+
SET_OH_BG_PTR(q, p);
|
| 230 |
+
if (GOT_LUCKY_NUMBER) ensure_struct(q);
|
| 231 |
+
return;
|
| 232 |
+
}
|
| 233 |
+
/* Check whether it was already in the list of predecessors. */
|
| 234 |
+
FOR_EACH_PRED(pred, q, { if (p == pred) return; });
|
| 235 |
+
ensure_struct(q);
|
| 236 |
+
old_back_ptr = GET_OH_BG_PTR(q);
|
| 237 |
+
be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
|
| 238 |
+
for (i = be -> n_edges, be_cont = be; i > MAX_IN;
|
| 239 |
+
be_cont = be_cont -> cont, i -= MAX_IN) {}
|
| 240 |
+
if (i == MAX_IN) {
|
| 241 |
+
be_cont -> cont = new_back_edges();
|
| 242 |
+
be_cont = be_cont -> cont;
|
| 243 |
+
i = 0;
|
| 244 |
+
}
|
| 245 |
+
be_cont -> edges[i] = p;
|
| 246 |
+
be -> n_edges++;
|
| 247 |
+
if (be -> n_edges == 100) {
|
| 248 |
+
# if 0
|
| 249 |
+
if (GC_print_stats) {
|
| 250 |
+
GC_err_printf("The following object has in-degree >= 100:\n");
|
| 251 |
+
GC_print_heap_obj(q);
|
| 252 |
+
}
|
| 253 |
+
# endif
|
| 254 |
+
}
|
| 255 |
+
}
|
| 256 |
+
|
| 257 |
+
typedef void (*per_object_func)(ptr_t p, size_t n_bytes, word gc_descr);
|
| 258 |
+
|
| 259 |
+
static void per_object_helper(struct hblk *h, word fn)
|
| 260 |
+
{
|
| 261 |
+
hdr * hhdr = HDR(h);
|
| 262 |
+
size_t sz = hhdr -> hb_sz;
|
| 263 |
+
word descr = hhdr -> hb_descr;
|
| 264 |
+
per_object_func f = (per_object_func)fn;
|
| 265 |
+
int i = 0;
|
| 266 |
+
|
| 267 |
+
do {
|
| 268 |
+
f((ptr_t)(h -> hb_body + i), sz, descr);
|
| 269 |
+
i += sz;
|
| 270 |
+
} while (i + sz <= BYTES_TO_WORDS(HBLKSIZE));
|
| 271 |
+
}
|
| 272 |
+
|
| 273 |
+
void GC_apply_to_each_object(per_object_func f)
|
| 274 |
+
{
|
| 275 |
+
GC_apply_to_all_blocks(per_object_helper, (word)f);
|
| 276 |
+
}
|
| 277 |
+
|
| 278 |
+
static void reset_back_edge(ptr_t p, size_t n_bytes, word gc_descr)
|
| 279 |
+
{
|
| 280 |
+
/* Skip any free list links, or dropped blocks */
|
| 281 |
+
if (GC_HAS_DEBUG_INFO(p)) {
|
| 282 |
+
ptr_t old_back_ptr = GET_OH_BG_PTR(p);
|
| 283 |
+
if ((word)old_back_ptr & FLAG_MANY) {
|
| 284 |
+
back_edges *be = (back_edges *)((word)old_back_ptr & ~FLAG_MANY);
|
| 285 |
+
if (!(be -> flags & RETAIN)) {
|
| 286 |
+
deallocate_back_edges(be);
|
| 287 |
+
SET_OH_BG_PTR(p, 0);
|
| 288 |
+
} else {
|
| 289 |
+
word *currentp;
|
| 290 |
+
|
| 291 |
+
GC_ASSERT(GC_is_marked(p));
|
| 292 |
+
|
| 293 |
+
/* Back edges may point to objects that will not be retained. */
|
| 294 |
+
/* Delete them for now, but remember the height. */
|
| 295 |
+
/* Some will be added back at next GC. */
|
| 296 |
+
be -> n_edges = 0;
|
| 297 |
+
if (0 != be -> cont) {
|
| 298 |
+
deallocate_back_edges(be -> cont);
|
| 299 |
+
be -> cont = 0;
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
GC_ASSERT(GC_is_marked(p));
|
| 303 |
+
|
| 304 |
+
/* We only retain things for one GC cycle at a time. */
|
| 305 |
+
be -> flags &= ~RETAIN;
|
| 306 |
+
}
|
| 307 |
+
} else /* Simple back pointer */ {
|
| 308 |
+
/* Clear to avoid dangling pointer. */
|
| 309 |
+
SET_OH_BG_PTR(p, 0);
|
| 310 |
+
}
|
| 311 |
+
}
|
| 312 |
+
}
|
| 313 |
+
|
| 314 |
+
static void add_back_edges(ptr_t p, size_t n_bytes, word gc_descr)
|
| 315 |
+
{
|
| 316 |
+
word *currentp = (word *)(p + sizeof(oh));
|
| 317 |
+
|
| 318 |
+
/* For now, fix up non-length descriptors conservatively. */
|
| 319 |
+
if((gc_descr & GC_DS_TAGS) != GC_DS_LENGTH) {
|
| 320 |
+
gc_descr = n_bytes;
|
| 321 |
+
}
|
| 322 |
+
while (currentp < (word *)(p + gc_descr)) {
|
| 323 |
+
word current = *currentp++;
|
| 324 |
+
FIXUP_POINTER(current);
|
| 325 |
+
if (current >= (word)GC_least_plausible_heap_addr &&
|
| 326 |
+
current <= (word)GC_greatest_plausible_heap_addr) {
|
| 327 |
+
ptr_t target = GC_base((void *)current);
|
| 328 |
+
if (0 != target) {
|
| 329 |
+
add_edge(p, target);
|
| 330 |
+
}
|
| 331 |
+
}
|
| 332 |
+
}
|
| 333 |
+
}
|
| 334 |
+
|
| 335 |
+
/* Rebuild the representation of the backward reachability graph. */
|
| 336 |
+
/* Does not examine mark bits. Can be called before GC. */
|
| 337 |
+
void GC_build_back_graph(void)
|
| 338 |
+
{
|
| 339 |
+
GC_apply_to_each_object(add_back_edges);
|
| 340 |
+
}
|
| 341 |
+
|
| 342 |
+
/* Return an approximation to the length of the longest simple path */
|
| 343 |
+
/* through unreachable objects to p. We refer to this as the height */
|
| 344 |
+
/* of p. */
|
| 345 |
+
static word backwards_height(ptr_t p)
|
| 346 |
+
{
|
| 347 |
+
word result;
|
| 348 |
+
ptr_t back_ptr = GET_OH_BG_PTR(p);
|
| 349 |
+
back_edges *be;
|
| 350 |
+
|
| 351 |
+
if (0 == back_ptr) return 1;
|
| 352 |
+
if (!((word)back_ptr & FLAG_MANY)) {
|
| 353 |
+
if (is_in_progress(p)) return 0; /* DFS back edge, i.e. we followed */
|
| 354 |
+
/* an edge to an object already */
|
| 355 |
+
/* on our stack: ignore */
|
| 356 |
+
push_in_progress(p);
|
| 357 |
+
result = backwards_height(back_ptr)+1;
|
| 358 |
+
pop_in_progress(p);
|
| 359 |
+
return result;
|
| 360 |
+
}
|
| 361 |
+
be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
|
| 362 |
+
if (be -> height >= 0 && be -> height_gc_no == GC_gc_no)
|
| 363 |
+
return be -> height;
|
| 364 |
+
/* Ignore back edges in DFS */
|
| 365 |
+
if (be -> height == HEIGHT_IN_PROGRESS) return 0;
|
| 366 |
+
result = (be -> height > 0? be -> height : 1);
|
| 367 |
+
be -> height = HEIGHT_IN_PROGRESS;
|
| 368 |
+
FOR_EACH_PRED(q, p, {
|
| 369 |
+
word this_height;
|
| 370 |
+
if (GC_is_marked(q) && !(FLAG_MANY & (word)GET_OH_BG_PTR(p))) {
|
| 371 |
+
if (GC_print_stats)
|
| 372 |
+
GC_log_printf("Found bogus pointer from 0x%lx to 0x%lx\n", q, p);
|
| 373 |
+
/* Reachable object "points to" unreachable one. */
|
| 374 |
+
/* Could be caused by our lax treatment of GC descriptors. */
|
| 375 |
+
this_height = 1;
|
| 376 |
+
} else {
|
| 377 |
+
this_height = backwards_height(q);
|
| 378 |
+
}
|
| 379 |
+
if (this_height >= result) result = this_height + 1;
|
| 380 |
+
});
|
| 381 |
+
be -> height = result;
|
| 382 |
+
be -> height_gc_no = GC_gc_no;
|
| 383 |
+
return result;
|
| 384 |
+
}
|
| 385 |
+
|
| 386 |
+
word GC_max_height;
|
| 387 |
+
ptr_t GC_deepest_obj;
|
| 388 |
+
|
| 389 |
+
/* Compute the maximum height of every unreachable predecessor p of a */
|
| 390 |
+
/* reachable object. Arrange to save the heights of all such objects p */
|
| 391 |
+
/* so that they can be used in calculating the height of objects in the */
|
| 392 |
+
/* next GC. */
|
| 393 |
+
/* Set GC_max_height to be the maximum height we encounter, and */
|
| 394 |
+
/* GC_deepest_obj to be the corresponding object. */
|
| 395 |
+
static void update_max_height(ptr_t p, size_t n_bytes, word gc_descr)
|
| 396 |
+
{
|
| 397 |
+
if (GC_is_marked(p) && GC_HAS_DEBUG_INFO(p)) {
|
| 398 |
+
int i;
|
| 399 |
+
word p_height = 0;
|
| 400 |
+
ptr_t p_deepest_obj = 0;
|
| 401 |
+
ptr_t back_ptr;
|
| 402 |
+
back_edges *be = 0;
|
| 403 |
+
|
| 404 |
+
/* If we remembered a height last time, use it as a minimum. */
|
| 405 |
+
/* It may have increased due to newly unreachable chains pointing */
|
| 406 |
+
/* to p, but it can't have decreased. */
|
| 407 |
+
back_ptr = GET_OH_BG_PTR(p);
|
| 408 |
+
if (0 != back_ptr && ((word)back_ptr & FLAG_MANY)) {
|
| 409 |
+
be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
|
| 410 |
+
if (be -> height != HEIGHT_UNKNOWN) p_height = be -> height;
|
| 411 |
+
}
|
| 412 |
+
FOR_EACH_PRED(q, p, {
|
| 413 |
+
if (!GC_is_marked(q) && GC_HAS_DEBUG_INFO(q)) {
|
| 414 |
+
word q_height;
|
| 415 |
+
|
| 416 |
+
q_height = backwards_height(q);
|
| 417 |
+
if (q_height > p_height) {
|
| 418 |
+
p_height = q_height;
|
| 419 |
+
p_deepest_obj = q;
|
| 420 |
+
}
|
| 421 |
+
}
|
| 422 |
+
});
|
| 423 |
+
if (p_height > 0) {
|
| 424 |
+
/* Remember the height for next time. */
|
| 425 |
+
if (be == 0) {
|
| 426 |
+
ensure_struct(p);
|
| 427 |
+
back_ptr = GET_OH_BG_PTR(p);
|
| 428 |
+
be = (back_edges *)((word)back_ptr & ~FLAG_MANY);
|
| 429 |
+
}
|
| 430 |
+
be -> flags |= RETAIN;
|
| 431 |
+
be -> height = p_height;
|
| 432 |
+
be -> height_gc_no = GC_gc_no;
|
| 433 |
+
}
|
| 434 |
+
if (p_height > GC_max_height) {
|
| 435 |
+
GC_max_height = p_height;
|
| 436 |
+
GC_deepest_obj = p_deepest_obj;
|
| 437 |
+
}
|
| 438 |
+
}
|
| 439 |
+
}
|
| 440 |
+
|
| 441 |
+
word GC_max_max_height = 0;
|
| 442 |
+
|
| 443 |
+
void GC_traverse_back_graph(void)
|
| 444 |
+
{
|
| 445 |
+
GC_max_height = 0;
|
| 446 |
+
GC_apply_to_each_object(update_max_height);
|
| 447 |
+
if (0 != GC_deepest_obj)
|
| 448 |
+
GC_set_mark_bit(GC_deepest_obj); /* Keep it until we can print it. */
|
| 449 |
+
}
|
| 450 |
+
|
| 451 |
+
void GC_print_back_graph_stats(void)
|
| 452 |
+
{
|
| 453 |
+
GC_printf("Maximum backwards height of reachable objects at GC %lu is %ld\n",
|
| 454 |
+
(unsigned long) GC_gc_no, (unsigned long)GC_max_height);
|
| 455 |
+
if (GC_max_height > GC_max_max_height) {
|
| 456 |
+
GC_max_max_height = GC_max_height;
|
| 457 |
+
GC_printf("The following unreachable object is last in a longest chain "
|
| 458 |
+
"of unreachable objects:\n");
|
| 459 |
+
GC_print_heap_obj(GC_deepest_obj);
|
| 460 |
+
}
|
| 461 |
+
if (GC_print_stats) {
|
| 462 |
+
GC_log_printf("Needed max total of %ld back-edge structs\n",
|
| 463 |
+
GC_n_back_edge_structs);
|
| 464 |
+
}
|
| 465 |
+
GC_apply_to_each_object(reset_back_edge);
|
| 466 |
+
GC_deepest_obj = 0;
|
| 467 |
+
}
|
| 468 |
+
|
| 469 |
+
#endif /* MAKE_BACK_GRAPH */
|
mosesdecoder/jam-files/engine/boehm_gc/bdw-gc.pc
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
prefix=/usr/local
|
| 2 |
+
exec_prefix=${prefix}
|
| 3 |
+
libdir=${exec_prefix}/lib
|
| 4 |
+
includedir=${prefix}/include
|
| 5 |
+
|
| 6 |
+
Name: Boehm-Demers-Weiser Conservative Garbage Collector
|
| 7 |
+
Description: A garbage collector for C and C++
|
| 8 |
+
Version: 7.0
|
| 9 |
+
Libs: -L${libdir} -lgc
|
| 10 |
+
Cflags: -I${includedir}
|
mosesdecoder/jam-files/engine/boehm_gc/callprocs
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/sh
|
| 2 |
+
GC_DEBUG=1
|
| 3 |
+
export GC_DEBUG
|
| 4 |
+
$* 2>&1 | awk '{print "0x3e=c\""$0"\""};/^\t##PC##=/ {if ($2 != 0) {print $2"?i"}}' | adb $1 | sed "s/^ >/>/"
|
mosesdecoder/jam-files/engine/boehm_gc/compile
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#! /bin/sh
|
| 2 |
+
# Wrapper for compilers which do not understand `-c -o'.
|
| 3 |
+
|
| 4 |
+
scriptversion=2004-10-12.08
|
| 5 |
+
|
| 6 |
+
# Copyright (C) 1999, 2000, 2003, 2004 Free Software Foundation, Inc.
|
| 7 |
+
# Written by Tom Tromey <tromey@cygnus.com>.
|
| 8 |
+
#
|
| 9 |
+
# This program is free software; you can redistribute it and/or modify
|
| 10 |
+
# it under the terms of the GNU General Public License as published by
|
| 11 |
+
# the Free Software Foundation; either version 2, or (at your option)
|
| 12 |
+
# any later version.
|
| 13 |
+
#
|
| 14 |
+
# This program is distributed in the hope that it will be useful,
|
| 15 |
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
| 16 |
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
| 17 |
+
# GNU General Public License for more details.
|
| 18 |
+
#
|
| 19 |
+
# You should have received a copy of the GNU General Public License
|
| 20 |
+
# along with this program; if not, write to the Free Software
|
| 21 |
+
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
| 22 |
+
|
| 23 |
+
# As a special exception to the GNU General Public License, if you
|
| 24 |
+
# distribute this file as part of a program that contains a
|
| 25 |
+
# configuration script generated by Autoconf, you may include it under
|
| 26 |
+
# the same distribution terms that you use for the rest of that program.
|
| 27 |
+
|
| 28 |
+
# This file is maintained in Automake, please report
|
| 29 |
+
# bugs to <bug-automake@gnu.org> or send patches to
|
| 30 |
+
# <automake-patches@gnu.org>.
|
| 31 |
+
|
| 32 |
+
case $1 in
|
| 33 |
+
'')
|
| 34 |
+
echo "$0: No command. Try \`$0 --help' for more information." 1>&2
|
| 35 |
+
exit 1;
|
| 36 |
+
;;
|
| 37 |
+
-h | --h*)
|
| 38 |
+
cat <<\EOF
|
| 39 |
+
Usage: compile [--help] [--version] PROGRAM [ARGS]
|
| 40 |
+
|
| 41 |
+
Wrapper for compilers which do not understand `-c -o'.
|
| 42 |
+
Remove `-o dest.o' from ARGS, run PROGRAM with the remaining
|
| 43 |
+
arguments, and rename the output as expected.
|
| 44 |
+
|
| 45 |
+
If you are trying to build a whole package this is not the
|
| 46 |
+
right script to run: please start by reading the file `INSTALL'.
|
| 47 |
+
|
| 48 |
+
Report bugs to <bug-automake@gnu.org>.
|
| 49 |
+
EOF
|
| 50 |
+
exit 0
|
| 51 |
+
;;
|
| 52 |
+
-v | --v*)
|
| 53 |
+
echo "compile $scriptversion"
|
| 54 |
+
exit 0
|
| 55 |
+
;;
|
| 56 |
+
esac
|
| 57 |
+
|
| 58 |
+
ofile=
|
| 59 |
+
cfile=
|
| 60 |
+
eat=
|
| 61 |
+
|
| 62 |
+
for arg
|
| 63 |
+
do
|
| 64 |
+
if test -n "$eat"; then
|
| 65 |
+
eat=
|
| 66 |
+
else
|
| 67 |
+
case $1 in
|
| 68 |
+
-o)
|
| 69 |
+
# configure might choose to run compile as `compile cc -o foo foo.c'.
|
| 70 |
+
# So we strip `-o arg' only if arg is an object.
|
| 71 |
+
eat=1
|
| 72 |
+
case $2 in
|
| 73 |
+
*.o | *.obj)
|
| 74 |
+
ofile=$2
|
| 75 |
+
;;
|
| 76 |
+
*)
|
| 77 |
+
set x "$@" -o "$2"
|
| 78 |
+
shift
|
| 79 |
+
;;
|
| 80 |
+
esac
|
| 81 |
+
;;
|
| 82 |
+
*.c)
|
| 83 |
+
cfile=$1
|
| 84 |
+
set x "$@" "$1"
|
| 85 |
+
shift
|
| 86 |
+
;;
|
| 87 |
+
*)
|
| 88 |
+
set x "$@" "$1"
|
| 89 |
+
shift
|
| 90 |
+
;;
|
| 91 |
+
esac
|
| 92 |
+
fi
|
| 93 |
+
shift
|
| 94 |
+
done
|
| 95 |
+
|
| 96 |
+
if test -z "$ofile" || test -z "$cfile"; then
|
| 97 |
+
# If no `-o' option was seen then we might have been invoked from a
|
| 98 |
+
# pattern rule where we don't need one. That is ok -- this is a
|
| 99 |
+
# normal compilation that the losing compiler can handle. If no
|
| 100 |
+
# `.c' file was seen then we are probably linking. That is also
|
| 101 |
+
# ok.
|
| 102 |
+
exec "$@"
|
| 103 |
+
fi
|
| 104 |
+
|
| 105 |
+
# Name of file we expect compiler to create.
|
| 106 |
+
cofile=`echo "$cfile" | sed -e 's|^.*/||' -e 's/\.c$/.o/'`
|
| 107 |
+
|
| 108 |
+
# Create the lock directory.
|
| 109 |
+
# Note: use `[/.-]' here to ensure that we don't use the same name
|
| 110 |
+
# that we are using for the .o file. Also, base the name on the expected
|
| 111 |
+
# object file name, since that is what matters with a parallel build.
|
| 112 |
+
lockdir=`echo "$cofile" | sed -e 's|[/.-]|_|g'`.d
|
| 113 |
+
while true; do
|
| 114 |
+
if mkdir "$lockdir" >/dev/null 2>&1; then
|
| 115 |
+
break
|
| 116 |
+
fi
|
| 117 |
+
sleep 1
|
| 118 |
+
done
|
| 119 |
+
# FIXME: race condition here if user kills between mkdir and trap.
|
| 120 |
+
trap "rmdir '$lockdir'; exit 1" 1 2 15
|
| 121 |
+
|
| 122 |
+
# Run the compile.
|
| 123 |
+
"$@"
|
| 124 |
+
ret=$?
|
| 125 |
+
|
| 126 |
+
if test -f "$cofile"; then
|
| 127 |
+
mv "$cofile" "$ofile"
|
| 128 |
+
elif test -f "${cofile}bj"; then
|
| 129 |
+
mv "${cofile}bj" "$ofile"
|
| 130 |
+
fi
|
| 131 |
+
|
| 132 |
+
rmdir "$lockdir"
|
| 133 |
+
exit $ret
|
| 134 |
+
|
| 135 |
+
# Local Variables:
|
| 136 |
+
# mode: shell-script
|
| 137 |
+
# sh-indentation: 2
|
| 138 |
+
# eval: (add-hook 'write-file-hooks 'time-stamp)
|
| 139 |
+
# time-stamp-start: "scriptversion="
|
| 140 |
+
# time-stamp-format: "%:y-%02m-%02d.%02H"
|
| 141 |
+
# time-stamp-end: "$"
|
| 142 |
+
# End:
|
mosesdecoder/jam-files/engine/boehm_gc/configure
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
mosesdecoder/jam-files/engine/boehm_gc/doc/README
ADDED
|
@@ -0,0 +1,548 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
Copyright (c) 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
| 2 |
+
Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
| 3 |
+
Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
| 4 |
+
Copyright (c) 1999-2005 Hewlett-Packard Development Company, L.P.
|
| 5 |
+
|
| 6 |
+
The file linux_threads.c is also
|
| 7 |
+
Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
| 8 |
+
|
| 9 |
+
The files Makefile.am, and configure.in are
|
| 10 |
+
Copyright (c) 2001 by Red Hat Inc. All rights reserved.
|
| 11 |
+
|
| 12 |
+
Several files supporting GNU-style builds are copyrighted by the Free
|
| 13 |
+
Software Foundation, and carry a different license from that given
|
| 14 |
+
below. The files included in the libatomic_ops distribution (included
|
| 15 |
+
here) use either the license below, or a similar MIT-style license,
|
| 16 |
+
or, for some files not actually used by the garbage-collector library, the
|
| 17 |
+
GPL.
|
| 18 |
+
|
| 19 |
+
THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 20 |
+
OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 21 |
+
|
| 22 |
+
Permission is hereby granted to use or copy this program
|
| 23 |
+
for any purpose, provided the above notices are retained on all copies.
|
| 24 |
+
Permission to modify the code and to distribute modified code is granted,
|
| 25 |
+
provided the above notices are retained, and a notice that the code was
|
| 26 |
+
modified is included with the above copyright notice.
|
| 27 |
+
|
| 28 |
+
A few of the files needed to use the GNU-style build procedure come with
|
| 29 |
+
slightly different licenses, though they are all similar in spirit. A few
|
| 30 |
+
are GPL'ed, but with an exception that should cover all uses in the
|
| 31 |
+
collector. (If you are concerned about such things, I recommend you look
|
| 32 |
+
at the notice in config.guess or ltmain.sh.)
|
| 33 |
+
|
| 34 |
+
This is version 7.0 of a conservative garbage collector for C and C++.
|
| 35 |
+
|
| 36 |
+
You might find a more recent version of this at
|
| 37 |
+
|
| 38 |
+
http://www.hpl.hp.com/personal/Hans_Boehm/gc
|
| 39 |
+
|
| 40 |
+
OVERVIEW
|
| 41 |
+
|
| 42 |
+
This is intended to be a general purpose, garbage collecting storage
|
| 43 |
+
allocator. The algorithms used are described in:
|
| 44 |
+
|
| 45 |
+
Boehm, H., and M. Weiser, "Garbage Collection in an Uncooperative Environment",
|
| 46 |
+
Software Practice & Experience, September 1988, pp. 807-820.
|
| 47 |
+
|
| 48 |
+
Boehm, H., A. Demers, and S. Shenker, "Mostly Parallel Garbage Collection",
|
| 49 |
+
Proceedings of the ACM SIGPLAN '91 Conference on Programming Language Design
|
| 50 |
+
and Implementation, SIGPLAN Notices 26, 6 (June 1991), pp. 157-164.
|
| 51 |
+
|
| 52 |
+
Boehm, H., "Space Efficient Conservative Garbage Collection", Proceedings
|
| 53 |
+
of the ACM SIGPLAN '91 Conference on Programming Language Design and
|
| 54 |
+
Implementation, SIGPLAN Notices 28, 6 (June 1993), pp. 197-206.
|
| 55 |
+
|
| 56 |
+
Boehm H., "Reducing Garbage Collector Cache Misses", Proceedings of the
|
| 57 |
+
2000 International Symposium on Memory Management.
|
| 58 |
+
|
| 59 |
+
Possible interactions between the collector and optimizing compilers are
|
| 60 |
+
discussed in
|
| 61 |
+
|
| 62 |
+
Boehm, H., and D. Chase, "A Proposal for GC-safe C Compilation",
|
| 63 |
+
The Journal of C Language Translation 4, 2 (December 1992).
|
| 64 |
+
|
| 65 |
+
and
|
| 66 |
+
|
| 67 |
+
Boehm H., "Simple GC-safe Compilation", Proceedings
|
| 68 |
+
of the ACM SIGPLAN '96 Conference on Programming Language Design and
|
| 69 |
+
Implementation.
|
| 70 |
+
|
| 71 |
+
(Some of these are also available from
|
| 72 |
+
http://www.hpl.hp.com/personal/Hans_Boehm/papers/, among other places.)
|
| 73 |
+
|
| 74 |
+
Unlike the collector described in the second reference, this collector
|
| 75 |
+
operates either with the mutator stopped during the entire collection
|
| 76 |
+
(default) or incrementally during allocations. (The latter is supported
|
| 77 |
+
on fewer machines.) On the most common platforms, it can be built
|
| 78 |
+
with or without thread support. On a few platforms, it can take advantage
|
| 79 |
+
of a multiprocessor to speed up garbage collection.
|
| 80 |
+
|
| 81 |
+
Many of the ideas underlying the collector have previously been explored
|
| 82 |
+
by others. Notably, some of the run-time systems developed at Xerox PARC
|
| 83 |
+
in the early 1980s conservatively scanned thread stacks to locate possible
|
| 84 |
+
pointers (cf. Paul Rovner, "On Adding Garbage Collection and Runtime Types
|
| 85 |
+
to a Strongly-Typed Statically Checked, Concurrent Language" Xerox PARC
|
| 86 |
+
CSL 84-7). Doug McIlroy wrote a simpler fully conservative collector that
|
| 87 |
+
was part of version 8 UNIX (tm), but appears to not have received
|
| 88 |
+
widespread use.
|
| 89 |
+
|
| 90 |
+
Rudimentary tools for use of the collector as a leak detector are included
|
| 91 |
+
(see http://www.hpl.hp.com/personal/Hans_Boehm/gc/leak.html),
|
| 92 |
+
as is a fairly sophisticated string package "cord" that makes use of the
|
| 93 |
+
collector. (See doc/README.cords and H.-J. Boehm, R. Atkinson, and M. Plass,
|
| 94 |
+
"Ropes: An Alternative to Strings", Software Practice and Experience 25, 12
|
| 95 |
+
(December 1995), pp. 1315-1330. This is very similar to the "rope" package
|
| 96 |
+
in Xerox Cedar, or the "rope" package in the SGI STL or the g++ distribution.)
|
| 97 |
+
|
| 98 |
+
Further collector documantation can be found at
|
| 99 |
+
|
| 100 |
+
http://www.hpl.hp.com/personal/Hans_Boehm/gc
|
| 101 |
+
|
| 102 |
+
|
| 103 |
+
GENERAL DESCRIPTION
|
| 104 |
+
|
| 105 |
+
This is a garbage collecting storage allocator that is intended to be
|
| 106 |
+
used as a plug-in replacement for C's malloc.
|
| 107 |
+
|
| 108 |
+
Since the collector does not require pointers to be tagged, it does not
|
| 109 |
+
attempt to ensure that all inaccessible storage is reclaimed. However,
|
| 110 |
+
in our experience, it is typically more successful at reclaiming unused
|
| 111 |
+
memory than most C programs using explicit deallocation. Unlike manually
|
| 112 |
+
introduced leaks, the amount of unreclaimed memory typically stays
|
| 113 |
+
bounded.
|
| 114 |
+
|
| 115 |
+
In the following, an "object" is defined to be a region of memory allocated
|
| 116 |
+
by the routines described below.
|
| 117 |
+
|
| 118 |
+
Any objects not intended to be collected must be pointed to either
|
| 119 |
+
from other such accessible objects, or from the registers,
|
| 120 |
+
stack, data, or statically allocated bss segments. Pointers from
|
| 121 |
+
the stack or registers may point to anywhere inside an object.
|
| 122 |
+
The same is true for heap pointers if the collector is compiled with
|
| 123 |
+
ALL_INTERIOR_POINTERS defined, or GC_all_interior_pointers is otherwise
|
| 124 |
+
set, as is now the default.
|
| 125 |
+
|
| 126 |
+
Compiling without ALL_INTERIOR_POINTERS may reduce accidental retention
|
| 127 |
+
of garbage objects, by requiring pointers from the heap to to the beginning
|
| 128 |
+
of an object. But this no longer appears to be a significant
|
| 129 |
+
issue for most programs occupying a small fraction of the possible
|
| 130 |
+
address space.
|
| 131 |
+
|
| 132 |
+
There are a number of routines which modify the pointer recognition
|
| 133 |
+
algorithm. GC_register_displacement allows certain interior pointers
|
| 134 |
+
to be recognized even if ALL_INTERIOR_POINTERS is nor defined.
|
| 135 |
+
GC_malloc_ignore_off_page allows some pointers into the middle of large objects
|
| 136 |
+
to be disregarded, greatly reducing the probablility of accidental
|
| 137 |
+
retention of large objects. For most purposes it seems best to compile
|
| 138 |
+
with ALL_INTERIOR_POINTERS and to use GC_malloc_ignore_off_page if
|
| 139 |
+
you get collector warnings from allocations of very large objects.
|
| 140 |
+
See README.debugging for details.
|
| 141 |
+
|
| 142 |
+
WARNING: pointers inside memory allocated by the standard "malloc" are not
|
| 143 |
+
seen by the garbage collector. Thus objects pointed to only from such a
|
| 144 |
+
region may be prematurely deallocated. It is thus suggested that the
|
| 145 |
+
standard "malloc" be used only for memory regions, such as I/O buffers, that
|
| 146 |
+
are guaranteed not to contain pointers to garbage collectable memory.
|
| 147 |
+
Pointers in C language automatic, static, or register variables,
|
| 148 |
+
are correctly recognized. (Note that GC_malloc_uncollectable has semantics
|
| 149 |
+
similar to standard malloc, but allocates objects that are traced by the
|
| 150 |
+
collector.)
|
| 151 |
+
|
| 152 |
+
WARNING: the collector does not always know how to find pointers in data
|
| 153 |
+
areas that are associated with dynamic libraries. This is easy to
|
| 154 |
+
remedy IF you know how to find those data areas on your operating
|
| 155 |
+
system (see GC_add_roots). Code for doing this under SunOS, IRIX 5.X and 6.X,
|
| 156 |
+
HP/UX, Alpha OSF/1, Linux, and win32 is included and used by default. (See
|
| 157 |
+
README.win32 for win32 details.) On other systems pointers from dynamic
|
| 158 |
+
library data areas may not be considered by the collector.
|
| 159 |
+
If you're writing a program that depends on the collector scanning
|
| 160 |
+
dynamic library data areas, it may be a good idea to include at least
|
| 161 |
+
one call to GC_is_visible() to ensure that those areas are visible
|
| 162 |
+
to the collector.
|
| 163 |
+
|
| 164 |
+
Note that the garbage collector does not need to be informed of shared
|
| 165 |
+
read-only data. However if the shared library mechanism can introduce
|
| 166 |
+
discontiguous data areas that may contain pointers, then the collector does
|
| 167 |
+
need to be informed.
|
| 168 |
+
|
| 169 |
+
Signal processing for most signals may be deferred during collection,
|
| 170 |
+
and during uninterruptible parts of the allocation process.
|
| 171 |
+
Like standard ANSI C mallocs, by default it is unsafe to invoke
|
| 172 |
+
malloc (and other GC routines) from a signal handler while another
|
| 173 |
+
malloc call may be in progress. Removing -DNO_SIGNALS from Makefile
|
| 174 |
+
attempts to remedy that. But that may not be reliable with a compiler that
|
| 175 |
+
substantially reorders memory operations inside GC_malloc.
|
| 176 |
+
|
| 177 |
+
The allocator/collector can also be configured for thread-safe operation.
|
| 178 |
+
(Full signal safety can also be achieved, but only at the cost of two system
|
| 179 |
+
calls per malloc, which is usually unacceptable.)
|
| 180 |
+
WARNING: the collector does not guarantee to scan thread-local storage
|
| 181 |
+
(e.g. of the kind accessed with pthread_getspecific()). The collector
|
| 182 |
+
does scan thread stacks, though, so generally the best solution is to
|
| 183 |
+
ensure that any pointers stored in thread-local storage are also
|
| 184 |
+
stored on the thread's stack for the duration of their lifetime.
|
| 185 |
+
(This is arguably a longstanding bug, but it hasn't been fixed yet.)
|
| 186 |
+
|
| 187 |
+
INSTALLATION AND PORTABILITY
|
| 188 |
+
|
| 189 |
+
As distributed, the collector operates silently
|
| 190 |
+
In the event of problems, this can usually be changed by defining the
|
| 191 |
+
GC_PRINT_STATS or GC_PRINT_VERBOSE_STATS environment variables. This
|
| 192 |
+
will result in a few lines of descriptive output for each collection.
|
| 193 |
+
(The given statistics exhibit a few peculiarities.
|
| 194 |
+
Things don't appear to add up for a variety of reasons, most notably
|
| 195 |
+
fragmentation losses. These are probably much more significant for the
|
| 196 |
+
contrived program "test.c" than for your application.)
|
| 197 |
+
|
| 198 |
+
On most Un*x-like platforms, the collector can be built either using a
|
| 199 |
+
GNU autoconf-based build infrastructure (type "configure; make" in the
|
| 200 |
+
simplest case), or with a classic makefile by itself (type
|
| 201 |
+
"cp Makefile.direct Makefile; make"). Here we focus on the latter option.
|
| 202 |
+
On other platforms, typically only the latter option is available, though
|
| 203 |
+
with a different supplied Makefile.)
|
| 204 |
+
|
| 205 |
+
Typing "make test" nstead of "make" will automatically build the collector
|
| 206 |
+
and then run setjmp_test and gctest. Setjmp_test will give you information
|
| 207 |
+
about configuring the collector, which is useful primarily if you have
|
| 208 |
+
a machine that's not already supported. Gctest is a somewhat superficial
|
| 209 |
+
test of collector functionality. Failure is indicated by a core dump or
|
| 210 |
+
a message to the effect that the collector is broken. Gctest takes about
|
| 211 |
+
a second to two to run on reasonable 2007 vintage desktops.
|
| 212 |
+
It may use up to about 30MB of memory. (The
|
| 213 |
+
multi-threaded version will use more. 64-bit versions may use more.)
|
| 214 |
+
"Make test" will also, as its last step, attempt to build and test the
|
| 215 |
+
"cord" string library.)
|
| 216 |
+
|
| 217 |
+
The Makefile will generate a library gc.a which you should link against.
|
| 218 |
+
Typing "make cords" will add the cord library to gc.a.
|
| 219 |
+
Note that this requires an ANSI C compiler.
|
| 220 |
+
|
| 221 |
+
It is suggested that if you need to replace a piece of the collector
|
| 222 |
+
(e.g. GC_mark_rts.c) you simply list your version ahead of gc.a on the
|
| 223 |
+
ld command line, rather than replacing the one in gc.a. (This will
|
| 224 |
+
generate numerous warnings under some versions of AIX, but it still
|
| 225 |
+
works.)
|
| 226 |
+
|
| 227 |
+
All include files that need to be used by clients will be put in the
|
| 228 |
+
include subdirectory. (Normally this is just gc.h. "Make cords" adds
|
| 229 |
+
"cord.h" and "ec.h".)
|
| 230 |
+
|
| 231 |
+
The collector currently is designed to run essentially unmodified on
|
| 232 |
+
machines that use a flat 32-bit or 64-bit address space.
|
| 233 |
+
That includes the vast majority of Workstations and X86 (X >= 3) PCs.
|
| 234 |
+
(The list here was deleted because it was getting too long and constantly
|
| 235 |
+
out of date.)
|
| 236 |
+
|
| 237 |
+
In a few cases (Amiga, OS/2, Win32, MacOS) a separate makefile
|
| 238 |
+
or equivalent is supplied. Many of these have separate README.system
|
| 239 |
+
files.
|
| 240 |
+
|
| 241 |
+
Dynamic libraries are completely supported only under SunOS/Solaris,
|
| 242 |
+
(and even that support is not functional on the last Sun 3 release),
|
| 243 |
+
Linux, FreeBSD, NetBSD, IRIX 5&6, HP/UX, Win32 (not Win32S) and OSF/1
|
| 244 |
+
on DEC AXP machines plus perhaps a few others listed near the top
|
| 245 |
+
of dyn_load.c. On other machines we recommend that you do one of
|
| 246 |
+
the following:
|
| 247 |
+
|
| 248 |
+
1) Add dynamic library support (and send us the code).
|
| 249 |
+
2) Use static versions of the libraries.
|
| 250 |
+
3) Arrange for dynamic libraries to use the standard malloc.
|
| 251 |
+
This is still dangerous if the library stores a pointer to a
|
| 252 |
+
garbage collected object. But nearly all standard interfaces
|
| 253 |
+
prohibit this, because they deal correctly with pointers
|
| 254 |
+
to stack allocated objects. (Strtok is an exception. Don't
|
| 255 |
+
use it.)
|
| 256 |
+
|
| 257 |
+
In all cases we assume that pointer alignment is consistent with that
|
| 258 |
+
enforced by the standard C compilers. If you use a nonstandard compiler
|
| 259 |
+
you may have to adjust the alignment parameters defined in gc_priv.h.
|
| 260 |
+
Note that this may also be an issue with packed records/structs, if those
|
| 261 |
+
enforce less alignment for pointers.
|
| 262 |
+
|
| 263 |
+
A port to a machine that is not byte addressed, or does not use 32 bit
|
| 264 |
+
or 64 bit addresses will require a major effort. A port to plain MSDOS
|
| 265 |
+
or win16 is hard.
|
| 266 |
+
|
| 267 |
+
For machines not already mentioned, or for nonstandard compilers,
|
| 268 |
+
some porting suggestions are provided in the "porting.html" file.
|
| 269 |
+
|
| 270 |
+
THE C INTERFACE TO THE ALLOCATOR
|
| 271 |
+
|
| 272 |
+
The following routines are intended to be directly called by the user.
|
| 273 |
+
Note that usually only GC_malloc is necessary. GC_clear_roots and GC_add_roots
|
| 274 |
+
calls may be required if the collector has to trace from nonstandard places
|
| 275 |
+
(e.g. from dynamic library data areas on a machine on which the
|
| 276 |
+
collector doesn't already understand them.) On some machines, it may
|
| 277 |
+
be desirable to set GC_stacktop to a good approximation of the stack base.
|
| 278 |
+
(This enhances code portability on HP PA machines, since there is no
|
| 279 |
+
good way for the collector to compute this value.) Client code may include
|
| 280 |
+
"gc.h", which defines all of the following, plus many others.
|
| 281 |
+
|
| 282 |
+
1) GC_malloc(nbytes)
|
| 283 |
+
- allocate an object of size nbytes. Unlike malloc, the object is
|
| 284 |
+
cleared before being returned to the user. Gc_malloc will
|
| 285 |
+
invoke the garbage collector when it determines this to be appropriate.
|
| 286 |
+
GC_malloc may return 0 if it is unable to acquire sufficient
|
| 287 |
+
space from the operating system. This is the most probable
|
| 288 |
+
consequence of running out of space. Other possible consequences
|
| 289 |
+
are that a function call will fail due to lack of stack space,
|
| 290 |
+
or that the collector will fail in other ways because it cannot
|
| 291 |
+
maintain its internal data structures, or that a crucial system
|
| 292 |
+
process will fail and take down the machine. Most of these
|
| 293 |
+
possibilities are independent of the malloc implementation.
|
| 294 |
+
|
| 295 |
+
2) GC_malloc_atomic(nbytes)
|
| 296 |
+
- allocate an object of size nbytes that is guaranteed not to contain any
|
| 297 |
+
pointers. The returned object is not guaranteed to be cleared.
|
| 298 |
+
(Can always be replaced by GC_malloc, but results in faster collection
|
| 299 |
+
times. The collector will probably run faster if large character
|
| 300 |
+
arrays, etc. are allocated with GC_malloc_atomic than if they are
|
| 301 |
+
statically allocated.)
|
| 302 |
+
|
| 303 |
+
3) GC_realloc(object, new_size)
|
| 304 |
+
- change the size of object to be new_size. Returns a pointer to the
|
| 305 |
+
new object, which may, or may not, be the same as the pointer to
|
| 306 |
+
the old object. The new object is taken to be atomic iff the old one
|
| 307 |
+
was. If the new object is composite and larger than the original object,
|
| 308 |
+
then the newly added bytes are cleared (we hope). This is very likely
|
| 309 |
+
to allocate a new object, unless MERGE_SIZES is defined in gc_priv.h.
|
| 310 |
+
Even then, it is likely to recycle the old object only if the object
|
| 311 |
+
is grown in small additive increments (which, we claim, is generally bad
|
| 312 |
+
coding practice.)
|
| 313 |
+
|
| 314 |
+
4) GC_free(object)
|
| 315 |
+
- explicitly deallocate an object returned by GC_malloc or
|
| 316 |
+
GC_malloc_atomic. Not necessary, but can be used to minimize
|
| 317 |
+
collections if performance is critical. Probably a performance
|
| 318 |
+
loss for very small objects (<= 8 bytes).
|
| 319 |
+
|
| 320 |
+
5) GC_expand_hp(bytes)
|
| 321 |
+
- Explicitly increase the heap size. (This is normally done automatically
|
| 322 |
+
if a garbage collection failed to GC_reclaim enough memory. Explicit
|
| 323 |
+
calls to GC_expand_hp may prevent unnecessarily frequent collections at
|
| 324 |
+
program startup.)
|
| 325 |
+
|
| 326 |
+
6) GC_malloc_ignore_off_page(bytes)
|
| 327 |
+
- identical to GC_malloc, but the client promises to keep a pointer to
|
| 328 |
+
the somewhere within the first 256 bytes of the object while it is
|
| 329 |
+
live. (This pointer should nortmally be declared volatile to prevent
|
| 330 |
+
interference from compiler optimizations.) This is the recommended
|
| 331 |
+
way to allocate anything that is likely to be larger than 100Kbytes
|
| 332 |
+
or so. (GC_malloc may result in failure to reclaim such objects.)
|
| 333 |
+
|
| 334 |
+
7) GC_set_warn_proc(proc)
|
| 335 |
+
- Can be used to redirect warnings from the collector. Such warnings
|
| 336 |
+
should be rare, and should not be ignored during code development.
|
| 337 |
+
|
| 338 |
+
8) GC_enable_incremental()
|
| 339 |
+
- Enables generational and incremental collection. Useful for large
|
| 340 |
+
heaps on machines that provide access to page dirty information.
|
| 341 |
+
Some dirty bit implementations may interfere with debugging
|
| 342 |
+
(by catching address faults) and place restrictions on heap arguments
|
| 343 |
+
to system calls (since write faults inside a system call may not be
|
| 344 |
+
handled well).
|
| 345 |
+
|
| 346 |
+
9) Several routines to allow for registration of finalization code.
|
| 347 |
+
User supplied finalization code may be invoked when an object becomes
|
| 348 |
+
unreachable. To call (*f)(obj, x) when obj becomes inaccessible, use
|
| 349 |
+
GC_register_finalizer(obj, f, x, 0, 0);
|
| 350 |
+
For more sophisticated uses, and for finalization ordering issues,
|
| 351 |
+
see gc.h.
|
| 352 |
+
|
| 353 |
+
The global variable GC_free_space_divisor may be adjusted up from its
|
| 354 |
+
default value of 4 to use less space and more collection time, or down for
|
| 355 |
+
the opposite effect. Setting it to 1 or 0 will effectively disable collections
|
| 356 |
+
and cause all allocations to simply grow the heap.
|
| 357 |
+
|
| 358 |
+
The variable GC_non_gc_bytes, which is normally 0, may be changed to reflect
|
| 359 |
+
the amount of memory allocated by the above routines that should not be
|
| 360 |
+
considered as a candidate for collection. Careless use may, of course, result
|
| 361 |
+
in excessive memory consumption.
|
| 362 |
+
|
| 363 |
+
Some additional tuning is possible through the parameters defined
|
| 364 |
+
near the top of gc_priv.h.
|
| 365 |
+
|
| 366 |
+
If only GC_malloc is intended to be used, it might be appropriate to define:
|
| 367 |
+
|
| 368 |
+
#define malloc(n) GC_malloc(n)
|
| 369 |
+
#define calloc(m,n) GC_malloc((m)*(n))
|
| 370 |
+
|
| 371 |
+
For small pieces of VERY allocation intensive code, gc_inl.h
|
| 372 |
+
includes some allocation macros that may be used in place of GC_malloc
|
| 373 |
+
and friends.
|
| 374 |
+
|
| 375 |
+
All externally visible names in the garbage collector start with "GC_".
|
| 376 |
+
To avoid name conflicts, client code should avoid this prefix, except when
|
| 377 |
+
accessing garbage collector routines or variables.
|
| 378 |
+
|
| 379 |
+
There are provisions for allocation with explicit type information.
|
| 380 |
+
This is rarely necessary. Details can be found in gc_typed.h.
|
| 381 |
+
|
| 382 |
+
THE C++ INTERFACE TO THE ALLOCATOR:
|
| 383 |
+
|
| 384 |
+
The Ellis-Hull C++ interface to the collector is included in
|
| 385 |
+
the collector distribution. If you intend to use this, type
|
| 386 |
+
"make c++" after the initial build of the collector is complete.
|
| 387 |
+
See gc_cpp.h for the definition of the interface. This interface
|
| 388 |
+
tries to approximate the Ellis-Detlefs C++ garbage collection
|
| 389 |
+
proposal without compiler changes.
|
| 390 |
+
|
| 391 |
+
Very often it will also be necessary to use gc_allocator.h and the
|
| 392 |
+
allocator declared there to construct STL data structures. Otherwise
|
| 393 |
+
subobjects of STL data structures wil be allcoated using a system
|
| 394 |
+
allocator, and objects they refer to may be prematurely collected.
|
| 395 |
+
|
| 396 |
+
USE AS LEAK DETECTOR:
|
| 397 |
+
|
| 398 |
+
The collector may be used to track down leaks in C programs that are
|
| 399 |
+
intended to run with malloc/free (e.g. code with extreme real-time or
|
| 400 |
+
portability constraints). To do so define FIND_LEAK in Makefile
|
| 401 |
+
This will cause the collector to invoke the report_leak
|
| 402 |
+
routine defined near the top of reclaim.c whenever an inaccessible
|
| 403 |
+
object is found that has not been explicitly freed. Such objects will
|
| 404 |
+
also be automatically reclaimed.
|
| 405 |
+
If all objects are allocated with GC_DEBUG_MALLOC (see next section), then
|
| 406 |
+
the default version of report_leak will report at least the source file and
|
| 407 |
+
line number at which the leaked object was allocated. This may sometimes be
|
| 408 |
+
sufficient. (On a few machines, it will also report a cryptic stack trace.
|
| 409 |
+
If this is not symbolic, it can somethimes be called into a sympolic stack
|
| 410 |
+
trace by invoking program "foo" with "callprocs foo". Callprocs is a short
|
| 411 |
+
shell script that invokes adb to expand program counter values to symbolic
|
| 412 |
+
addresses. It was largely supplied by Scott Schwartz.)
|
| 413 |
+
Note that the debugging facilities described in the next section can
|
| 414 |
+
sometimes be slightly LESS effective in leak finding mode, since in
|
| 415 |
+
leak finding mode, GC_debug_free actually results in reuse of the object.
|
| 416 |
+
(Otherwise the object is simply marked invalid.) Also note that the test
|
| 417 |
+
program is not designed to run meaningfully in FIND_LEAK mode.
|
| 418 |
+
Use "make gc.a" to build the collector.
|
| 419 |
+
|
| 420 |
+
DEBUGGING FACILITIES:
|
| 421 |
+
|
| 422 |
+
The routines GC_debug_malloc, GC_debug_malloc_atomic, GC_debug_realloc,
|
| 423 |
+
and GC_debug_free provide an alternate interface to the collector, which
|
| 424 |
+
provides some help with memory overwrite errors, and the like.
|
| 425 |
+
Objects allocated in this way are annotated with additional
|
| 426 |
+
information. Some of this information is checked during garbage
|
| 427 |
+
collections, and detected inconsistencies are reported to stderr.
|
| 428 |
+
|
| 429 |
+
Simple cases of writing past the end of an allocated object should
|
| 430 |
+
be caught if the object is explicitly deallocated, or if the
|
| 431 |
+
collector is invoked while the object is live. The first deallocation
|
| 432 |
+
of an object will clear the debugging info associated with an
|
| 433 |
+
object, so accidentally repeated calls to GC_debug_free will report the
|
| 434 |
+
deallocation of an object without debugging information. Out of
|
| 435 |
+
memory errors will be reported to stderr, in addition to returning
|
| 436 |
+
NIL.
|
| 437 |
+
|
| 438 |
+
GC_debug_malloc checking during garbage collection is enabled
|
| 439 |
+
with the first call to GC_debug_malloc. This will result in some
|
| 440 |
+
slowdown during collections. If frequent heap checks are desired,
|
| 441 |
+
this can be achieved by explicitly invoking GC_gcollect, e.g. from
|
| 442 |
+
the debugger.
|
| 443 |
+
|
| 444 |
+
GC_debug_malloc allocated objects should not be passed to GC_realloc
|
| 445 |
+
or GC_free, and conversely. It is however acceptable to allocate only
|
| 446 |
+
some objects with GC_debug_malloc, and to use GC_malloc for other objects,
|
| 447 |
+
provided the two pools are kept distinct. In this case, there is a very
|
| 448 |
+
low probablility that GC_malloc allocated objects may be misidentified as
|
| 449 |
+
having been overwritten. This should happen with probability at most
|
| 450 |
+
one in 2**32. This probability is zero if GC_debug_malloc is never called.
|
| 451 |
+
|
| 452 |
+
GC_debug_malloc, GC_malloc_atomic, and GC_debug_realloc take two
|
| 453 |
+
additional trailing arguments, a string and an integer. These are not
|
| 454 |
+
interpreted by the allocator. They are stored in the object (the string is
|
| 455 |
+
not copied). If an error involving the object is detected, they are printed.
|
| 456 |
+
|
| 457 |
+
The macros GC_MALLOC, GC_MALLOC_ATOMIC, GC_REALLOC, GC_FREE, and
|
| 458 |
+
GC_REGISTER_FINALIZER are also provided. These require the same arguments
|
| 459 |
+
as the corresponding (nondebugging) routines. If gc.h is included
|
| 460 |
+
with GC_DEBUG defined, they call the debugging versions of these
|
| 461 |
+
functions, passing the current file name and line number as the two
|
| 462 |
+
extra arguments, where appropriate. If gc.h is included without GC_DEBUG
|
| 463 |
+
defined, then all these macros will instead be defined to their nondebugging
|
| 464 |
+
equivalents. (GC_REGISTER_FINALIZER is necessary, since pointers to
|
| 465 |
+
objects with debugging information are really pointers to a displacement
|
| 466 |
+
of 16 bytes form the object beginning, and some translation is necessary
|
| 467 |
+
when finalization routines are invoked. For details, about what's stored
|
| 468 |
+
in the header, see the definition of the type oh in debug_malloc.c)
|
| 469 |
+
|
| 470 |
+
INCREMENTAL/GENERATIONAL COLLECTION:
|
| 471 |
+
|
| 472 |
+
The collector normally interrupts client code for the duration of
|
| 473 |
+
a garbage collection mark phase. This may be unacceptable if interactive
|
| 474 |
+
response is needed for programs with large heaps. The collector
|
| 475 |
+
can also run in a "generational" mode, in which it usually attempts to
|
| 476 |
+
collect only objects allocated since the last garbage collection.
|
| 477 |
+
Furthermore, in this mode, garbage collections run mostly incrementally,
|
| 478 |
+
with a small amount of work performed in response to each of a large number of
|
| 479 |
+
GC_malloc requests.
|
| 480 |
+
|
| 481 |
+
This mode is enabled by a call to GC_enable_incremental().
|
| 482 |
+
|
| 483 |
+
Incremental and generational collection is effective in reducing
|
| 484 |
+
pause times only if the collector has some way to tell which objects
|
| 485 |
+
or pages have been recently modified. The collector uses two sources
|
| 486 |
+
of information:
|
| 487 |
+
|
| 488 |
+
1. Information provided by the VM system. This may be provided in
|
| 489 |
+
one of several forms. Under Solaris 2.X (and potentially under other
|
| 490 |
+
similar systems) information on dirty pages can be read from the
|
| 491 |
+
/proc file system. Under other systems (currently SunOS4.X) it is
|
| 492 |
+
possible to write-protect the heap, and catch the resulting faults.
|
| 493 |
+
On these systems we require that system calls writing to the heap
|
| 494 |
+
(other than read) be handled specially by client code.
|
| 495 |
+
See os_dep.c for details.
|
| 496 |
+
|
| 497 |
+
2. Information supplied by the programmer. We define "stubborn"
|
| 498 |
+
objects to be objects that are rarely changed. Such an object
|
| 499 |
+
can be allocated (and enabled for writing) with GC_malloc_stubborn.
|
| 500 |
+
Once it has been initialized, the collector should be informed with
|
| 501 |
+
a call to GC_end_stubborn_change. Subsequent writes that store
|
| 502 |
+
pointers into the object must be preceded by a call to
|
| 503 |
+
GC_change_stubborn.
|
| 504 |
+
|
| 505 |
+
This mechanism performs best for objects that are written only for
|
| 506 |
+
initialization, and such that only one stubborn object is writable
|
| 507 |
+
at once. It is typically not worth using for short-lived
|
| 508 |
+
objects. Stubborn objects are treated less efficiently than pointerfree
|
| 509 |
+
(atomic) objects.
|
| 510 |
+
|
| 511 |
+
A rough rule of thumb is that, in the absence of VM information, garbage
|
| 512 |
+
collection pauses are proportional to the amount of pointerful storage
|
| 513 |
+
plus the amount of modified "stubborn" storage that is reachable during
|
| 514 |
+
the collection.
|
| 515 |
+
|
| 516 |
+
Initial allocation of stubborn objects takes longer than allocation
|
| 517 |
+
of other objects, since other data structures need to be maintained.
|
| 518 |
+
|
| 519 |
+
We recommend against random use of stubborn objects in client
|
| 520 |
+
code, since bugs caused by inappropriate writes to stubborn objects
|
| 521 |
+
are likely to be very infrequently observed and hard to trace.
|
| 522 |
+
However, their use may be appropriate in a few carefully written
|
| 523 |
+
library routines that do not make the objects themselves available
|
| 524 |
+
for writing by client code.
|
| 525 |
+
|
| 526 |
+
|
| 527 |
+
BUGS:
|
| 528 |
+
|
| 529 |
+
Any memory that does not have a recognizable pointer to it will be
|
| 530 |
+
reclaimed. Exclusive-or'ing forward and backward links in a list
|
| 531 |
+
doesn't cut it.
|
| 532 |
+
Some C optimizers may lose the last undisguised pointer to a memory
|
| 533 |
+
object as a consequence of clever optimizations. This has almost
|
| 534 |
+
never been observed in practice. Send mail to boehm@acm.org
|
| 535 |
+
for suggestions on how to fix your compiler.
|
| 536 |
+
This is not a real-time collector. In the standard configuration,
|
| 537 |
+
percentage of time required for collection should be constant across
|
| 538 |
+
heap sizes. But collection pauses will increase for larger heaps.
|
| 539 |
+
They will decrease with the number of processors if parallel marking
|
| 540 |
+
is enabled.
|
| 541 |
+
(On 2007 vintage machines, GC times may be on the order of 5 msecs
|
| 542 |
+
per MB of accessible memory that needs to be scanned and processor.
|
| 543 |
+
Your mileage may vary.) The incremental/generational collection facility
|
| 544 |
+
may help in some cases.
|
| 545 |
+
Please address bug reports to boehm@acm.org. If you are
|
| 546 |
+
contemplating a major addition, you might also send mail to ask whether
|
| 547 |
+
it's already been done (or whether we tried and discarded it).
|
| 548 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/doc/README.amiga
ADDED
|
@@ -0,0 +1,322 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
===========================================================================
|
| 2 |
+
Kjetil S. Matheussen's notes (28-11-2000)
|
| 3 |
+
===========================================================================
|
| 4 |
+
Compiles under SAS/C again. Should allso still compile under other
|
| 5 |
+
amiga compilers without big changes. I haven't checked if it still
|
| 6 |
+
works under gcc, because I don't have gcc for amiga. But I have
|
| 7 |
+
updated 'Makefile', and hope it compiles fine.
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
WHATS NEW:
|
| 11 |
+
|
| 12 |
+
1.
|
| 13 |
+
Made a pretty big effort in preventing GCs allocating-functions from returning
|
| 14 |
+
chip-mem.
|
| 15 |
+
|
| 16 |
+
The lower part of the new file AmigaOS.c does this in various ways, mainly by
|
| 17 |
+
wrapping GC_malloc, GC_malloc_atomic, GC_malloc_uncollectable,
|
| 18 |
+
GC_malloc_atomic_uncollectable, GC_malloc_stubborn, GC_malloc_ignore_off_page
|
| 19 |
+
and GC_malloc_atomic_ignore_off_page. GC_realloc is allso wrapped, but
|
| 20 |
+
doesn't do the same effort in preventing to return chip-mem.
|
| 21 |
+
Other allocating-functions (f.ex. GC_*_typed_) can probably be
|
| 22 |
+
used without any problems, but beware that the warn hook will not be called.
|
| 23 |
+
In case of problems, don't define GC_AMIGA_FASTALLOC.
|
| 24 |
+
|
| 25 |
+
Programs using more time actually using the memory allocated
|
| 26 |
+
(instead of just allocate and free rapidly) have
|
| 27 |
+
the most to earn on this, but even gctest now normally runs twice
|
| 28 |
+
as fast and uses less memory, on my poor 8MB machine.
|
| 29 |
+
|
| 30 |
+
The changes have only effect when there is no more
|
| 31 |
+
fast-mem left. But with the way GC works, it
|
| 32 |
+
could happen quite often. Beware that an atexit handler had to be added,
|
| 33 |
+
so using the abort() function will make a big memory-loss.
|
| 34 |
+
If you absolutely must call abort() instead of exit(), try calling
|
| 35 |
+
the GC_amiga_free_all_mem function before abort().
|
| 36 |
+
|
| 37 |
+
New amiga-spesific compilation flags:
|
| 38 |
+
|
| 39 |
+
GC_AMIGA_FASTALLOC - By NOT defining this option, GC will work like before,
|
| 40 |
+
it will not try to force fast-mem out of the OS, and
|
| 41 |
+
it will use normal calloc for allocation, and the rest
|
| 42 |
+
of the following flags will have no effect.
|
| 43 |
+
|
| 44 |
+
GC_AMIGA_ONLYFAST - Makes GC never to return chip-mem. GC_AMIGA_RETRY have
|
| 45 |
+
no effect if this flag is set.
|
| 46 |
+
|
| 47 |
+
GC_AMIGA_GC - If gc returns NULL, do a GC_gcollect, and try again. This
|
| 48 |
+
usually is a success with the standard GC configuration.
|
| 49 |
+
It is allso the most important flag to set to prevent
|
| 50 |
+
GC from returning chip-mem. Beware that it slows down a lot
|
| 51 |
+
when a program is rapidly allocating/deallocating when
|
| 52 |
+
theres either very little fast-memory left or verly little
|
| 53 |
+
chip-memory left. Its not a very common situation, but gctest
|
| 54 |
+
sometimes (very rare) use many minutes because of this.
|
| 55 |
+
|
| 56 |
+
GC_AMIGA_RETRY - If gc succeed allocating memory, but it is chip-mem,
|
| 57 |
+
try again and see if it is fast-mem. Most of the time,
|
| 58 |
+
it will actually return fast-mem for the second try.
|
| 59 |
+
I have set max number of retries to 9 or size/5000. You
|
| 60 |
+
can change this if you like. (see GC_amiga_rec_alloc())
|
| 61 |
+
|
| 62 |
+
GC_AMIGA_PRINTSTATS - Gather some statistics during the execution of a
|
| 63 |
+
program, and prints out the info when the atexit-handler
|
| 64 |
+
is called.
|
| 65 |
+
|
| 66 |
+
My reccomendation is to set all this flags, except GC_AMIGA_PRINTSTATS and
|
| 67 |
+
GC_AMIGA_ONLYFAST.
|
| 68 |
+
|
| 69 |
+
If your program demands high response-time, you should
|
| 70 |
+
not define GC_AMIGA_GC, and possible allso define GC_AMIGA_ONLYFAST.
|
| 71 |
+
GC_AMIGA_RETRY does not seem to slow down much.
|
| 72 |
+
|
| 73 |
+
Allso, when compiling up programs, and GC_AMIGA_FASTALLOC was not defined when
|
| 74 |
+
compilling gc, you can define GC_AMIGA_MAKINGLIB to avoid having these allocation-
|
| 75 |
+
functions wrapped. (see gc.h)
|
| 76 |
+
|
| 77 |
+
Note that GC_realloc must not be called before any of
|
| 78 |
+
the other above mentioned allocating-functions have been called. (shouldn't be
|
| 79 |
+
any programs doing so either, I hope).
|
| 80 |
+
|
| 81 |
+
Another note. The allocation-function is wrapped when defining
|
| 82 |
+
GC_AMIGA_FASTALLOC by letting the function go thru the new
|
| 83 |
+
GC_amiga_allocwrapper_do function-pointer (see gc.h). Means that
|
| 84 |
+
sending function-pointers, such as GC_malloc, GC_malloc_atomic, etc.,
|
| 85 |
+
for later to be called like f.ex this, (*GC_malloc_functionpointer)(size),
|
| 86 |
+
will not wrap the function. This is normally not a big problem, unless
|
| 87 |
+
all allocation function is called like this, which will cause the
|
| 88 |
+
atexit un-allocating function never to be called. Then you either
|
| 89 |
+
have to manually add the atexit handler, or call the allocation-
|
| 90 |
+
functions function-pointer functions like this;
|
| 91 |
+
(*GC_amiga_allocwrapper_do)(size,GC_malloc_functionpointer).
|
| 92 |
+
There are probably better ways this problem could be handled, unfortunately,
|
| 93 |
+
I didn't find any without rewriting or replacing a lot of the GC-code, which
|
| 94 |
+
I really didn't want to. (Making new GC_malloc_* functions, and just
|
| 95 |
+
define f.ex GC_malloc as GC_amiga_malloc should allso work).
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
New amiga-spesific function:
|
| 99 |
+
|
| 100 |
+
void GC_amiga_set_toany(void (*func)(void));
|
| 101 |
+
|
| 102 |
+
'func' is a function that will be called right before gc has to change
|
| 103 |
+
allocation-method from MEMF_FAST to MEMF_ANY. Ie. when it is likely
|
| 104 |
+
it will return chip-mem.
|
| 105 |
+
|
| 106 |
+
|
| 107 |
+
2. A few small compiler-spesific additions to make it compile with SAS/C again.
|
| 108 |
+
|
| 109 |
+
3. Updated and rewritten the smakefile, so that it works again and that
|
| 110 |
+
the "unnecesarry" 'SCOPTIONS' files could be removed. Allso included
|
| 111 |
+
the cord-smakefile stuff in the main smakefile, so that the cord smakefile
|
| 112 |
+
could be removed too. By writing smake -f Smakefile.smk, both gc.lib and
|
| 113 |
+
cord.lib will be made.
|
| 114 |
+
|
| 115 |
+
|
| 116 |
+
|
| 117 |
+
STILL MISSING:
|
| 118 |
+
|
| 119 |
+
Programs can not be started from workbench, at least not for SAS/C. (Martin
|
| 120 |
+
Tauchmanns note about that it now works with workbench is definitely wrong
|
| 121 |
+
when concerning SAS/C). I guess it works if you use the old "#if 0'ed"-code,
|
| 122 |
+
but I haven't tested it. I think the reason for MT to replace the
|
| 123 |
+
"#if 0'ed"-code was only because it was a bit to SAS/C-spesific. But I
|
| 124 |
+
don't know. An iconx-script solves this problem anyway.
|
| 125 |
+
|
| 126 |
+
|
| 127 |
+
BEWARE!
|
| 128 |
+
|
| 129 |
+
-To run gctest, set the stack to around 200000 bytes first.
|
| 130 |
+
-SAS/C-spesific: cord will crash if you compile gc.lib with
|
| 131 |
+
either parm=reg or parm=both. (missing legal prototypes for
|
| 132 |
+
function-pointers someplace is the reason I guess.).
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
tested with software: Radium, http://www.stud.ifi.uio.no/~ksvalast/radium/
|
| 136 |
+
|
| 137 |
+
tested with hardware: MC68060
|
| 138 |
+
|
| 139 |
+
|
| 140 |
+
-ksvalast@ifi.uio.no
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
===========================================================================
|
| 144 |
+
Martin Tauchmann's notes (1-Apr-99)
|
| 145 |
+
===========================================================================
|
| 146 |
+
|
| 147 |
+
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/>
|
| 148 |
+
Modify the `Makefile`
|
| 149 |
+
CC=cc $(ABI_FLAG)
|
| 150 |
+
to
|
| 151 |
+
CC=gcc $(ABI_FLAG)
|
| 152 |
+
|
| 153 |
+
TECHNICAL NOTES
|
| 154 |
+
|
| 155 |
+
- `GC_get_stack_base()`, `GC_register_data_segments()` works now with every
|
| 156 |
+
C compiler; also Workbench.
|
| 157 |
+
|
| 158 |
+
- Removed AMIGA_SKIP_SEG, but the Code-Segment must not be scanned by GC.
|
| 159 |
+
|
| 160 |
+
|
| 161 |
+
PROBLEMS
|
| 162 |
+
- When the Linker, does`t merge all Code-Segments to an single one. LD of GCC
|
| 163 |
+
do it always.
|
| 164 |
+
|
| 165 |
+
- With ixemul.library V47.3, when an GC program launched from another program
|
| 166 |
+
(example: `Make` or `if_mach M68K AMIGA gctest`), `GC_register_data_segments()`
|
| 167 |
+
found the Segment-List of the caller program.
|
| 168 |
+
Can be fixed, if the run-time initialization code (for C programs, usually *crt0*)
|
| 169 |
+
support `__data` and `__bss`.
|
| 170 |
+
|
| 171 |
+
- PowerPC Amiga currently not supported.
|
| 172 |
+
|
| 173 |
+
- Dynamic libraries (dyn_load.c) not supported.
|
| 174 |
+
|
| 175 |
+
|
| 176 |
+
TESTED WITH SOFTWARE
|
| 177 |
+
|
| 178 |
+
`Optimized Oberon 2 C` (oo2c) <http://cognac.informatik.uni-kl.de/download/index.html>
|
| 179 |
+
|
| 180 |
+
|
| 181 |
+
TESTED WITH HARDWARE
|
| 182 |
+
|
| 183 |
+
MC68030
|
| 184 |
+
|
| 185 |
+
|
| 186 |
+
CONTACT
|
| 187 |
+
|
| 188 |
+
Please, contact me at <martintauchmann@bigfoot.com>, when you change the
|
| 189 |
+
Amiga port. <http://martintauchmann.home.pages.de>
|
| 190 |
+
|
| 191 |
+
===========================================================================
|
| 192 |
+
Michel Schinz's notes
|
| 193 |
+
===========================================================================
|
| 194 |
+
WHO DID WHAT
|
| 195 |
+
|
| 196 |
+
The original Amiga port was made by Jesper Peterson. I (Michel Schinz)
|
| 197 |
+
modified it slightly to reflect the changes made in the new official
|
| 198 |
+
distributions, and to take advantage of the new SAS/C 6.x features. I also
|
| 199 |
+
created a makefile to compile the "cord" package (see the cord
|
| 200 |
+
subdirectory).
|
| 201 |
+
|
| 202 |
+
TECHNICAL NOTES
|
| 203 |
+
|
| 204 |
+
In addition to Jesper's notes, I have the following to say:
|
| 205 |
+
|
| 206 |
+
- Starting with version 4.3, gctest checks to see if the code segment is
|
| 207 |
+
added to the root set or not, and complains if it is. Previous versions
|
| 208 |
+
of this Amiga port added the code segment to the root set, so I tried to
|
| 209 |
+
fix that. The only problem is that, as far as I know, it is impossible to
|
| 210 |
+
know which segments are code segments and which are data segments (there
|
| 211 |
+
are indeed solutions to this problem, like scanning the program on disk
|
| 212 |
+
or patch the LoadSeg functions, but they are rather complicated). The
|
| 213 |
+
solution I have chosen (see os_dep.c) is to test whether the program
|
| 214 |
+
counter is in the segment we are about to add to the root set, and if it
|
| 215 |
+
is, to skip the segment. The problems are that this solution is rather
|
| 216 |
+
awkward and that it works only for one code segment. This means that if
|
| 217 |
+
your program has more than one code segment, all of them but one will be
|
| 218 |
+
added to the root set. This isn't a big problem in fact, since the
|
| 219 |
+
collector will continue to work correctly, but it may be slower.
|
| 220 |
+
|
| 221 |
+
Anyway, the code which decides whether to skip a segment or not can be
|
| 222 |
+
removed simply by not defining AMIGA_SKIP_SEG. But notice that if you do
|
| 223 |
+
so, gctest will complain (it will say that "GC_is_visible produced wrong
|
| 224 |
+
failure indication"). However, it may be useful if you happen to have
|
| 225 |
+
pointers stored in a code segment (you really shouldn't).
|
| 226 |
+
|
| 227 |
+
If anyone has a good solution to the problem of finding, when a program
|
| 228 |
+
is loaded in memory, whether a segment is a code or a data segment,
|
| 229 |
+
please let me know.
|
| 230 |
+
|
| 231 |
+
PROBLEMS
|
| 232 |
+
|
| 233 |
+
If you have any problem with this version, please contact me at
|
| 234 |
+
schinz@alphanet.ch (but do *not* send long files, since we pay for
|
| 235 |
+
every mail!).
|
| 236 |
+
|
| 237 |
+
===========================================================================
|
| 238 |
+
Jesper Peterson's notes
|
| 239 |
+
===========================================================================
|
| 240 |
+
|
| 241 |
+
ADDITIONAL NOTES FOR AMIGA PORT
|
| 242 |
+
|
| 243 |
+
These notes assume some familiarity with Amiga internals.
|
| 244 |
+
|
| 245 |
+
WHY I PORTED TO THE AMIGA
|
| 246 |
+
|
| 247 |
+
The sole reason why I made this port was as a first step in getting
|
| 248 |
+
the Sather(*) language on the Amiga. A port of this language will
|
| 249 |
+
be done as soon as the Sather 1.0 sources are made available to me.
|
| 250 |
+
Given this motivation, the garbage collection (GC) port is rather
|
| 251 |
+
minimal.
|
| 252 |
+
|
| 253 |
+
(*) For information on Sather read the comp.lang.sather newsgroup.
|
| 254 |
+
|
| 255 |
+
LIMITATIONS
|
| 256 |
+
|
| 257 |
+
This port assumes that the startup code linked with target programs
|
| 258 |
+
is that supplied with SAS/C versions 6.0 or later. This allows
|
| 259 |
+
assumptions to be made about where to find the stack base pointer
|
| 260 |
+
and data segments when programs are run from WorkBench, as opposed
|
| 261 |
+
to running from the CLI. The compiler dependent code is all in the
|
| 262 |
+
GC_get_stack_base() and GC_register_data_segments() functions, but
|
| 263 |
+
may spread as I add Amiga specific features.
|
| 264 |
+
|
| 265 |
+
Given that SAS/C was assumed, the port is set up to be built with
|
| 266 |
+
"smake" using the "SMakefile". Compiler options in "SCoptions" can
|
| 267 |
+
be set with "scopts" program. Both "smake" and "scopts" are part of
|
| 268 |
+
the SAS/C commercial development system.
|
| 269 |
+
|
| 270 |
+
In keeping with the porting philosophy outlined above, this port
|
| 271 |
+
will not behave well with Amiga specific code. Especially not inter-
|
| 272 |
+
process comms via messages, and setting up public structures like
|
| 273 |
+
Intuition objects or anything else in the system lists. For the
|
| 274 |
+
time being the use of this library is limited to single threaded
|
| 275 |
+
ANSI/POSIX compliant or near-complient code. (ie. Stick to stdio
|
| 276 |
+
for now). Given this limitation there is currently no mechanism for
|
| 277 |
+
allocating "CHIP" or "PUBLIC" memory under the garbage collector.
|
| 278 |
+
I'll add this after giving it considerable thought. The major
|
| 279 |
+
problem is the entire physical address space may have to me scanned,
|
| 280 |
+
since there is no telling who we may have passed memory to.
|
| 281 |
+
|
| 282 |
+
If you allocate your own stack in client code, you will have to
|
| 283 |
+
assign the pointer plus stack size to GC_stackbottom.
|
| 284 |
+
|
| 285 |
+
The initial stack size of the target program can be compiled in by
|
| 286 |
+
setting the __stack symbol (see SAS documentaion). It can be over-
|
| 287 |
+
ridden from the CLI by running the AmigaDOS "stack" program, or from
|
| 288 |
+
the WorkBench by setting the stack size in the tool types window.
|
| 289 |
+
|
| 290 |
+
SAS/C COMPILER OPTIONS (SCoptions)
|
| 291 |
+
|
| 292 |
+
You may wish to check the "CPU" code option is appropriate for your
|
| 293 |
+
intended target system.
|
| 294 |
+
|
| 295 |
+
Under no circumstances set the "StackExtend" code option in either
|
| 296 |
+
compiling the library or *ANY* client code.
|
| 297 |
+
|
| 298 |
+
All benign compiler warnings have been suppressed. These mainly
|
| 299 |
+
involve lack of prototypes in the code, and dead assignments
|
| 300 |
+
detected by the optimizer.
|
| 301 |
+
|
| 302 |
+
THE GOOD NEWS
|
| 303 |
+
|
| 304 |
+
The library as it stands is compatible with the GigaMem commercial
|
| 305 |
+
virtual memory software, and probably similar PD software.
|
| 306 |
+
|
| 307 |
+
The performance of "gctest" on an Amiga 2630 (68030 @ 25Mhz)
|
| 308 |
+
compares favourably with an HP9000 with similar architecture (a 325
|
| 309 |
+
with a 68030 I think).
|
| 310 |
+
|
| 311 |
+
-----------------------------------------------------------------------
|
| 312 |
+
|
| 313 |
+
The Amiga port has been brought to you by:
|
| 314 |
+
|
| 315 |
+
Jesper Peterson.
|
| 316 |
+
|
| 317 |
+
jep@mtiame.mtia.oz.au (preferred, but 1 week turnaround)
|
| 318 |
+
jep@orca1.vic.design.telecom.au (that's orca<one>, 1 day turnaround)
|
| 319 |
+
|
| 320 |
+
At least one of these addresses should be around for a while, even
|
| 321 |
+
though I don't work for either of the companies involved.
|
| 322 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/doc/README.changes
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
mosesdecoder/jam-files/engine/boehm_gc/doc/README.ews4800
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
GC on EWS4800
|
| 2 |
+
-------------
|
| 3 |
+
|
| 4 |
+
1. About EWS4800
|
| 5 |
+
EWS4800 is 32bit/64bit workstation.
|
| 6 |
+
|
| 7 |
+
Vender: NEC Corporation
|
| 8 |
+
OS: UX/4800 R9.* - R13.* (SystemV R4.2)
|
| 9 |
+
CPU: R4000, R4400, R10000 (MIPS)
|
| 10 |
+
|
| 11 |
+
2. Compiler
|
| 12 |
+
|
| 13 |
+
32bit:
|
| 14 |
+
Use ANSI C compiler.
|
| 15 |
+
CC = /usr/abiccs/bin/cc
|
| 16 |
+
|
| 17 |
+
64bit:
|
| 18 |
+
Use 64bit ANSI C compiler.
|
| 19 |
+
CC = /usr/ccs64/bin/cc
|
| 20 |
+
AR = /usr/ccs64/bin/ar
|
| 21 |
+
|
| 22 |
+
3. ELF file format
|
| 23 |
+
*** Caution: The following infomation is empirical. ***
|
| 24 |
+
|
| 25 |
+
32bit:
|
| 26 |
+
ELF file has an unique format. (See a.out(4) and end(3C).)
|
| 27 |
+
|
| 28 |
+
&_start
|
| 29 |
+
: text segment
|
| 30 |
+
&etext
|
| 31 |
+
DATASTART
|
| 32 |
+
: data segment (initialized)
|
| 33 |
+
&edata
|
| 34 |
+
DATASTART2
|
| 35 |
+
: data segment (uninitialized)
|
| 36 |
+
&end
|
| 37 |
+
|
| 38 |
+
Here, DATASTART and DATASTART2 are macros of GC, and are defined as
|
| 39 |
+
the following equations. (See include/private/gcconfig.h.)
|
| 40 |
+
The algorithm for DATASTART is similar with the function
|
| 41 |
+
GC_SysVGetDataStart() in os_dep.c.
|
| 42 |
+
|
| 43 |
+
DATASTART = ((&etext + 0x3ffff) & ~0x3ffff) + (&etext & 0xffff)
|
| 44 |
+
|
| 45 |
+
Dynamically linked:
|
| 46 |
+
DATASTART2 = (&_gp + 0x8000 + 0x3ffff) & ~0x3ffff
|
| 47 |
+
|
| 48 |
+
Statically linked:
|
| 49 |
+
DATASTART2 = &edata
|
| 50 |
+
|
| 51 |
+
GC has to check addresses both between DATASTART and &edata, and
|
| 52 |
+
between DATASTART2 and &end. If a program accesses between &etext
|
| 53 |
+
and DATASTART, or between &edata and DATASTART2, the segmentation
|
| 54 |
+
error occurs and the program stops.
|
| 55 |
+
|
| 56 |
+
If a program is statically linked, there is not a gap between
|
| 57 |
+
&edata and DATASTART2. The global symbol &_DYNAMIC_LINKING is used
|
| 58 |
+
for the detection.
|
| 59 |
+
|
| 60 |
+
64bit:
|
| 61 |
+
ELF file has a simple format. (See end(3C).)
|
| 62 |
+
|
| 63 |
+
_ftext
|
| 64 |
+
: text segment
|
| 65 |
+
_etext
|
| 66 |
+
_fdata = DATASTART
|
| 67 |
+
: data segment (initialized)
|
| 68 |
+
_edata
|
| 69 |
+
_fbss
|
| 70 |
+
: data segment (uninitialized)
|
| 71 |
+
_end = DATAEND
|
| 72 |
+
|
| 73 |
+
--
|
| 74 |
+
Hironori SAKAMOTO <hsaka@mth.biglobe.ne.jp>
|
| 75 |
+
|
| 76 |
+
|
| 77 |
+
When using the new "configure; make" build process, please
|
| 78 |
+
run configure with the --disable-shared option. "Make check" does not
|
| 79 |
+
yet pass with dynamic libraries. Ther reasons for that are not yet
|
| 80 |
+
understood. (HB, paraphrasing message from Hironori SAKAMOTO.)
|
| 81 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/doc/README.macros
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
The collector uses a large amount of conditional compilation in order to
|
| 2 |
+
deal with platform dependencies. This violates a number of known coding
|
| 3 |
+
standards. On the other hand, it seems to be the only practical way to
|
| 4 |
+
support this many platforms without excessive code duplication.
|
| 5 |
+
|
| 6 |
+
A few guidelines have mostly been followed in order to keep this manageable:
|
| 7 |
+
|
| 8 |
+
1) #if and #ifdef directives are properly indented whenever easily possible.
|
| 9 |
+
All known C compilers allow whitespace between the "#" and the "if" to make
|
| 10 |
+
this possible. ANSI C also allows white space before the "#", though we
|
| 11 |
+
avoid that. It has the known disadvantages that it differs from the normal
|
| 12 |
+
GNU conventions, and that it makes patches larger than otherwise necessary.
|
| 13 |
+
In my opinion, it's still well worth it, for the same reason that we indent
|
| 14 |
+
ordinary "if" statements.
|
| 15 |
+
|
| 16 |
+
2) Whenever possible, tests are performed on the macros defined in gcconfig.h
|
| 17 |
+
instead of directly testing patform-specific predefined macros. This makes it
|
| 18 |
+
relatively easy to adapt to new compilers with a different set of predefined
|
| 19 |
+
macros. Currently these macros generally identify platforms instead of
|
| 20 |
+
features. In many cases, this is a mistake.
|
| 21 |
+
|
| 22 |
+
Many of the tested configuration macros are at least somewhat defined in
|
| 23 |
+
either include/private/gcconfig.h or in Makefile.direct. Here is an attempt
|
| 24 |
+
at defining some of the remainder: (Thanks to Walter Bright for suggesting
|
| 25 |
+
this. This is a work in progress)
|
| 26 |
+
|
| 27 |
+
MACRO EXPLANATION
|
| 28 |
+
----- -----------
|
| 29 |
+
|
| 30 |
+
__DMC__ Always #define'd by the Digital Mars compiler. Expands
|
| 31 |
+
to the compiler version number in hex, i.e. 0x810 is
|
| 32 |
+
version 8.1b0
|
| 33 |
+
|
| 34 |
+
_ENABLE_ARRAYNEW
|
| 35 |
+
#define'd by the Digital Mars C++ compiler when
|
| 36 |
+
operator new[] and delete[] are separately
|
| 37 |
+
overloadable. Used in gc_cpp.h.
|
| 38 |
+
|
| 39 |
+
_MSC_VER Expands to the Visual C++ compiler version. Assumed to
|
| 40 |
+
not be defined for other compilers (at least if they behave
|
| 41 |
+
appreciably differently).
|
| 42 |
+
|
| 43 |
+
_DLL Defined by Visual C++ if dynamic libraries are being built
|
| 44 |
+
or used. Used to test whether __declspec(dllimport) or
|
| 45 |
+
__declspec(dllexport) needs to be added to declarations
|
| 46 |
+
to support the case in which the collector is in a dll.
|
| 47 |
+
|
| 48 |
+
GC_DLL User-settable macro that forces the effect of _DLL. Set
|
| 49 |
+
by gc.h if _DLL is defined and GC_NOT_DLL is undefined.
|
| 50 |
+
This is the macro that is tested internally to determine
|
| 51 |
+
whether the GC is in its own dynamic library. May need
|
| 52 |
+
to be set by clients before including gc.h. Note that
|
| 53 |
+
inside the GC implementation it indicates that the
|
| 54 |
+
collector is in its own dynamic library, should export
|
| 55 |
+
its symbols, etc. But in clients it indicates that the
|
| 56 |
+
GC resides in a different DLL, its entry points should
|
| 57 |
+
be referenced accordingly, and precautions may need to
|
| 58 |
+
be taken to properly deal with statically allocated
|
| 59 |
+
variables in the main program. Used only for MS Windows.
|
| 60 |
+
|
| 61 |
+
GC_NOT_DLL User-settable macro that overrides _DLL, e.g. if dynamic
|
| 62 |
+
libraries are used, but the collector is in a static library.
|
| 63 |
+
|
| 64 |
+
__STDC__ Assumed to be defined only by compilers that understand
|
| 65 |
+
prototypes and other C89 features. Its value is generally
|
| 66 |
+
not used, since we are fine with most nonconforming extensions.
|
| 67 |
+
|
| 68 |
+
SUNOS5SIGS Solaris-like signal handling. This is probably misnamed,
|
| 69 |
+
since it really doesn't guarantee much more than Posix.
|
| 70 |
+
Currently set only for Solaris2.X, HPUX, and DRSNX. Should
|
| 71 |
+
probably be set for some other platforms.
|
| 72 |
+
|
| 73 |
+
PCR Set if the collector is being built as part of the Xerox
|
| 74 |
+
Portable Common Runtime.
|
| 75 |
+
|
| 76 |
+
USE_COMPILER_TLS Assume the existence of __thread-style thread-local
|
| 77 |
+
storage. Set automatically for thread-local allocation with
|
| 78 |
+
the HP/UX vendor compiler. Usable with gcc on sufficiently
|
| 79 |
+
up-to-date ELF platforms.
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/doc/README.rs6000
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
We have so far failed to find a good way to determine the stack base.
|
| 2 |
+
It is highly recommended that GC_stackbottom be set explicitly on program
|
| 3 |
+
startup. The supplied value sometimes causes failure under AIX 4.1, though
|
| 4 |
+
it appears to work under 3.X. HEURISTIC2 seems to work under 4.1, but
|
| 5 |
+
involves a substantial performance penalty, and will fail if there is
|
| 6 |
+
no limit on stack size.
|
| 7 |
+
|
| 8 |
+
There is no thread support. (I assume recent versions of AIX provide
|
| 9 |
+
pthreads? I no longer have access to a machine ...)
|
mosesdecoder/jam-files/engine/boehm_gc/doc/doc.am
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#
|
| 2 |
+
#
|
| 3 |
+
# THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 4 |
+
# OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 5 |
+
#
|
| 6 |
+
# Permission is hereby granted to use or copy this program
|
| 7 |
+
# for any purpose, provided the above notices are retained on all copies.
|
| 8 |
+
# Permission to modify the code and to distribute modified code is granted,
|
| 9 |
+
# provided the above notices are retained, and a notice that the code was
|
| 10 |
+
# modified is included with the above copyright notice.
|
| 11 |
+
#
|
| 12 |
+
# Modified by: Grzegorz Jakacki <jakacki at acm dot org>
|
| 13 |
+
# Modified by: Petter Urkedal <petter.urkedal@nordita.dk>
|
| 14 |
+
|
| 15 |
+
## Process this file with automake to produce Makefile.in.
|
| 16 |
+
|
| 17 |
+
# installed documentation
|
| 18 |
+
#
|
| 19 |
+
dist_pkgdata_DATA = \
|
| 20 |
+
doc/barrett_diagram \
|
| 21 |
+
doc/debugging.html \
|
| 22 |
+
doc/gc.man \
|
| 23 |
+
doc/gcdescr.html \
|
| 24 |
+
doc/README \
|
| 25 |
+
doc/README.amiga \
|
| 26 |
+
doc/README.arm.cross \
|
| 27 |
+
doc/README.autoconf \
|
| 28 |
+
doc/README.changes \
|
| 29 |
+
doc/README.contributors \
|
| 30 |
+
doc/README.cords \
|
| 31 |
+
doc/README.DGUX386 \
|
| 32 |
+
doc/README.dj \
|
| 33 |
+
doc/README.environment \
|
| 34 |
+
doc/README.ews4800 \
|
| 35 |
+
doc/README.hp \
|
| 36 |
+
doc/README.linux \
|
| 37 |
+
doc/README.Mac \
|
| 38 |
+
doc/README.MacOSX \
|
| 39 |
+
doc/README.macros \
|
| 40 |
+
doc/README.OS2 \
|
| 41 |
+
doc/README.rs6000 \
|
| 42 |
+
doc/README.sgi \
|
| 43 |
+
doc/README.solaris2 \
|
| 44 |
+
doc/README.uts \
|
| 45 |
+
doc/README.win32 \
|
| 46 |
+
doc/README.win64 \
|
| 47 |
+
doc/overview.html \
|
| 48 |
+
doc/tree.html \
|
| 49 |
+
doc/leak.html \
|
| 50 |
+
doc/gcinterface.html \
|
| 51 |
+
doc/scale.html \
|
| 52 |
+
doc/README.darwin \
|
| 53 |
+
doc/simple_example.html \
|
| 54 |
+
doc/porting.html
|
| 55 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/doc/gcdescr.html
ADDED
|
@@ -0,0 +1,621 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<HTML>
|
| 2 |
+
<HEAD>
|
| 3 |
+
<TITLE> Conservative GC Algorithmic Overview </TITLE>
|
| 4 |
+
<AUTHOR> Hans-J. Boehm, HP Labs (Some of this was written at SGI)</author>
|
| 5 |
+
</HEAD>
|
| 6 |
+
<BODY>
|
| 7 |
+
<H1> <I>This is under construction, and may always be.</i> </h1>
|
| 8 |
+
<H1> Conservative GC Algorithmic Overview </h1>
|
| 9 |
+
<P>
|
| 10 |
+
This is a description of the algorithms and data structures used in our
|
| 11 |
+
conservative garbage collector. I expect the level of detail to increase
|
| 12 |
+
with time. For a survey of GC algorithms, see for example
|
| 13 |
+
<A HREF="ftp://ftp.cs.utexas.edu/pub/garbage/gcsurvey.ps"> Paul Wilson's
|
| 14 |
+
excellent paper</a>. For an overview of the collector interface,
|
| 15 |
+
see <A HREF="gcinterface.html">here</a>.
|
| 16 |
+
<P>
|
| 17 |
+
This description is targeted primarily at someone trying to understand the
|
| 18 |
+
source code. It specifically refers to variable and function names.
|
| 19 |
+
It may also be useful for understanding the algorithms at a higher level.
|
| 20 |
+
<P>
|
| 21 |
+
The description here assumes that the collector is used in default mode.
|
| 22 |
+
In particular, we assume that it used as a garbage collector, and not just
|
| 23 |
+
a leak detector. We initially assume that it is used in stop-the-world,
|
| 24 |
+
non-incremental mode, though the presence of the incremental collector
|
| 25 |
+
will be apparent in the design.
|
| 26 |
+
We assume the default finalization model, but the code affected by that
|
| 27 |
+
is very localized.
|
| 28 |
+
<H2> Introduction </h2>
|
| 29 |
+
The garbage collector uses a modified mark-sweep algorithm. Conceptually
|
| 30 |
+
it operates roughly in four phases, which are performed occasionally
|
| 31 |
+
as part of a memory allocation:
|
| 32 |
+
|
| 33 |
+
<OL>
|
| 34 |
+
|
| 35 |
+
<LI>
|
| 36 |
+
<I>Preparation</i> Each object has an associated mark bit.
|
| 37 |
+
Clear all mark bits, indicating that all objects
|
| 38 |
+
are potentially unreachable.
|
| 39 |
+
|
| 40 |
+
<LI>
|
| 41 |
+
<I>Mark phase</i> Marks all objects that can be reachable via chains of
|
| 42 |
+
pointers from variables. Often the collector has no real information
|
| 43 |
+
about the location of pointer variables in the heap, so it
|
| 44 |
+
views all static data areas, stacks and registers as potentially containing
|
| 45 |
+
pointers. Any bit patterns that represent addresses inside
|
| 46 |
+
heap objects managed by the collector are viewed as pointers.
|
| 47 |
+
Unless the client program has made heap object layout information
|
| 48 |
+
available to the collector, any heap objects found to be reachable from
|
| 49 |
+
variables are again scanned similarly.
|
| 50 |
+
|
| 51 |
+
<LI>
|
| 52 |
+
<I>Sweep phase</i> Scans the heap for inaccessible, and hence unmarked,
|
| 53 |
+
objects, and returns them to an appropriate free list for reuse. This is
|
| 54 |
+
not really a separate phase; even in non incremental mode this is operation
|
| 55 |
+
is usually performed on demand during an allocation that discovers an empty
|
| 56 |
+
free list. Thus the sweep phase is very unlikely to touch a page that
|
| 57 |
+
would not have been touched shortly thereafter anyway.
|
| 58 |
+
|
| 59 |
+
<LI>
|
| 60 |
+
<I>Finalization phase</i> Unreachable objects which had been registered
|
| 61 |
+
for finalization are enqueued for finalization outside the collector.
|
| 62 |
+
|
| 63 |
+
</ol>
|
| 64 |
+
|
| 65 |
+
<P>
|
| 66 |
+
The remaining sections describe the memory allocation data structures,
|
| 67 |
+
and then the last 3 collection phases in more detail. We conclude by
|
| 68 |
+
outlining some of the additional features implemented in the collector.
|
| 69 |
+
|
| 70 |
+
<H2>Allocation</h2>
|
| 71 |
+
The collector includes its own memory allocator. The allocator obtains
|
| 72 |
+
memory from the system in a platform-dependent way. Under UNIX, it
|
| 73 |
+
uses either <TT>malloc</tt>, <TT>sbrk</tt>, or <TT>mmap</tt>.
|
| 74 |
+
<P>
|
| 75 |
+
Most static data used by the allocator, as well as that needed by the
|
| 76 |
+
rest of the garbage collector is stored inside the
|
| 77 |
+
<TT>_GC_arrays</tt> structure.
|
| 78 |
+
This allows the garbage collector to easily ignore the collectors own
|
| 79 |
+
data structures when it searches for root pointers. Other allocator
|
| 80 |
+
and collector internal data structures are allocated dynamically
|
| 81 |
+
with <TT>GC_scratch_alloc</tt>. <TT>GC_scratch_alloc</tt> does not
|
| 82 |
+
allow for deallocation, and is therefore used only for permanent data
|
| 83 |
+
structures.
|
| 84 |
+
<P>
|
| 85 |
+
The allocator allocates objects of different <I>kinds</i>.
|
| 86 |
+
Different kinds are handled somewhat differently by certain parts
|
| 87 |
+
of the garbage collector. Certain kinds are scanned for pointers,
|
| 88 |
+
others are not. Some may have per-object type descriptors that
|
| 89 |
+
determine pointer locations. Or a specific kind may correspond
|
| 90 |
+
to one specific object layout. Two built-in kinds are uncollectable.
|
| 91 |
+
One (<TT>STUBBORN</tt>) is immutable without special precautions.
|
| 92 |
+
In spite of that, it is very likely that most C clients of the
|
| 93 |
+
collector currently
|
| 94 |
+
use at most two kinds: <TT>NORMAL</tt> and <TT>PTRFREE</tt> objects.
|
| 95 |
+
The <A HREF="http://gcc.gnu.org/java">gcj</a> runtime also makes
|
| 96 |
+
heavy use of a kind (allocated with GC_gcj_malloc) that stores
|
| 97 |
+
type information at a known offset in method tables.
|
| 98 |
+
<P>
|
| 99 |
+
The collector uses a two level allocator. A large block is defined to
|
| 100 |
+
be one larger than half of <TT>HBLKSIZE</tt>, which is a power of 2,
|
| 101 |
+
typically on the order of the page size.
|
| 102 |
+
<P>
|
| 103 |
+
Large block sizes are rounded up to
|
| 104 |
+
the next multiple of <TT>HBLKSIZE</tt> and then allocated by
|
| 105 |
+
<TT>GC_allochblk</tt>. Recent versions of the collector
|
| 106 |
+
use an approximate best fit algorithm by keeping free lists for
|
| 107 |
+
several large block sizes.
|
| 108 |
+
The actual
|
| 109 |
+
implementation of <TT>GC_allochblk</tt>
|
| 110 |
+
is significantly complicated by black-listing issues
|
| 111 |
+
(see below).
|
| 112 |
+
<P>
|
| 113 |
+
Small blocks are allocated in chunks of size <TT>HBLKSIZE</tt>.
|
| 114 |
+
Each chunk is
|
| 115 |
+
dedicated to only one object size and kind. The allocator maintains
|
| 116 |
+
separate free lists for each size and kind of object.
|
| 117 |
+
<P>
|
| 118 |
+
Once a large block is split for use in smaller objects, it can only
|
| 119 |
+
be used for objects of that size, unless the collector discovers a completely
|
| 120 |
+
empty chunk. Completely empty chunks are restored to the appropriate
|
| 121 |
+
large block free list.
|
| 122 |
+
<P>
|
| 123 |
+
In order to avoid allocating blocks for too many distinct object sizes,
|
| 124 |
+
the collector normally does not directly allocate objects of every possible
|
| 125 |
+
request size. Instead request are rounded up to one of a smaller number
|
| 126 |
+
of allocated sizes, for which free lists are maintained. The exact
|
| 127 |
+
allocated sizes are computed on demand, but subject to the constraint
|
| 128 |
+
that they increase roughly in geometric progression. Thus objects
|
| 129 |
+
requested early in the execution are likely to be allocated with exactly
|
| 130 |
+
the requested size, subject to alignment constraints.
|
| 131 |
+
See <TT>GC_init_size_map</tt> for details.
|
| 132 |
+
<P>
|
| 133 |
+
The actual size rounding operation during small object allocation is
|
| 134 |
+
implemented as a table lookup in <TT>GC_size_map</tt>.
|
| 135 |
+
<P>
|
| 136 |
+
Both collector initialization and computation of allocated sizes are
|
| 137 |
+
handled carefully so that they do not slow down the small object fast
|
| 138 |
+
allocation path. An attempt to allocate before the collector is initialized,
|
| 139 |
+
or before the appropriate <TT>GC_size_map</tt> entry is computed,
|
| 140 |
+
will take the same path as an allocation attempt with an empty free list.
|
| 141 |
+
This results in a call to the slow path code (<TT>GC_generic_malloc_inner</tt>)
|
| 142 |
+
which performs the appropriate initialization checks.
|
| 143 |
+
<P>
|
| 144 |
+
In non-incremental mode, we make a decision about whether to garbage collect
|
| 145 |
+
whenever an allocation would otherwise have failed with the current heap size.
|
| 146 |
+
If the total amount of allocation since the last collection is less than
|
| 147 |
+
the heap size divided by <TT>GC_free_space_divisor</tt>, we try to
|
| 148 |
+
expand the heap. Otherwise, we initiate a garbage collection. This ensures
|
| 149 |
+
that the amount of garbage collection work per allocated byte remains
|
| 150 |
+
constant.
|
| 151 |
+
<P>
|
| 152 |
+
The above is in fact an oversimplification of the real heap expansion
|
| 153 |
+
and GC triggering heuristic, which adjusts slightly for root size
|
| 154 |
+
and certain kinds of
|
| 155 |
+
fragmentation. In particular:
|
| 156 |
+
<UL>
|
| 157 |
+
<LI> Programs with a large root set size and
|
| 158 |
+
little live heap memory will expand the heap to amortize the cost of
|
| 159 |
+
scanning the roots.
|
| 160 |
+
<LI> Versions 5.x of the collector actually collect more frequently in
|
| 161 |
+
nonincremental mode. The large block allocator usually refuses to split
|
| 162 |
+
large heap blocks once the garbage collection threshold is
|
| 163 |
+
reached. This often has the effect of collecting well before the
|
| 164 |
+
heap fills up, thus reducing fragmentation and working set size at the
|
| 165 |
+
expense of GC time. Versions 6.x choose an intermediate strategy depending
|
| 166 |
+
on how much large object allocation has taken place in the past.
|
| 167 |
+
(If the collector is configured to unmap unused pages, versions 6.x
|
| 168 |
+
use the 5.x strategy.)
|
| 169 |
+
<LI> In calculating the amount of allocation since the last collection we
|
| 170 |
+
give partial credit for objects we expect to be explicitly deallocated.
|
| 171 |
+
Even if all objects are explicitly managed, it is often desirable to collect
|
| 172 |
+
on rare occasion, since that is our only mechanism for coalescing completely
|
| 173 |
+
empty chunks.
|
| 174 |
+
</ul>
|
| 175 |
+
<P>
|
| 176 |
+
It has been suggested that this should be adjusted so that we favor
|
| 177 |
+
expansion if the resulting heap still fits into physical memory.
|
| 178 |
+
In many cases, that would no doubt help. But it is tricky to do this
|
| 179 |
+
in a way that remains robust if multiple application are contending
|
| 180 |
+
for a single pool of physical memory.
|
| 181 |
+
|
| 182 |
+
<H2>Mark phase</h2>
|
| 183 |
+
|
| 184 |
+
At each collection, the collector marks all objects that are
|
| 185 |
+
possibly reachable from pointer variables. Since it cannot generally
|
| 186 |
+
tell where pointer variables are located, it scans the following
|
| 187 |
+
<I>root segments</i> for pointers:
|
| 188 |
+
<UL>
|
| 189 |
+
<LI>The registers. Depending on the architecture, this may be done using
|
| 190 |
+
assembly code, or by calling a <TT>setjmp</tt>-like function which saves
|
| 191 |
+
register contents on the stack.
|
| 192 |
+
<LI>The stack(s). In the case of a single-threaded application,
|
| 193 |
+
on most platforms this
|
| 194 |
+
is done by scanning the memory between (an approximation of) the current
|
| 195 |
+
stack pointer and <TT>GC_stackbottom</tt>. (For Itanium, the register stack
|
| 196 |
+
scanned separately.) The <TT>GC_stackbottom</tt> variable is set in
|
| 197 |
+
a highly platform-specific way depending on the appropriate configuration
|
| 198 |
+
information in <TT>gcconfig.h</tt>. Note that the currently active
|
| 199 |
+
stack needs to be scanned carefully, since callee-save registers of
|
| 200 |
+
client code may appear inside collector stack frames, which may
|
| 201 |
+
change during the mark process. This is addressed by scanning
|
| 202 |
+
some sections of the stack "eagerly", effectively capturing a snapshot
|
| 203 |
+
at one point in time.
|
| 204 |
+
<LI>Static data region(s). In the simplest case, this is the region
|
| 205 |
+
between <TT>DATASTART</tt> and <TT>DATAEND</tt>, as defined in
|
| 206 |
+
<TT>gcconfig.h</tt>. However, in most cases, this will also involve
|
| 207 |
+
static data regions associated with dynamic libraries. These are
|
| 208 |
+
identified by the mostly platform-specific code in <TT>dyn_load.c</tt>.
|
| 209 |
+
</ul>
|
| 210 |
+
The marker maintains an explicit stack of memory regions that are known
|
| 211 |
+
to be accessible, but that have not yet been searched for contained pointers.
|
| 212 |
+
Each stack entry contains the starting address of the block to be scanned,
|
| 213 |
+
as well as a descriptor of the block. If no layout information is
|
| 214 |
+
available for the block, then the descriptor is simply a length.
|
| 215 |
+
(For other possibilities, see <TT>gc_mark.h</tt>.)
|
| 216 |
+
<P>
|
| 217 |
+
At the beginning of the mark phase, all root segments
|
| 218 |
+
(as described above) are pushed on the
|
| 219 |
+
stack by <TT>GC_push_roots</tt>. (Registers and eagerly processed
|
| 220 |
+
stack sections are processed by pushing the referenced objects instead
|
| 221 |
+
of the stack section itself.) If <TT>ALL_INTERIOR_PTRS</tt> is not
|
| 222 |
+
defined, then stack roots require special treatment. In this case, the
|
| 223 |
+
normal marking code ignores interior pointers, but <TT>GC_push_all_stack</tt>
|
| 224 |
+
explicitly checks for interior pointers and pushes descriptors for target
|
| 225 |
+
objects.
|
| 226 |
+
<P>
|
| 227 |
+
The marker is structured to allow incremental marking.
|
| 228 |
+
Each call to <TT>GC_mark_some</tt> performs a small amount of
|
| 229 |
+
work towards marking the heap.
|
| 230 |
+
It maintains
|
| 231 |
+
explicit state in the form of <TT>GC_mark_state</tt>, which
|
| 232 |
+
identifies a particular sub-phase. Some other pieces of state, most
|
| 233 |
+
notably the mark stack, identify how much work remains to be done
|
| 234 |
+
in each sub-phase. The normal progression of mark states for
|
| 235 |
+
a stop-the-world collection is:
|
| 236 |
+
<OL>
|
| 237 |
+
<LI> <TT>MS_INVALID</tt> indicating that there may be accessible unmarked
|
| 238 |
+
objects. In this case <TT>GC_objects_are_marked</tt> will simultaneously
|
| 239 |
+
be false, so the mark state is advanced to
|
| 240 |
+
<LI> <TT>MS_PUSH_UNCOLLECTABLE</tt> indicating that it suffices to push
|
| 241 |
+
uncollectable objects, roots, and then mark everything reachable from them.
|
| 242 |
+
<TT>Scan_ptr</tt> is advanced through the heap until all uncollectable
|
| 243 |
+
objects are pushed, and objects reachable from them are marked.
|
| 244 |
+
At that point, the next call to <TT>GC_mark_some</tt> calls
|
| 245 |
+
<TT>GC_push_roots</tt> to push the roots. It the advances the
|
| 246 |
+
mark state to
|
| 247 |
+
<LI> <TT>MS_ROOTS_PUSHED</tt> asserting that once the mark stack is
|
| 248 |
+
empty, all reachable objects are marked. Once in this state, we work
|
| 249 |
+
only on emptying the mark stack. Once this is completed, the state
|
| 250 |
+
changes to
|
| 251 |
+
<LI> <TT>MS_NONE</tt> indicating that reachable objects are marked.
|
| 252 |
+
</ol>
|
| 253 |
+
|
| 254 |
+
The core mark routine <TT>GC_mark_from</tt>, is called
|
| 255 |
+
repeatedly by several of the sub-phases when the mark stack starts to fill
|
| 256 |
+
up. It is also called repeatedly in <TT>MS_ROOTS_PUSHED</tt> state
|
| 257 |
+
to empty the mark stack.
|
| 258 |
+
The routine is designed to only perform a limited amount of marking at
|
| 259 |
+
each call, so that it can also be used by the incremental collector.
|
| 260 |
+
It is fairly carefully tuned, since it usually consumes a large majority
|
| 261 |
+
of the garbage collection time.
|
| 262 |
+
<P>
|
| 263 |
+
The fact that it perform a only a small amount of work per call also
|
| 264 |
+
allows it to be used as the core routine of the parallel marker. In that
|
| 265 |
+
case it is normally invoked on thread-private mark stacks instead of the
|
| 266 |
+
global mark stack. More details can be found in
|
| 267 |
+
<A HREF="scale.html">scale.html</a>
|
| 268 |
+
<P>
|
| 269 |
+
The marker correctly handles mark stack overflows. Whenever the mark stack
|
| 270 |
+
overflows, the mark state is reset to <TT>MS_INVALID</tt>.
|
| 271 |
+
Since there are already marked objects in the heap,
|
| 272 |
+
this eventually forces a complete
|
| 273 |
+
scan of the heap, searching for pointers, during which any unmarked objects
|
| 274 |
+
referenced by marked objects are again pushed on the mark stack. This
|
| 275 |
+
process is repeated until the mark phase completes without a stack overflow.
|
| 276 |
+
Each time the stack overflows, an attempt is made to grow the mark stack.
|
| 277 |
+
All pieces of the collector that push regions onto the mark stack have to be
|
| 278 |
+
careful to ensure forward progress, even in case of repeated mark stack
|
| 279 |
+
overflows. Every mark attempt results in additional marked objects.
|
| 280 |
+
<P>
|
| 281 |
+
Each mark stack entry is processed by examining all candidate pointers
|
| 282 |
+
in the range described by the entry. If the region has no associated
|
| 283 |
+
type information, then this typically requires that each 4-byte aligned
|
| 284 |
+
quantity (8-byte aligned with 64-bit pointers) be considered a candidate
|
| 285 |
+
pointer.
|
| 286 |
+
<P>
|
| 287 |
+
We determine whether a candidate pointer is actually the address of
|
| 288 |
+
a heap block. This is done in the following steps:
|
| 289 |
+
<NL>
|
| 290 |
+
<LI> The candidate pointer is checked against rough heap bounds.
|
| 291 |
+
These heap bounds are maintained such that all actual heap objects
|
| 292 |
+
fall between them. In order to facilitate black-listing (see below)
|
| 293 |
+
we also include address regions that the heap is likely to expand into.
|
| 294 |
+
Most non-pointers fail this initial test.
|
| 295 |
+
<LI> The candidate pointer is divided into two pieces; the most significant
|
| 296 |
+
bits identify a <TT>HBLKSIZE</tt>-sized page in the address space, and
|
| 297 |
+
the least significant bits specify an offset within that page.
|
| 298 |
+
(A hardware page may actually consist of multiple such pages.
|
| 299 |
+
HBLKSIZE is usually the page size divided by a small power of two.)
|
| 300 |
+
<LI>
|
| 301 |
+
The page address part of the candidate pointer is looked up in a
|
| 302 |
+
<A HREF="tree.html">table</a>.
|
| 303 |
+
Each table entry contains either 0, indicating that the page is not part
|
| 304 |
+
of the garbage collected heap, a small integer <I>n</i>, indicating
|
| 305 |
+
that the page is part of large object, starting at least <I>n</i> pages
|
| 306 |
+
back, or a pointer to a descriptor for the page. In the first case,
|
| 307 |
+
the candidate pointer i not a true pointer and can be safely ignored.
|
| 308 |
+
In the last two cases, we can obtain a descriptor for the page containing
|
| 309 |
+
the beginning of the object.
|
| 310 |
+
<LI>
|
| 311 |
+
The starting address of the referenced object is computed.
|
| 312 |
+
The page descriptor contains the size of the object(s)
|
| 313 |
+
in that page, the object kind, and the necessary mark bits for those
|
| 314 |
+
objects. The size information can be used to map the candidate pointer
|
| 315 |
+
to the object starting address. To accelerate this process, the page header
|
| 316 |
+
also contains a pointer to a precomputed map of page offsets to displacements
|
| 317 |
+
from the beginning of an object. The use of this map avoids a
|
| 318 |
+
potentially slow integer remainder operation in computing the object
|
| 319 |
+
start address.
|
| 320 |
+
<LI>
|
| 321 |
+
The mark bit for the target object is checked and set. If the object
|
| 322 |
+
was previously unmarked, the object is pushed on the mark stack.
|
| 323 |
+
The descriptor is read from the page descriptor. (This is computed
|
| 324 |
+
from information <TT>GC_obj_kinds</tt> when the page is first allocated.)
|
| 325 |
+
</nl>
|
| 326 |
+
<P>
|
| 327 |
+
At the end of the mark phase, mark bits for left-over free lists are cleared,
|
| 328 |
+
in case a free list was accidentally marked due to a stray pointer.
|
| 329 |
+
|
| 330 |
+
<H2>Sweep phase</h2>
|
| 331 |
+
|
| 332 |
+
At the end of the mark phase, all blocks in the heap are examined.
|
| 333 |
+
Unmarked large objects are immediately returned to the large object free list.
|
| 334 |
+
Each small object page is checked to see if all mark bits are clear.
|
| 335 |
+
If so, the entire page is returned to the large object free list.
|
| 336 |
+
Small object pages containing some reachable object are queued for later
|
| 337 |
+
sweeping, unless we determine that the page contains very little free
|
| 338 |
+
space, in which case it is not examined further.
|
| 339 |
+
<P>
|
| 340 |
+
This initial sweep pass touches only block headers, not
|
| 341 |
+
the blocks themselves. Thus it does not require significant paging, even
|
| 342 |
+
if large sections of the heap are not in physical memory.
|
| 343 |
+
<P>
|
| 344 |
+
Nonempty small object pages are swept when an allocation attempt
|
| 345 |
+
encounters an empty free list for that object size and kind.
|
| 346 |
+
Pages for the correct size and kind are repeatedly swept until at
|
| 347 |
+
least one empty block is found. Sweeping such a page involves
|
| 348 |
+
scanning the mark bit array in the page header, and building a free
|
| 349 |
+
list linked through the first words in the objects themselves.
|
| 350 |
+
This does involve touching the appropriate data page, but in most cases
|
| 351 |
+
it will be touched only just before it is used for allocation.
|
| 352 |
+
Hence any paging is essentially unavoidable.
|
| 353 |
+
<P>
|
| 354 |
+
Except in the case of pointer-free objects, we maintain the invariant
|
| 355 |
+
that any object in a small object free list is cleared (except possibly
|
| 356 |
+
for the link field). Thus it becomes the burden of the small object
|
| 357 |
+
sweep routine to clear objects. This has the advantage that we can
|
| 358 |
+
easily recover from accidentally marking a free list, though that could
|
| 359 |
+
also be handled by other means. The collector currently spends a fair
|
| 360 |
+
amount of time clearing objects, and this approach should probably be
|
| 361 |
+
revisited.
|
| 362 |
+
<P>
|
| 363 |
+
In most configurations, we use specialized sweep routines to handle common
|
| 364 |
+
small object sizes. Since we allocate one mark bit per word, it becomes
|
| 365 |
+
easier to examine the relevant mark bits if the object size divides
|
| 366 |
+
the word length evenly. We also suitably unroll the inner sweep loop
|
| 367 |
+
in each case. (It is conceivable that profile-based procedure cloning
|
| 368 |
+
in the compiler could make this unnecessary and counterproductive. I
|
| 369 |
+
know of no existing compiler to which this applies.)
|
| 370 |
+
<P>
|
| 371 |
+
The sweeping of small object pages could be avoided completely at the expense
|
| 372 |
+
of examining mark bits directly in the allocator. This would probably
|
| 373 |
+
be more expensive, since each allocation call would have to reload
|
| 374 |
+
a large amount of state (e.g. next object address to be swept, position
|
| 375 |
+
in mark bit table) before it could do its work. The current scheme
|
| 376 |
+
keeps the allocator simple and allows useful optimizations in the sweeper.
|
| 377 |
+
|
| 378 |
+
<H2>Finalization</h2>
|
| 379 |
+
Both <TT>GC_register_disappearing_link</tt> and
|
| 380 |
+
<TT>GC_register_finalizer</tt> add the request to a corresponding hash
|
| 381 |
+
table. The hash table is allocated out of collected memory, but
|
| 382 |
+
the reference to the finalizable object is hidden from the collector.
|
| 383 |
+
Currently finalization requests are processed non-incrementally at the
|
| 384 |
+
end of a mark cycle.
|
| 385 |
+
<P>
|
| 386 |
+
The collector makes an initial pass over the table of finalizable objects,
|
| 387 |
+
pushing the contents of unmarked objects onto the mark stack.
|
| 388 |
+
After pushing each object, the marker is invoked to mark all objects
|
| 389 |
+
reachable from it. The object itself is not explicitly marked.
|
| 390 |
+
This assures that objects on which a finalizer depends are neither
|
| 391 |
+
collected nor finalized.
|
| 392 |
+
<P>
|
| 393 |
+
If in the process of marking from an object the
|
| 394 |
+
object itself becomes marked, we have uncovered
|
| 395 |
+
a cycle involving the object. This usually results in a warning from the
|
| 396 |
+
collector. Such objects are not finalized, since it may be
|
| 397 |
+
unsafe to do so. See the more detailed
|
| 398 |
+
<A HREF="http://www.hpl.hp.com/personal/Hans_Boehm/gc/finalization.html"> discussion of finalization semantics</a>.
|
| 399 |
+
<P>
|
| 400 |
+
Any objects remaining unmarked at the end of this process are added to
|
| 401 |
+
a queue of objects whose finalizers can be run. Depending on collector
|
| 402 |
+
configuration, finalizers are dequeued and run either implicitly during
|
| 403 |
+
allocation calls, or explicitly in response to a user request.
|
| 404 |
+
(Note that the former is unfortunately both the default and not generally safe.
|
| 405 |
+
If finalizers perform synchronization, it may result in deadlocks.
|
| 406 |
+
Nontrivial finalizers generally need to perform synchronization, and
|
| 407 |
+
thus require a different collector configuration.)
|
| 408 |
+
<P>
|
| 409 |
+
The collector provides a mechanism for replacing the procedure that is
|
| 410 |
+
used to mark through objects. This is used both to provide support for
|
| 411 |
+
Java-style unordered finalization, and to ignore certain kinds of cycles,
|
| 412 |
+
<I>e.g.</i> those arising from C++ implementations of virtual inheritance.
|
| 413 |
+
|
| 414 |
+
<H2>Generational Collection and Dirty Bits</h2>
|
| 415 |
+
We basically use the concurrent and generational GC algorithm described in
|
| 416 |
+
<A HREF="http://www.hpl.hp.com/personal/Hans_Boehm/gc/papers/pldi91.ps.Z">"Mostly Parallel Garbage Collection"</a>,
|
| 417 |
+
by Boehm, Demers, and Shenker.
|
| 418 |
+
<P>
|
| 419 |
+
The most significant modification is that
|
| 420 |
+
the collector always starts running in the allocating thread.
|
| 421 |
+
There is no separate garbage collector thread. (If parallel GC is
|
| 422 |
+
enabled, helper threads may also be woken up.)
|
| 423 |
+
If an allocation attempt either requests a large object, or encounters
|
| 424 |
+
an empty small object free list, and notices that there is a collection
|
| 425 |
+
in progress, it immediately performs a small amount of marking work
|
| 426 |
+
as described above.
|
| 427 |
+
<P>
|
| 428 |
+
This change was made both because we wanted to easily accommodate
|
| 429 |
+
single-threaded environments, and because a separate GC thread requires
|
| 430 |
+
very careful control over the scheduler to prevent the mutator from
|
| 431 |
+
out-running the collector, and hence provoking unneeded heap growth.
|
| 432 |
+
<P>
|
| 433 |
+
In incremental mode, the heap is always expanded when we encounter
|
| 434 |
+
insufficient space for an allocation. Garbage collection is triggered
|
| 435 |
+
whenever we notice that more than
|
| 436 |
+
<TT>GC_heap_size</tt>/2 * <TT>GC_free_space_divisor</tt>
|
| 437 |
+
bytes of allocation have taken place.
|
| 438 |
+
After <TT>GC_full_freq</tt> minor collections a major collection
|
| 439 |
+
is started.
|
| 440 |
+
<P>
|
| 441 |
+
All collections initially run interrupted until a predetermined
|
| 442 |
+
amount of time (50 msecs by default) has expired. If this allows
|
| 443 |
+
the collection to complete entirely, we can avoid correcting
|
| 444 |
+
for data structure modifications during the collection. If it does
|
| 445 |
+
not complete, we return control to the mutator, and perform small
|
| 446 |
+
amounts of additional GC work during those later allocations that
|
| 447 |
+
cannot be satisfied from small object free lists. When marking completes,
|
| 448 |
+
the set of modified pages is retrieved, and we mark once again from
|
| 449 |
+
marked objects on those pages, this time with the mutator stopped.
|
| 450 |
+
<P>
|
| 451 |
+
We keep track of modified pages using one of several distinct mechanisms:
|
| 452 |
+
<OL>
|
| 453 |
+
<LI>
|
| 454 |
+
Through explicit mutator cooperation. Currently this requires
|
| 455 |
+
the use of <TT>GC_malloc_stubborn</tt>, and is rarely used.
|
| 456 |
+
<LI>
|
| 457 |
+
(<TT>MPROTECT_VDB</tt>) By write-protecting physical pages and
|
| 458 |
+
catching write faults. This is
|
| 459 |
+
implemented for many Unix-like systems and for win32. It is not possible
|
| 460 |
+
in a few environments.
|
| 461 |
+
<LI>
|
| 462 |
+
(<TT>PROC_VDB</tt>) By retrieving dirty bit information from /proc.
|
| 463 |
+
(Currently only Sun's
|
| 464 |
+
Solaris supports this. Though this is considerably cleaner, performance
|
| 465 |
+
may actually be better with mprotect and signals.)
|
| 466 |
+
<LI>
|
| 467 |
+
(<TT>PCR_VDB</tt>) By relying on an external dirty bit implementation, in this
|
| 468 |
+
case the one in Xerox PCR.
|
| 469 |
+
<LI>
|
| 470 |
+
(<TT>DEFAULT_VDB</tt>) By treating all pages as dirty. This is the default if
|
| 471 |
+
none of the other techniques is known to be usable, and
|
| 472 |
+
<TT>GC_malloc_stubborn</tt> is not used. Practical only for testing, or if
|
| 473 |
+
the vast majority of objects use <TT>GC_malloc_stubborn</tt>.
|
| 474 |
+
</ol>
|
| 475 |
+
|
| 476 |
+
<H2>Black-listing</h2>
|
| 477 |
+
|
| 478 |
+
The collector implements <I>black-listing</i> of pages, as described
|
| 479 |
+
in
|
| 480 |
+
<A HREF="http://www.acm.org/pubs/citations/proceedings/pldi/155090/p197-boehm/">
|
| 481 |
+
Boehm, ``Space Efficient Conservative Collection'', PLDI '93</a>, also available
|
| 482 |
+
<A HREF="papers/pldi93.ps.Z">here</a>.
|
| 483 |
+
<P>
|
| 484 |
+
During the mark phase, the collector tracks ``near misses'', i.e. attempts
|
| 485 |
+
to follow a ``pointer'' to just outside the garbage-collected heap, or
|
| 486 |
+
to a currently unallocated page inside the heap. Pages that have been
|
| 487 |
+
the targets of such near misses are likely to be the targets of
|
| 488 |
+
misidentified ``pointers'' in the future. To minimize the future
|
| 489 |
+
damage caused by such misidentifications they will be allocated only to
|
| 490 |
+
small pointerfree objects.
|
| 491 |
+
<P>
|
| 492 |
+
The collector understands two different kinds of black-listing. A
|
| 493 |
+
page may be black listed for interior pointer references
|
| 494 |
+
(<TT>GC_add_to_black_list_stack</tt>), if it was the target of a near
|
| 495 |
+
miss from a location that requires interior pointer recognition,
|
| 496 |
+
<I>e.g.</i> the stack, or the heap if <TT>GC_all_interior_pointers</tt>
|
| 497 |
+
is set. In this case, we also avoid allocating large blocks that include
|
| 498 |
+
this page.
|
| 499 |
+
<P>
|
| 500 |
+
If the near miss came from a source that did not require interior
|
| 501 |
+
pointer recognition, it is black-listed with
|
| 502 |
+
<TT>GC_add_to_black_list_normal</tt>.
|
| 503 |
+
A page black-listed in this way may appear inside a large object,
|
| 504 |
+
so long as it is not the first page of a large object.
|
| 505 |
+
<P>
|
| 506 |
+
The <TT>GC_allochblk</tt> routine respects black-listing when assigning
|
| 507 |
+
a block to a particular object kind and size. It occasionally
|
| 508 |
+
drops (i.e. allocates and forgets) blocks that are completely black-listed
|
| 509 |
+
in order to avoid excessively long large block free lists containing
|
| 510 |
+
only unusable blocks. This would otherwise become an issue
|
| 511 |
+
if there is low demand for small pointerfree objects.
|
| 512 |
+
|
| 513 |
+
<H2>Thread support</h2>
|
| 514 |
+
We support several different threading models. Unfortunately Pthreads,
|
| 515 |
+
the only reasonably well standardized thread model, supports too narrow
|
| 516 |
+
an interface for conservative garbage collection. There appears to be
|
| 517 |
+
no completely portable way to allow the collector
|
| 518 |
+
to coexist with various Pthreads
|
| 519 |
+
implementations. Hence we currently support only the more
|
| 520 |
+
common Pthreads implementations.
|
| 521 |
+
<P>
|
| 522 |
+
In particular, it is very difficult for the collector to stop all other
|
| 523 |
+
threads in the system and examine the register contents. This is currently
|
| 524 |
+
accomplished with very different mechanisms for some Pthreads
|
| 525 |
+
implementations. The Solaris implementation temporarily disables much
|
| 526 |
+
of the user-level threads implementation by stopping kernel-level threads
|
| 527 |
+
("lwp"s). The Linux/HPUX/OSF1 and Irix implementations sends signals to
|
| 528 |
+
individual Pthreads and has them wait in the signal handler.
|
| 529 |
+
<P>
|
| 530 |
+
The Linux and Irix implementations use
|
| 531 |
+
only documented Pthreads calls, but rely on extensions to their semantics.
|
| 532 |
+
The Linux implementation <TT>linux_threads.c</tt> relies on only very
|
| 533 |
+
mild extensions to the pthreads semantics, and already supports a large number
|
| 534 |
+
of other Unix-like pthreads implementations. Our goal is to make this the
|
| 535 |
+
only pthread support in the collector.
|
| 536 |
+
<P>
|
| 537 |
+
(The Irix implementation is separate only for historical reasons and should
|
| 538 |
+
clearly be merged. The current Solaris implementation probably performs
|
| 539 |
+
better in the uniprocessor case, but does not support thread operations in the
|
| 540 |
+
collector. Hence it cannot support the parallel marker.)
|
| 541 |
+
<P>
|
| 542 |
+
All implementations must
|
| 543 |
+
intercept thread creation and a few other thread-specific calls to allow
|
| 544 |
+
enumeration of threads and location of thread stacks. This is current
|
| 545 |
+
accomplished with <TT># define</tt>'s in <TT>gc.h</tt>
|
| 546 |
+
(really <TT>gc_pthread_redirects.h</tt>), or optionally
|
| 547 |
+
by using ld's function call wrapping mechanism under Linux.
|
| 548 |
+
<P>
|
| 549 |
+
Recent versions of the collector support several facilites to enhance
|
| 550 |
+
the processor-scalability and thread performance of the collector.
|
| 551 |
+
These are discussed in more detail <A HREF="scale.html">here</a>.
|
| 552 |
+
We briefly outline the data approach to thread-local allocation in the
|
| 553 |
+
next section.
|
| 554 |
+
<H2>Thread-local allocation</h2>
|
| 555 |
+
If thread-local allocation is enabled, the collector keeps separate
|
| 556 |
+
arrays of free lists for each thread. Thread-local allocation
|
| 557 |
+
is currently only supported on a few platforms.
|
| 558 |
+
<P>
|
| 559 |
+
The free list arrays associated
|
| 560 |
+
with each thread are only used to satisfy requests for objects that
|
| 561 |
+
are both very small, and belong to one of a small number of well-known
|
| 562 |
+
kinds. These currently include "normal" and pointer-free objects.
|
| 563 |
+
Depending onthe configuration, "gcj" objects may also be included.
|
| 564 |
+
<P>
|
| 565 |
+
Thread-local free list entries contain either a pointer to the first
|
| 566 |
+
element of a free list, or they contain a counter of the number of
|
| 567 |
+
allocation "granules" allocated so far. Initially they contain the
|
| 568 |
+
value one, i.e. a small counter value.
|
| 569 |
+
<P>
|
| 570 |
+
Thread-local allocation allocates directly through the global
|
| 571 |
+
allocator, if the object is of a size or kind not covered by the
|
| 572 |
+
local free lists.
|
| 573 |
+
<P>
|
| 574 |
+
If there is an appropriate local free list, the allocator checks whether it
|
| 575 |
+
contains a sufficiently small counter value. If so, the counter is simply
|
| 576 |
+
incremented by the counter value, and the global allocator is used.
|
| 577 |
+
In this way, the initial few allocations of a given size bypass the local
|
| 578 |
+
allocator. A thread that only allocates a handful of objects of a given
|
| 579 |
+
size will not build up its own free list for that size. This avoids
|
| 580 |
+
wasting space for unpopular objects sizes or kinds.
|
| 581 |
+
<P>
|
| 582 |
+
Once the counter passes a threshold, <TT>GC_malloc_many</tt> is called
|
| 583 |
+
to allocate roughly <TT>HBLKSIZE</tt> space and put it on the corresponding
|
| 584 |
+
local free list. Further allocations of that size and kind then use
|
| 585 |
+
this free list, and no longer need to acquire the allocation lock.
|
| 586 |
+
The allocation procedure is otherwise similar to the global free lists.
|
| 587 |
+
The local free lists are also linked using the first word in the object.
|
| 588 |
+
In most cases this means they require considerably less time.
|
| 589 |
+
<P>
|
| 590 |
+
Local free lists are treated buy most of the rest of the collector
|
| 591 |
+
as though they were in-use reachable data. This requires some care,
|
| 592 |
+
since pointer-free objects are not normally traced, and hence a special
|
| 593 |
+
tracing procedure is required to mark all objects on pointer-free and
|
| 594 |
+
gcj local free lists.
|
| 595 |
+
<P>
|
| 596 |
+
On thread exit, any remaining thread-local free list entries are
|
| 597 |
+
transferred back to the global free list.
|
| 598 |
+
<P>
|
| 599 |
+
Note that if the collector is configured for thread-local allocation,
|
| 600 |
+
GC versions before 7 do not invoke the thread-local allocator by default.
|
| 601 |
+
<TT>GC_malloc</tt> only uses thread-local allocation in version 7 and later.
|
| 602 |
+
In earlier versions, <TT>GC_MALLOC</tt> (all caps) may be directed
|
| 603 |
+
to use thread-local allocation by defining <TT>GC_REDIRECT_TO_LOCAL</tt>
|
| 604 |
+
and then include <TT>gc_local_alloc.h</tt>.
|
| 605 |
+
<P>
|
| 606 |
+
For some more details see <A HREF="scale.html">here</a>, and the
|
| 607 |
+
technical report entitled
|
| 608 |
+
<A HREF="http://www.hpl.hp.com/techreports/2000/HPL-2000-165.html">
|
| 609 |
+
``Fast Multiprocessor Memory Allocation and Garbage Collection''
|
| 610 |
+
</a>
|
| 611 |
+
<P>
|
| 612 |
+
<HR>
|
| 613 |
+
<P>
|
| 614 |
+
Comments are appreciated. Please send mail to
|
| 615 |
+
<A HREF="mailto:boehm@acm.org"><TT>boehm@acm.org</tt></a> or
|
| 616 |
+
<A HREF="mailto:Hans.Boehm@hp.com"><TT>Hans.Boehm@hp.com</tt></a>
|
| 617 |
+
<P>
|
| 618 |
+
This is a modified copy of a page written while the author was at SGI.
|
| 619 |
+
The original was <A HREF="http://reality.sgi.com/boehm/gcdescr.html">here</a>.
|
| 620 |
+
</body>
|
| 621 |
+
</html>
|
mosesdecoder/jam-files/engine/boehm_gc/doc/scale.html
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<HTML>
|
| 2 |
+
<HEAD>
|
| 3 |
+
<TITLE>Garbage collector scalability</TITLE>
|
| 4 |
+
</HEAD>
|
| 5 |
+
<BODY>
|
| 6 |
+
<H1>Garbage collector scalability</h1>
|
| 7 |
+
In its default configuration, the Boehm-Demers-Weiser garbage collector
|
| 8 |
+
is not thread-safe. It can be made thread-safe for a number of environments
|
| 9 |
+
by building the collector with the appropriate
|
| 10 |
+
<TT>-D</tt><I>XXX</i><TT>-THREADS</tt> compilation
|
| 11 |
+
flag. This has primarily two effects:
|
| 12 |
+
<OL>
|
| 13 |
+
<LI> It causes the garbage collector to stop all other threads when
|
| 14 |
+
it needs to see a consistent memory state.
|
| 15 |
+
<LI> It causes the collector to acquire a lock around essentially all
|
| 16 |
+
allocation and garbage collection activity.
|
| 17 |
+
</ol>
|
| 18 |
+
Since a single lock is used for all allocation-related activity, only one
|
| 19 |
+
thread can be allocating or collecting at one point. This inherently
|
| 20 |
+
limits performance of multi-threaded applications on multiprocessors.
|
| 21 |
+
<P>
|
| 22 |
+
On most platforms, the allocator/collector lock is implemented as a
|
| 23 |
+
spin lock with exponential back-off. Longer wait times are implemented
|
| 24 |
+
by yielding and/or sleeping. If a collection is in progress, the pure
|
| 25 |
+
spinning stage is skipped. This has the advantage that uncontested and
|
| 26 |
+
thus most uniprocessor lock acquisitions are very cheap. It has the
|
| 27 |
+
disadvantage that the application may sleep for small periods of time
|
| 28 |
+
even when there is work to be done. And threads may be unnecessarily
|
| 29 |
+
woken up for short periods. Nonetheless, this scheme empirically
|
| 30 |
+
outperforms native queue-based mutual exclusion implementations in most
|
| 31 |
+
cases, sometimes drastically so.
|
| 32 |
+
<H2>Options for enhanced scalability</h2>
|
| 33 |
+
Version 6.0 of the collector adds two facilities to enhance collector
|
| 34 |
+
scalability on multiprocessors. As of 6.0alpha1, these are supported
|
| 35 |
+
only under Linux on X86 and IA64 processors, though ports to other
|
| 36 |
+
otherwise supported Pthreads platforms should be straightforward.
|
| 37 |
+
They are intended to be used together.
|
| 38 |
+
<UL>
|
| 39 |
+
<LI>
|
| 40 |
+
Building the collector with <TT>-DPARALLEL_MARK</tt> allows the collector to
|
| 41 |
+
run the mark phase in parallel in multiple threads, and thus on multiple
|
| 42 |
+
processors. The mark phase typically consumes the large majority of the
|
| 43 |
+
collection time. Thus this largely parallelizes the garbage collector
|
| 44 |
+
itself, though not the allocation process. Currently the marking is
|
| 45 |
+
performed by the thread that triggered the collection, together with
|
| 46 |
+
<I>N</i>-1 dedicated
|
| 47 |
+
threads, where <I>N</i> is the number of processors detected by the collector.
|
| 48 |
+
The dedicated threads are created once at initialization time.
|
| 49 |
+
<P>
|
| 50 |
+
A second effect of this flag is to switch to a more concurrent
|
| 51 |
+
implementation of <TT>GC_malloc_many</tt>, so that free lists can be
|
| 52 |
+
built, and memory can be cleared, by more than one thread concurrently.
|
| 53 |
+
<LI>
|
| 54 |
+
Building the collector with -DTHREAD_LOCAL_ALLOC adds support for thread
|
| 55 |
+
local allocation. It does not, by itself, cause thread local allocation
|
| 56 |
+
to be used. It simply allows the use of the interface in
|
| 57 |
+
<TT>gc_local_alloc.h</tt>.
|
| 58 |
+
<P>
|
| 59 |
+
Memory returned from thread-local allocators is completely interchangeable
|
| 60 |
+
with that returned by the standard allocators. It may be used by other
|
| 61 |
+
threads. The only difference is that, if the thread allocates enough
|
| 62 |
+
memory of a certain kind, it will build a thread-local free list for
|
| 63 |
+
objects of that kind, and allocate from that. This greatly reduces
|
| 64 |
+
locking. The thread-local free lists are refilled using
|
| 65 |
+
<TT>GC_malloc_many</tt>.
|
| 66 |
+
<P>
|
| 67 |
+
An important side effect of this flag is to replace the default
|
| 68 |
+
spin-then-sleep lock to be replace by a spin-then-queue based implementation.
|
| 69 |
+
This <I>reduces performance</i> for the standard allocation functions,
|
| 70 |
+
though it usually improves performance when thread-local allocation is
|
| 71 |
+
used heavily, and thus the number of short-duration lock acquisitions
|
| 72 |
+
is greatly reduced.
|
| 73 |
+
</ul>
|
| 74 |
+
<P>
|
| 75 |
+
The easiest way to switch an application to thread-local allocation is to
|
| 76 |
+
<OL>
|
| 77 |
+
<LI> Define the macro <TT>GC_REDIRECT_TO_LOCAL</tt>,
|
| 78 |
+
and then include the <TT>gc.h</tt>
|
| 79 |
+
header in each client source file.
|
| 80 |
+
<LI> Invoke <TT>GC_thr_init()</tt> before any allocation.
|
| 81 |
+
<LI> Allocate using <TT>GC_MALLOC</tt>, <TT>GC_MALLOC_ATOMIC</tt>,
|
| 82 |
+
and/or <TT>GC_GCJ_MALLOC</tt>.
|
| 83 |
+
</ol>
|
| 84 |
+
<H2>The Parallel Marking Algorithm</h2>
|
| 85 |
+
We use an algorithm similar to
|
| 86 |
+
<A HREF="http://www.yl.is.s.u-tokyo.ac.jp/gc/">that developed by
|
| 87 |
+
Endo, Taura, and Yonezawa</a> at the University of Tokyo.
|
| 88 |
+
However, the data structures and implementation are different,
|
| 89 |
+
and represent a smaller change to the original collector source,
|
| 90 |
+
probably at the expense of extreme scalability. Some of
|
| 91 |
+
the refinements they suggest, <I>e.g.</i> splitting large
|
| 92 |
+
objects, were also incorporated into out approach.
|
| 93 |
+
<P>
|
| 94 |
+
The global mark stack is transformed into a global work queue.
|
| 95 |
+
Unlike the usual case, it never shrinks during a mark phase.
|
| 96 |
+
The mark threads remove objects from the queue by copying them to a
|
| 97 |
+
local mark stack and changing the global descriptor to zero, indicating
|
| 98 |
+
that there is no more work to be done for this entry.
|
| 99 |
+
This removal
|
| 100 |
+
is done with no synchronization. Thus it is possible for more than
|
| 101 |
+
one worker to remove the same entry, resulting in some work duplication.
|
| 102 |
+
<P>
|
| 103 |
+
The global work queue grows only if a marker thread decides to
|
| 104 |
+
return some of its local mark stack to the global one. This
|
| 105 |
+
is done if the global queue appears to be running low, or if
|
| 106 |
+
the local stack is in danger of overflowing. It does require
|
| 107 |
+
synchronization, but should be relatively rare.
|
| 108 |
+
<P>
|
| 109 |
+
The sequential marking code is reused to process local mark stacks.
|
| 110 |
+
Hence the amount of additional code required for parallel marking
|
| 111 |
+
is minimal.
|
| 112 |
+
<P>
|
| 113 |
+
It should be possible to use generational collection in the presence of the
|
| 114 |
+
parallel collector, by calling <TT>GC_enable_incremental()</tt>.
|
| 115 |
+
This does not result in fully incremental collection, since parallel mark
|
| 116 |
+
phases cannot currently be interrupted, and doing so may be too
|
| 117 |
+
expensive.
|
| 118 |
+
<P>
|
| 119 |
+
Gcj-style mark descriptors do not currently mix with the combination
|
| 120 |
+
of local allocation and incremental collection. They should work correctly
|
| 121 |
+
with one or the other, but not both.
|
| 122 |
+
<P>
|
| 123 |
+
The number of marker threads is set on startup to the number of
|
| 124 |
+
available processors (or to the value of the <TT>GC_NPROCS</tt>
|
| 125 |
+
environment variable). If only a single processor is detected,
|
| 126 |
+
parallel marking is disabled.
|
| 127 |
+
<P>
|
| 128 |
+
Note that setting GC_NPROCS to 1 also causes some lock acquisitions inside
|
| 129 |
+
the collector to immediately yield the processor instead of busy waiting
|
| 130 |
+
first. In the case of a multiprocessor and a client with multiple
|
| 131 |
+
simultaneously runnable threads, this may have disastrous performance
|
| 132 |
+
consequences (e.g. a factor of 10 slowdown).
|
| 133 |
+
<H2>Performance</h2>
|
| 134 |
+
We conducted some simple experiments with a version of
|
| 135 |
+
<A HREF="gc_bench.html">our GC benchmark</a> that was slightly modified to
|
| 136 |
+
run multiple concurrent client threads in the same address space.
|
| 137 |
+
Each client thread does the same work as the original benchmark, but they share
|
| 138 |
+
a heap.
|
| 139 |
+
This benchmark involves very little work outside of memory allocation.
|
| 140 |
+
This was run with GC 6.0alpha3 on a dual processor Pentium III/500 machine
|
| 141 |
+
under Linux 2.2.12.
|
| 142 |
+
<P>
|
| 143 |
+
Running with a thread-unsafe collector, the benchmark ran in 9
|
| 144 |
+
seconds. With the simple thread-safe collector,
|
| 145 |
+
built with <TT>-DLINUX_THREADS</tt>, the execution time
|
| 146 |
+
increased to 10.3 seconds, or 23.5 elapsed seconds with two clients.
|
| 147 |
+
(The times for the <TT>malloc</tt>/i<TT>free</tt> version
|
| 148 |
+
with glibc <TT>malloc</tt>
|
| 149 |
+
are 10.51 (standard library, pthreads not linked),
|
| 150 |
+
20.90 (one thread, pthreads linked),
|
| 151 |
+
and 24.55 seconds respectively. The benchmark favors a
|
| 152 |
+
garbage collector, since most objects are small.)
|
| 153 |
+
<P>
|
| 154 |
+
The following table gives execution times for the collector built
|
| 155 |
+
with parallel marking and thread-local allocation support
|
| 156 |
+
(<TT>-DGC_LINUX_THREADS -DPARALLEL_MARK -DTHREAD_LOCAL_ALLOC</tt>). We tested
|
| 157 |
+
the client using either one or two marker threads, and running
|
| 158 |
+
one or two client threads. Note that the client uses thread local
|
| 159 |
+
allocation exclusively. With -DTHREAD_LOCAL_ALLOC the collector
|
| 160 |
+
switches to a locking strategy that is better tuned to less frequent
|
| 161 |
+
lock acquisition. The standard allocation primitives thus peform
|
| 162 |
+
slightly worse than without -DTHREAD_LOCAL_ALLOC, and should be
|
| 163 |
+
avoided in time-critical code.
|
| 164 |
+
<P>
|
| 165 |
+
(The results using <TT>pthread_mutex_lock</tt>
|
| 166 |
+
directly for allocation locking would have been worse still, at
|
| 167 |
+
least for older versions of linuxthreads.
|
| 168 |
+
With THREAD_LOCAL_ALLOC, we first repeatedly try to acquire the
|
| 169 |
+
lock with pthread_mutex_try_lock(), busy_waiting between attempts.
|
| 170 |
+
After a fixed number of attempts, we use pthread_mutex_lock().)
|
| 171 |
+
<P>
|
| 172 |
+
These measurements do not use incremental collection, nor was prefetching
|
| 173 |
+
enabled in the marker. We used the C version of the benchmark.
|
| 174 |
+
All measurements are in elapsed seconds on an unloaded machine.
|
| 175 |
+
<P>
|
| 176 |
+
<TABLE BORDER ALIGN="CENTER">
|
| 177 |
+
<TR><TH>Number of threads</th><TH>1 marker thread (secs.)</th>
|
| 178 |
+
<TH>2 marker threads (secs.)</th></tr>
|
| 179 |
+
<TR><TD>1 client</td><TD ALIGN="CENTER">10.45</td><TD ALIGN="CENTER">7.85</td>
|
| 180 |
+
<TR><TD>2 clients</td><TD ALIGN="CENTER">19.95</td><TD ALIGN="CENTER">12.3</td>
|
| 181 |
+
</table>
|
| 182 |
+
<PP>
|
| 183 |
+
The execution time for the single threaded case is slightly worse than with
|
| 184 |
+
simple locking. However, even the single-threaded benchmark runs faster than
|
| 185 |
+
even the thread-unsafe version if a second processor is available.
|
| 186 |
+
The execution time for two clients with thread local allocation time is
|
| 187 |
+
only 1.4 times the sequential execution time for a single thread in a
|
| 188 |
+
thread-unsafe environment, even though it involves twice the client work.
|
| 189 |
+
That represents close to a
|
| 190 |
+
factor of 2 improvement over the 2 client case with the old collector.
|
| 191 |
+
The old collector clearly
|
| 192 |
+
still suffered from some contention overhead, in spite of the fact that the
|
| 193 |
+
locking scheme had been fairly well tuned.
|
| 194 |
+
<P>
|
| 195 |
+
Full linear speedup (i.e. the same execution time for 1 client on one
|
| 196 |
+
processor as 2 clients on 2 processors)
|
| 197 |
+
is probably not achievable on this kind of
|
| 198 |
+
hardware even with such a small number of processors,
|
| 199 |
+
since the memory system is
|
| 200 |
+
a major constraint for the garbage collector,
|
| 201 |
+
the processors usually share a single memory bus, and thus
|
| 202 |
+
the aggregate memory bandwidth does not increase in
|
| 203 |
+
proportion to the number of processors.
|
| 204 |
+
<P>
|
| 205 |
+
These results are likely to be very sensitive to both hardware and OS
|
| 206 |
+
issues. Preliminary experiments with an older Pentium Pro machine running
|
| 207 |
+
an older kernel were far less encouraging.
|
| 208 |
+
|
| 209 |
+
</body>
|
| 210 |
+
</html>
|
mosesdecoder/jam-files/engine/boehm_gc/doc/simple_example.html
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<HTML>
|
| 2 |
+
<HEAD>
|
| 3 |
+
<TITLE>Using the Garbage Collector: A simple example</title>
|
| 4 |
+
</head>
|
| 5 |
+
<BODY>
|
| 6 |
+
<H1>Using the Garbage Collector: A simple example</h1>
|
| 7 |
+
The following consists of step-by-step instructions for building and
|
| 8 |
+
using the collector. We'll assume a Linux/gcc platform and
|
| 9 |
+
a single-threaded application. <FONT COLOR=green>The green
|
| 10 |
+
text contains information about other platforms or scenarios.
|
| 11 |
+
It can be skipped, especially on first reading</font>.
|
| 12 |
+
<H2>Building the collector</h2>
|
| 13 |
+
If you haven't already so, unpack the collector and enter
|
| 14 |
+
the newly created directory with
|
| 15 |
+
<PRE>
|
| 16 |
+
tar xvfz gc<version>.tar.gz
|
| 17 |
+
cd gc<version>
|
| 18 |
+
</pre>
|
| 19 |
+
<P>
|
| 20 |
+
You can configure, build, and install the collector in a private
|
| 21 |
+
directory, say /home/xyz/gc, with the following commands:
|
| 22 |
+
<PRE>
|
| 23 |
+
./configure --prefix=/home/xyz/gc --disable-threads
|
| 24 |
+
make
|
| 25 |
+
make check
|
| 26 |
+
make install
|
| 27 |
+
</pre>
|
| 28 |
+
Here the "<TT>make check</tt>" command is optional, but highly recommended.
|
| 29 |
+
It runs a basic correctness test which usually takes well under a minute.
|
| 30 |
+
<FONT COLOR=green>
|
| 31 |
+
<H3>Other platforms</h3>
|
| 32 |
+
On non-Unix, non-Linux platforms, the collector is usually built by copying
|
| 33 |
+
the appropriate makefile (see the platform-specific README in doc/README.xxx
|
| 34 |
+
in the distribution) to the file "Makefile" (overwriting the copy of
|
| 35 |
+
Makefile.direct that was originally there), and then typing "make"
|
| 36 |
+
(or "nmake" or ...). This builds the library in the source tree. You may
|
| 37 |
+
want to move it and the files in the include directory to a more convenient
|
| 38 |
+
place.
|
| 39 |
+
<P>
|
| 40 |
+
If you use a makefile that does not require running a configure script,
|
| 41 |
+
you should first look at the makefile, and adjust any options that are
|
| 42 |
+
documented there.
|
| 43 |
+
<P>
|
| 44 |
+
If your platform provides a "make" utility, that is generally preferred
|
| 45 |
+
to platform- and compiler- dependent "project" files. (At least that is the
|
| 46 |
+
strong preference of the would-be maintainer of those project files.)
|
| 47 |
+
<H3>Threads</h3>
|
| 48 |
+
If you need thread support, configure the collector with
|
| 49 |
+
<PRE>
|
| 50 |
+
--enable-threads=posix --enable-thread-local-alloc --enable-parallel-mark
|
| 51 |
+
</pre>
|
| 52 |
+
instead of
|
| 53 |
+
<TT>--disable-threads</tt>
|
| 54 |
+
If your target is a real old-fashioned uniprocessor (no "hyperthreading",
|
| 55 |
+
etc.) you will want to omit <TT>--enable-parallel-mark</tt>.
|
| 56 |
+
<H3>C++</h3>
|
| 57 |
+
You will need to include the C++ support, which unfortunately tends to
|
| 58 |
+
be among the least portable parts of the collector, since it seems
|
| 59 |
+
to rely on some corner cases of the language. On Linux, it
|
| 60 |
+
suffices to add <TT>--enable-cplusplus</tt> to the configure options.
|
| 61 |
+
</font>
|
| 62 |
+
<H2>Writing the program</h2>
|
| 63 |
+
You will need a
|
| 64 |
+
<PRE>
|
| 65 |
+
#include "gc.h"
|
| 66 |
+
</pre>
|
| 67 |
+
at the beginning of every file that allocates memory through the
|
| 68 |
+
garbage collector. Call <TT>GC_MALLOC</tt> wherever you would
|
| 69 |
+
have call <TT>malloc</tt>. This initializes memory to zero like
|
| 70 |
+
<TT>calloc</tt>; there is no need to explicitly clear the
|
| 71 |
+
result.
|
| 72 |
+
<P>
|
| 73 |
+
If you know that an object will not contain pointers to the
|
| 74 |
+
garbage-collected heap, and you don't need it to be initialized,
|
| 75 |
+
call <TT>GC_MALLOC_ATOMIC</tt> instead.
|
| 76 |
+
<P>
|
| 77 |
+
A function <TT>GC_FREE</tt> is provided but need not be called.
|
| 78 |
+
For very small objects, your program will probably perform better if
|
| 79 |
+
you do not call it, and let the collector do its job.
|
| 80 |
+
<P>
|
| 81 |
+
A <TT>GC_REALLOC</tt> function behaves like the C library <TT>realloc</tt>.
|
| 82 |
+
It allocates uninitialized pointer-free memory if the original
|
| 83 |
+
object was allocated that way.
|
| 84 |
+
<P>
|
| 85 |
+
The following program <TT>loop.c</tt> is a trivial example:
|
| 86 |
+
<PRE>
|
| 87 |
+
#include "gc.h"
|
| 88 |
+
#include <assert.h>
|
| 89 |
+
#include <stdio.h>
|
| 90 |
+
|
| 91 |
+
int main()
|
| 92 |
+
{
|
| 93 |
+
int i;
|
| 94 |
+
|
| 95 |
+
GC_INIT(); /* Optional on Linux/X86; see below. */
|
| 96 |
+
for (i = 0; i < 10000000; ++i)
|
| 97 |
+
{
|
| 98 |
+
int **p = (int **) GC_MALLOC(sizeof(int *));
|
| 99 |
+
int *q = (int *) GC_MALLOC_ATOMIC(sizeof(int));
|
| 100 |
+
assert(*p == 0);
|
| 101 |
+
*p = (int *) GC_REALLOC(q, 2 * sizeof(int));
|
| 102 |
+
if (i % 100000 == 0)
|
| 103 |
+
printf("Heap size = %d\n", GC_get_heap_size());
|
| 104 |
+
}
|
| 105 |
+
return 0;
|
| 106 |
+
}
|
| 107 |
+
</pre>
|
| 108 |
+
<FONT COLOR=green>
|
| 109 |
+
<H3>Interaction with the system malloc</h3>
|
| 110 |
+
It is usually best not to mix garbage-collected allocation with the system
|
| 111 |
+
<TT>malloc-free</tt>. If you do, you need to be careful not to store
|
| 112 |
+
pointers to the garbage-collected heap in memory allocated with the system
|
| 113 |
+
<TT>malloc</tt>.
|
| 114 |
+
<H3>Other Platforms</h3>
|
| 115 |
+
On some other platforms it is necessary to call <TT>GC_INIT()</tt> from the main program,
|
| 116 |
+
which is presumed to be part of the main executable, not a dynamic library.
|
| 117 |
+
This can never hurt, and is thus generally good practice.
|
| 118 |
+
|
| 119 |
+
<H3>Threads</h3>
|
| 120 |
+
For a multithreaded program some more rules apply:
|
| 121 |
+
<UL>
|
| 122 |
+
<LI>
|
| 123 |
+
Files that either allocate through the GC <I>or make thread-related calls</i>
|
| 124 |
+
should first define the macro <TT>GC_THREADS</tt>, and then
|
| 125 |
+
include <TT>"gc.h"</tt>. On some platforms this will redefine some
|
| 126 |
+
threads primitives, e.g. to let the collector keep track of thread creation.
|
| 127 |
+
<LI>
|
| 128 |
+
To take advantage of fast thread-local allocation, use the following instead
|
| 129 |
+
of including <TT>gc.h</tt>:
|
| 130 |
+
<PRE>
|
| 131 |
+
#define GC_REDIRECT_TO_LOCAL
|
| 132 |
+
#include "gc_local_alloc.h"
|
| 133 |
+
</pre>
|
| 134 |
+
This will cause GC_MALLOC and GC_MALLOC_ATOMIC to keep per-thread allocation
|
| 135 |
+
caches, and greatly reduce the number of lock acquisitions during allocation.
|
| 136 |
+
</ul>
|
| 137 |
+
|
| 138 |
+
<H3>C++</h3>
|
| 139 |
+
In the case of C++, you need to be especially careful not to store pointers
|
| 140 |
+
to the garbage-collected heap in areas that are not traced by the collector.
|
| 141 |
+
The collector includes some <A HREF="gcinterface.html">alternate interfaces</a>
|
| 142 |
+
to make that easier.
|
| 143 |
+
|
| 144 |
+
<H3>Debugging</h3>
|
| 145 |
+
Additional debug checks can be performed by defining <TT>GC_DEBUG</tt> before
|
| 146 |
+
including <TT>gc.h</tt>. Additional options are available if the collector
|
| 147 |
+
is also built with <TT>--enable-full_debug</tt> and all allocations are
|
| 148 |
+
performed with <TT>GC_DEBUG</tt> defined.
|
| 149 |
+
|
| 150 |
+
<H3>What if I can't rewrite/recompile my program?</h3>
|
| 151 |
+
You may be able to build the collector with <TT>--enable-redirect-malloc</tt>
|
| 152 |
+
and set the <TT>LD_PRELOAD</tt> environment variable to point to the resulting
|
| 153 |
+
library, thus replacing the standard <TT>malloc</tt> with its garbage-collected
|
| 154 |
+
counterpart. This is rather platform dependent. See the
|
| 155 |
+
<A HREF="leak.html">leak detection documentation</a> for some more details.
|
| 156 |
+
|
| 157 |
+
</font>
|
| 158 |
+
|
| 159 |
+
<H2>Compiling and linking</h2>
|
| 160 |
+
|
| 161 |
+
The above application <TT>loop.c</tt> test program can be compiled and linked
|
| 162 |
+
with
|
| 163 |
+
|
| 164 |
+
<PRE>
|
| 165 |
+
cc -I/home/xyz/gc/include loop.c /home/xyz/gc/lib/libgc.a -o loop
|
| 166 |
+
</pre>
|
| 167 |
+
|
| 168 |
+
The <TT>-I</tt> option directs the compiler to the right include
|
| 169 |
+
directory. In this case, we list the static library
|
| 170 |
+
directly on the compile line; the dynamic library could have been
|
| 171 |
+
used instead, provided we arranged for the dynamic loader to find
|
| 172 |
+
it, e.g. by setting <TT>LD_LIBRARY_PATH</tt>.
|
| 173 |
+
|
| 174 |
+
<FONT COLOR=green>
|
| 175 |
+
|
| 176 |
+
<H3>Threads</h3>
|
| 177 |
+
|
| 178 |
+
On pthread platforms, you will of course also have to link with
|
| 179 |
+
<TT>-lpthread</tt>,
|
| 180 |
+
and compile with any thread-safety options required by your compiler.
|
| 181 |
+
On some platforms, you may also need to link with <TT>-ldl</tt>
|
| 182 |
+
or <TT>-lrt</tt>.
|
| 183 |
+
Looking at threadlibs.c in the GC build directory
|
| 184 |
+
should give you the appropriate
|
| 185 |
+
list if a plain <TT>-lpthread</tt> doesn't work.
|
| 186 |
+
|
| 187 |
+
</font>
|
| 188 |
+
|
| 189 |
+
<H2>Running the executable</h2>
|
| 190 |
+
|
| 191 |
+
The executable can of course be run normally, e.g. by typing
|
| 192 |
+
|
| 193 |
+
<PRE>
|
| 194 |
+
./loop
|
| 195 |
+
</pre>
|
| 196 |
+
|
| 197 |
+
The operation of the collector is affected by a number of environment variables.
|
| 198 |
+
For example, setting <TT>GC_PRINT_STATS</tt> produces some
|
| 199 |
+
GC statistics on stdout.
|
| 200 |
+
See <TT>README.environment</tt> in the distribution for details.
|
| 201 |
+
</body>
|
| 202 |
+
</html>
|
mosesdecoder/jam-files/engine/boehm_gc/finalize.c
ADDED
|
@@ -0,0 +1,869 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
| 3 |
+
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
| 4 |
+
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
| 5 |
+
* Copyright (C) 2007 Free Software Foundation, Inc
|
| 6 |
+
|
| 7 |
+
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 8 |
+
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 9 |
+
*
|
| 10 |
+
* Permission is hereby granted to use or copy this program
|
| 11 |
+
* for any purpose, provided the above notices are retained on all copies.
|
| 12 |
+
* Permission to modify the code and to distribute modified code is granted,
|
| 13 |
+
* provided the above notices are retained, and a notice that the code was
|
| 14 |
+
* modified is included with the above copyright notice.
|
| 15 |
+
*/
|
| 16 |
+
/* Boehm, February 1, 1996 1:19 pm PST */
|
| 17 |
+
# define I_HIDE_POINTERS
|
| 18 |
+
# include "private/gc_pmark.h"
|
| 19 |
+
|
| 20 |
+
# ifdef FINALIZE_ON_DEMAND
|
| 21 |
+
int GC_finalize_on_demand = 1;
|
| 22 |
+
# else
|
| 23 |
+
int GC_finalize_on_demand = 0;
|
| 24 |
+
# endif
|
| 25 |
+
|
| 26 |
+
# ifdef JAVA_FINALIZATION
|
| 27 |
+
int GC_java_finalization = 1;
|
| 28 |
+
# else
|
| 29 |
+
int GC_java_finalization = 0;
|
| 30 |
+
# endif
|
| 31 |
+
|
| 32 |
+
/* Type of mark procedure used for marking from finalizable object. */
|
| 33 |
+
/* This procedure normally does not mark the object, only its */
|
| 34 |
+
/* descendents. */
|
| 35 |
+
typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */);
|
| 36 |
+
|
| 37 |
+
# define HASH3(addr,size,log_size) \
|
| 38 |
+
((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
|
| 39 |
+
& ((size) - 1))
|
| 40 |
+
#define HASH2(addr,log_size) HASH3(addr, 1 << log_size, log_size)
|
| 41 |
+
|
| 42 |
+
struct hash_chain_entry {
|
| 43 |
+
word hidden_key;
|
| 44 |
+
struct hash_chain_entry * next;
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
unsigned GC_finalization_failures = 0;
|
| 48 |
+
/* Number of finalization requests that failed for lack of memory. */
|
| 49 |
+
|
| 50 |
+
static struct disappearing_link {
|
| 51 |
+
struct hash_chain_entry prolog;
|
| 52 |
+
# define dl_hidden_link prolog.hidden_key
|
| 53 |
+
/* Field to be cleared. */
|
| 54 |
+
# define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
|
| 55 |
+
# define dl_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
|
| 56 |
+
|
| 57 |
+
word dl_hidden_obj; /* Pointer to object base */
|
| 58 |
+
} **dl_head = 0;
|
| 59 |
+
|
| 60 |
+
static signed_word log_dl_table_size = -1;
|
| 61 |
+
/* Binary log of */
|
| 62 |
+
/* current size of array pointed to by dl_head. */
|
| 63 |
+
/* -1 ==> size is 0. */
|
| 64 |
+
|
| 65 |
+
word GC_dl_entries = 0; /* Number of entries currently in disappearing */
|
| 66 |
+
/* link table. */
|
| 67 |
+
|
| 68 |
+
static struct finalizable_object {
|
| 69 |
+
struct hash_chain_entry prolog;
|
| 70 |
+
# define fo_hidden_base prolog.hidden_key
|
| 71 |
+
/* Pointer to object base. */
|
| 72 |
+
/* No longer hidden once object */
|
| 73 |
+
/* is on finalize_now queue. */
|
| 74 |
+
# define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
|
| 75 |
+
# define fo_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
|
| 76 |
+
GC_finalization_proc fo_fn; /* Finalizer. */
|
| 77 |
+
ptr_t fo_client_data;
|
| 78 |
+
word fo_object_size; /* In bytes. */
|
| 79 |
+
finalization_mark_proc * fo_mark_proc; /* Mark-through procedure */
|
| 80 |
+
} **fo_head = 0;
|
| 81 |
+
|
| 82 |
+
struct finalizable_object * GC_finalize_now = 0;
|
| 83 |
+
/* LIst of objects that should be finalized now. */
|
| 84 |
+
|
| 85 |
+
static signed_word log_fo_table_size = -1;
|
| 86 |
+
|
| 87 |
+
word GC_fo_entries = 0;
|
| 88 |
+
|
| 89 |
+
void GC_push_finalizer_structures(void)
|
| 90 |
+
{
|
| 91 |
+
GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
|
| 92 |
+
GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
|
| 93 |
+
GC_push_all((ptr_t)(&GC_finalize_now),
|
| 94 |
+
(ptr_t)(&GC_finalize_now) + sizeof(word));
|
| 95 |
+
}
|
| 96 |
+
|
| 97 |
+
/* Double the size of a hash table. *size_ptr is the log of its current */
|
| 98 |
+
/* size. May be a noop. */
|
| 99 |
+
/* *table is a pointer to an array of hash headers. If we succeed, we */
|
| 100 |
+
/* update both *table and *log_size_ptr. */
|
| 101 |
+
/* Lock is held. Signals are disabled. */
|
| 102 |
+
void GC_grow_table(struct hash_chain_entry ***table,
|
| 103 |
+
signed_word *log_size_ptr)
|
| 104 |
+
{
|
| 105 |
+
register word i;
|
| 106 |
+
register struct hash_chain_entry *p;
|
| 107 |
+
signed_word log_old_size = *log_size_ptr;
|
| 108 |
+
signed_word log_new_size = log_old_size + 1;
|
| 109 |
+
word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
|
| 110 |
+
word new_size = (word)1 << log_new_size;
|
| 111 |
+
/* FIXME: Power of 2 size often gets rounded up to one more page. */
|
| 112 |
+
struct hash_chain_entry **new_table = (struct hash_chain_entry **)
|
| 113 |
+
GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
|
| 114 |
+
(size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
|
| 115 |
+
|
| 116 |
+
if (new_table == 0) {
|
| 117 |
+
if (table == 0) {
|
| 118 |
+
ABORT("Insufficient space for initial table allocation");
|
| 119 |
+
} else {
|
| 120 |
+
return;
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
for (i = 0; i < old_size; i++) {
|
| 124 |
+
p = (*table)[i];
|
| 125 |
+
while (p != 0) {
|
| 126 |
+
ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
|
| 127 |
+
struct hash_chain_entry *next = p -> next;
|
| 128 |
+
size_t new_hash = HASH3(real_key, new_size, log_new_size);
|
| 129 |
+
|
| 130 |
+
p -> next = new_table[new_hash];
|
| 131 |
+
new_table[new_hash] = p;
|
| 132 |
+
p = next;
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
*log_size_ptr = log_new_size;
|
| 136 |
+
*table = new_table;
|
| 137 |
+
}
|
| 138 |
+
|
| 139 |
+
int GC_register_disappearing_link(void * * link)
|
| 140 |
+
{
|
| 141 |
+
ptr_t base;
|
| 142 |
+
|
| 143 |
+
base = (ptr_t)GC_base((void *)link);
|
| 144 |
+
if (base == 0)
|
| 145 |
+
ABORT("Bad arg to GC_register_disappearing_link");
|
| 146 |
+
return(GC_general_register_disappearing_link(link, base));
|
| 147 |
+
}
|
| 148 |
+
|
| 149 |
+
int GC_general_register_disappearing_link(void * * link, void * obj)
|
| 150 |
+
{
|
| 151 |
+
struct disappearing_link *curr_dl;
|
| 152 |
+
size_t index;
|
| 153 |
+
struct disappearing_link * new_dl;
|
| 154 |
+
DCL_LOCK_STATE;
|
| 155 |
+
|
| 156 |
+
if ((word)link & (ALIGNMENT-1))
|
| 157 |
+
ABORT("Bad arg to GC_general_register_disappearing_link");
|
| 158 |
+
# ifdef THREADS
|
| 159 |
+
LOCK();
|
| 160 |
+
# endif
|
| 161 |
+
if (log_dl_table_size == -1
|
| 162 |
+
|| GC_dl_entries > ((word)1 << log_dl_table_size)) {
|
| 163 |
+
GC_grow_table((struct hash_chain_entry ***)(&dl_head),
|
| 164 |
+
&log_dl_table_size);
|
| 165 |
+
if (GC_print_stats) {
|
| 166 |
+
GC_log_printf("Grew dl table to %u entries\n",
|
| 167 |
+
(1 << log_dl_table_size));
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
index = HASH2(link, log_dl_table_size);
|
| 171 |
+
curr_dl = dl_head[index];
|
| 172 |
+
for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
|
| 173 |
+
if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
|
| 174 |
+
curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
|
| 175 |
+
# ifdef THREADS
|
| 176 |
+
UNLOCK();
|
| 177 |
+
# endif
|
| 178 |
+
return(1);
|
| 179 |
+
}
|
| 180 |
+
}
|
| 181 |
+
new_dl = (struct disappearing_link *)
|
| 182 |
+
GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
|
| 183 |
+
if (0 == new_dl) {
|
| 184 |
+
# ifdef THREADS
|
| 185 |
+
UNLOCK();
|
| 186 |
+
# endif
|
| 187 |
+
new_dl = (struct disappearing_link *)
|
| 188 |
+
GC_oom_fn(sizeof(struct disappearing_link));
|
| 189 |
+
if (0 == new_dl) {
|
| 190 |
+
GC_finalization_failures++;
|
| 191 |
+
return(0);
|
| 192 |
+
}
|
| 193 |
+
/* It's not likely we'll make it here, but ... */
|
| 194 |
+
# ifdef THREADS
|
| 195 |
+
LOCK();
|
| 196 |
+
# endif
|
| 197 |
+
}
|
| 198 |
+
new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
|
| 199 |
+
new_dl -> dl_hidden_link = HIDE_POINTER(link);
|
| 200 |
+
dl_set_next(new_dl, dl_head[index]);
|
| 201 |
+
dl_head[index] = new_dl;
|
| 202 |
+
GC_dl_entries++;
|
| 203 |
+
# ifdef THREADS
|
| 204 |
+
UNLOCK();
|
| 205 |
+
# endif
|
| 206 |
+
return(0);
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
int GC_unregister_disappearing_link(void * * link)
|
| 210 |
+
{
|
| 211 |
+
struct disappearing_link *curr_dl, *prev_dl;
|
| 212 |
+
size_t index;
|
| 213 |
+
DCL_LOCK_STATE;
|
| 214 |
+
|
| 215 |
+
LOCK();
|
| 216 |
+
index = HASH2(link, log_dl_table_size);
|
| 217 |
+
if (((word)link & (ALIGNMENT-1))) goto out;
|
| 218 |
+
prev_dl = 0; curr_dl = dl_head[index];
|
| 219 |
+
while (curr_dl != 0) {
|
| 220 |
+
if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
|
| 221 |
+
if (prev_dl == 0) {
|
| 222 |
+
dl_head[index] = dl_next(curr_dl);
|
| 223 |
+
} else {
|
| 224 |
+
dl_set_next(prev_dl, dl_next(curr_dl));
|
| 225 |
+
}
|
| 226 |
+
GC_dl_entries--;
|
| 227 |
+
UNLOCK();
|
| 228 |
+
# ifdef DBG_HDRS_ALL
|
| 229 |
+
dl_set_next(curr_dl, 0);
|
| 230 |
+
# else
|
| 231 |
+
GC_free((void *)curr_dl);
|
| 232 |
+
# endif
|
| 233 |
+
return(1);
|
| 234 |
+
}
|
| 235 |
+
prev_dl = curr_dl;
|
| 236 |
+
curr_dl = dl_next(curr_dl);
|
| 237 |
+
}
|
| 238 |
+
out:
|
| 239 |
+
UNLOCK();
|
| 240 |
+
return(0);
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
/* Possible finalization_marker procedures. Note that mark stack */
|
| 244 |
+
/* overflow is handled by the caller, and is not a disaster. */
|
| 245 |
+
GC_API void GC_normal_finalize_mark_proc(ptr_t p)
|
| 246 |
+
{
|
| 247 |
+
hdr * hhdr = HDR(p);
|
| 248 |
+
|
| 249 |
+
PUSH_OBJ(p, hhdr, GC_mark_stack_top,
|
| 250 |
+
&(GC_mark_stack[GC_mark_stack_size]));
|
| 251 |
+
}
|
| 252 |
+
|
| 253 |
+
/* This only pays very partial attention to the mark descriptor. */
|
| 254 |
+
/* It does the right thing for normal and atomic objects, and treats */
|
| 255 |
+
/* most others as normal. */
|
| 256 |
+
GC_API void GC_ignore_self_finalize_mark_proc(ptr_t p)
|
| 257 |
+
{
|
| 258 |
+
hdr * hhdr = HDR(p);
|
| 259 |
+
word descr = hhdr -> hb_descr;
|
| 260 |
+
ptr_t q, r;
|
| 261 |
+
ptr_t scan_limit;
|
| 262 |
+
ptr_t target_limit = p + hhdr -> hb_sz - 1;
|
| 263 |
+
|
| 264 |
+
if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
|
| 265 |
+
scan_limit = p + descr - sizeof(word);
|
| 266 |
+
} else {
|
| 267 |
+
scan_limit = target_limit + 1 - sizeof(word);
|
| 268 |
+
}
|
| 269 |
+
for (q = p; q <= scan_limit; q += ALIGNMENT) {
|
| 270 |
+
r = *(ptr_t *)q;
|
| 271 |
+
if (r < p || r > target_limit) {
|
| 272 |
+
GC_PUSH_ONE_HEAP(r, q);
|
| 273 |
+
}
|
| 274 |
+
}
|
| 275 |
+
}
|
| 276 |
+
|
| 277 |
+
/*ARGSUSED*/
|
| 278 |
+
GC_API void GC_null_finalize_mark_proc(ptr_t p)
|
| 279 |
+
{
|
| 280 |
+
}
|
| 281 |
+
|
| 282 |
+
/* Possible finalization_marker procedures. Note that mark stack */
|
| 283 |
+
/* overflow is handled by the caller, and is not a disaster. */
|
| 284 |
+
|
| 285 |
+
/* GC_unreachable_finalize_mark_proc is an alias for normal marking, */
|
| 286 |
+
/* but it is explicitly tested for, and triggers different */
|
| 287 |
+
/* behavior. Objects registered in this way are not finalized */
|
| 288 |
+
/* if they are reachable by other finalizable objects, eve if those */
|
| 289 |
+
/* other objects specify no ordering. */
|
| 290 |
+
GC_API void GC_unreachable_finalize_mark_proc(ptr_t p)
|
| 291 |
+
{
|
| 292 |
+
GC_normal_finalize_mark_proc(p);
|
| 293 |
+
}
|
| 294 |
+
|
| 295 |
+
|
| 296 |
+
|
| 297 |
+
/* Register a finalization function. See gc.h for details. */
|
| 298 |
+
/* in the nonthreads case, we try to avoid disabling signals, */
|
| 299 |
+
/* since it can be expensive. Threads packages typically */
|
| 300 |
+
/* make it cheaper. */
|
| 301 |
+
/* The last parameter is a procedure that determines */
|
| 302 |
+
/* marking for finalization ordering. Any objects marked */
|
| 303 |
+
/* by that procedure will be guaranteed to not have been */
|
| 304 |
+
/* finalized when this finalizer is invoked. */
|
| 305 |
+
GC_API void GC_register_finalizer_inner(void * obj,
|
| 306 |
+
GC_finalization_proc fn, void *cd,
|
| 307 |
+
GC_finalization_proc *ofn, void **ocd,
|
| 308 |
+
finalization_mark_proc mp)
|
| 309 |
+
{
|
| 310 |
+
ptr_t base;
|
| 311 |
+
struct finalizable_object * curr_fo, * prev_fo;
|
| 312 |
+
size_t index;
|
| 313 |
+
struct finalizable_object *new_fo;
|
| 314 |
+
hdr *hhdr;
|
| 315 |
+
DCL_LOCK_STATE;
|
| 316 |
+
|
| 317 |
+
# ifdef THREADS
|
| 318 |
+
LOCK();
|
| 319 |
+
# endif
|
| 320 |
+
if (log_fo_table_size == -1
|
| 321 |
+
|| GC_fo_entries > ((word)1 << log_fo_table_size)) {
|
| 322 |
+
GC_grow_table((struct hash_chain_entry ***)(&fo_head),
|
| 323 |
+
&log_fo_table_size);
|
| 324 |
+
if (GC_print_stats) {
|
| 325 |
+
GC_log_printf("Grew fo table to %u entries\n",
|
| 326 |
+
(1 << log_fo_table_size));
|
| 327 |
+
}
|
| 328 |
+
}
|
| 329 |
+
/* in the THREADS case signals are disabled and we hold allocation */
|
| 330 |
+
/* lock; otherwise neither is true. Proceed carefully. */
|
| 331 |
+
base = (ptr_t)obj;
|
| 332 |
+
index = HASH2(base, log_fo_table_size);
|
| 333 |
+
prev_fo = 0; curr_fo = fo_head[index];
|
| 334 |
+
while (curr_fo != 0) {
|
| 335 |
+
GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
|
| 336 |
+
if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
|
| 337 |
+
/* Interruption by a signal in the middle of this */
|
| 338 |
+
/* should be safe. The client may see only *ocd */
|
| 339 |
+
/* updated, but we'll declare that to be his */
|
| 340 |
+
/* problem. */
|
| 341 |
+
if (ocd) *ocd = (void *) (curr_fo -> fo_client_data);
|
| 342 |
+
if (ofn) *ofn = curr_fo -> fo_fn;
|
| 343 |
+
/* Delete the structure for base. */
|
| 344 |
+
if (prev_fo == 0) {
|
| 345 |
+
fo_head[index] = fo_next(curr_fo);
|
| 346 |
+
} else {
|
| 347 |
+
fo_set_next(prev_fo, fo_next(curr_fo));
|
| 348 |
+
}
|
| 349 |
+
if (fn == 0) {
|
| 350 |
+
GC_fo_entries--;
|
| 351 |
+
/* May not happen if we get a signal. But a high */
|
| 352 |
+
/* estimate will only make the table larger than */
|
| 353 |
+
/* necessary. */
|
| 354 |
+
# if !defined(THREADS) && !defined(DBG_HDRS_ALL)
|
| 355 |
+
GC_free((void *)curr_fo);
|
| 356 |
+
# endif
|
| 357 |
+
} else {
|
| 358 |
+
curr_fo -> fo_fn = fn;
|
| 359 |
+
curr_fo -> fo_client_data = (ptr_t)cd;
|
| 360 |
+
curr_fo -> fo_mark_proc = mp;
|
| 361 |
+
/* Reinsert it. We deleted it first to maintain */
|
| 362 |
+
/* consistency in the event of a signal. */
|
| 363 |
+
if (prev_fo == 0) {
|
| 364 |
+
fo_head[index] = curr_fo;
|
| 365 |
+
} else {
|
| 366 |
+
fo_set_next(prev_fo, curr_fo);
|
| 367 |
+
}
|
| 368 |
+
}
|
| 369 |
+
# ifdef THREADS
|
| 370 |
+
UNLOCK();
|
| 371 |
+
# endif
|
| 372 |
+
return;
|
| 373 |
+
}
|
| 374 |
+
prev_fo = curr_fo;
|
| 375 |
+
curr_fo = fo_next(curr_fo);
|
| 376 |
+
}
|
| 377 |
+
if (ofn) *ofn = 0;
|
| 378 |
+
if (ocd) *ocd = 0;
|
| 379 |
+
if (fn == 0) {
|
| 380 |
+
# ifdef THREADS
|
| 381 |
+
UNLOCK();
|
| 382 |
+
# endif
|
| 383 |
+
return;
|
| 384 |
+
}
|
| 385 |
+
GET_HDR(base, hhdr);
|
| 386 |
+
if (0 == hhdr) {
|
| 387 |
+
/* We won't collect it, hence finalizer wouldn't be run. */
|
| 388 |
+
# ifdef THREADS
|
| 389 |
+
UNLOCK();
|
| 390 |
+
# endif
|
| 391 |
+
return;
|
| 392 |
+
}
|
| 393 |
+
new_fo = (struct finalizable_object *)
|
| 394 |
+
GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
|
| 395 |
+
GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object));
|
| 396 |
+
if (EXPECT(0 == new_fo, FALSE)) {
|
| 397 |
+
# ifdef THREADS
|
| 398 |
+
UNLOCK();
|
| 399 |
+
# endif
|
| 400 |
+
new_fo = (struct finalizable_object *)
|
| 401 |
+
GC_oom_fn(sizeof(struct finalizable_object));
|
| 402 |
+
if (0 == new_fo) {
|
| 403 |
+
GC_finalization_failures++;
|
| 404 |
+
return;
|
| 405 |
+
}
|
| 406 |
+
/* It's not likely we'll make it here, but ... */
|
| 407 |
+
# ifdef THREADS
|
| 408 |
+
LOCK();
|
| 409 |
+
# endif
|
| 410 |
+
}
|
| 411 |
+
new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
|
| 412 |
+
new_fo -> fo_fn = fn;
|
| 413 |
+
new_fo -> fo_client_data = (ptr_t)cd;
|
| 414 |
+
new_fo -> fo_object_size = hhdr -> hb_sz;
|
| 415 |
+
new_fo -> fo_mark_proc = mp;
|
| 416 |
+
fo_set_next(new_fo, fo_head[index]);
|
| 417 |
+
GC_fo_entries++;
|
| 418 |
+
fo_head[index] = new_fo;
|
| 419 |
+
# ifdef THREADS
|
| 420 |
+
UNLOCK();
|
| 421 |
+
# endif
|
| 422 |
+
}
|
| 423 |
+
|
| 424 |
+
void GC_register_finalizer(void * obj,
|
| 425 |
+
GC_finalization_proc fn, void * cd,
|
| 426 |
+
GC_finalization_proc *ofn, void ** ocd)
|
| 427 |
+
{
|
| 428 |
+
GC_register_finalizer_inner(obj, fn, cd, ofn,
|
| 429 |
+
ocd, GC_normal_finalize_mark_proc);
|
| 430 |
+
}
|
| 431 |
+
|
| 432 |
+
void GC_register_finalizer_ignore_self(void * obj,
|
| 433 |
+
GC_finalization_proc fn, void * cd,
|
| 434 |
+
GC_finalization_proc *ofn, void ** ocd)
|
| 435 |
+
{
|
| 436 |
+
GC_register_finalizer_inner(obj, fn, cd, ofn,
|
| 437 |
+
ocd, GC_ignore_self_finalize_mark_proc);
|
| 438 |
+
}
|
| 439 |
+
|
| 440 |
+
void GC_register_finalizer_no_order(void * obj,
|
| 441 |
+
GC_finalization_proc fn, void * cd,
|
| 442 |
+
GC_finalization_proc *ofn, void ** ocd)
|
| 443 |
+
{
|
| 444 |
+
GC_register_finalizer_inner(obj, fn, cd, ofn,
|
| 445 |
+
ocd, GC_null_finalize_mark_proc);
|
| 446 |
+
}
|
| 447 |
+
|
| 448 |
+
static GC_bool need_unreachable_finalization = FALSE;
|
| 449 |
+
/* Avoid the work if this isn't used. */
|
| 450 |
+
|
| 451 |
+
void GC_register_finalizer_unreachable(void * obj,
|
| 452 |
+
GC_finalization_proc fn, void * cd,
|
| 453 |
+
GC_finalization_proc *ofn, void ** ocd)
|
| 454 |
+
{
|
| 455 |
+
need_unreachable_finalization = TRUE;
|
| 456 |
+
GC_ASSERT(GC_java_finalization);
|
| 457 |
+
GC_register_finalizer_inner(obj, fn, cd, ofn,
|
| 458 |
+
ocd, GC_unreachable_finalize_mark_proc);
|
| 459 |
+
}
|
| 460 |
+
|
| 461 |
+
#ifndef NO_DEBUGGING
|
| 462 |
+
void GC_dump_finalization(void)
|
| 463 |
+
{
|
| 464 |
+
struct disappearing_link * curr_dl;
|
| 465 |
+
struct finalizable_object * curr_fo;
|
| 466 |
+
ptr_t real_ptr, real_link;
|
| 467 |
+
int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
|
| 468 |
+
int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
|
| 469 |
+
int i;
|
| 470 |
+
|
| 471 |
+
GC_printf("Disappearing links:\n");
|
| 472 |
+
for (i = 0; i < dl_size; i++) {
|
| 473 |
+
for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
|
| 474 |
+
real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
|
| 475 |
+
real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
|
| 476 |
+
GC_printf("Object: %p, Link:%p\n", real_ptr, real_link);
|
| 477 |
+
}
|
| 478 |
+
}
|
| 479 |
+
GC_printf("Finalizers:\n");
|
| 480 |
+
for (i = 0; i < fo_size; i++) {
|
| 481 |
+
for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
|
| 482 |
+
real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
| 483 |
+
GC_printf("Finalizable object: %p\n", real_ptr);
|
| 484 |
+
}
|
| 485 |
+
}
|
| 486 |
+
}
|
| 487 |
+
#endif
|
| 488 |
+
|
| 489 |
+
/* Called with world stopped. Cause disappearing links to disappear, */
|
| 490 |
+
/* and invoke finalizers. */
|
| 491 |
+
void GC_finalize(void)
|
| 492 |
+
{
|
| 493 |
+
struct disappearing_link * curr_dl, * prev_dl, * next_dl;
|
| 494 |
+
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
|
| 495 |
+
ptr_t real_ptr, real_link;
|
| 496 |
+
size_t i;
|
| 497 |
+
size_t dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
|
| 498 |
+
size_t fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
|
| 499 |
+
|
| 500 |
+
/* Make disappearing links disappear */
|
| 501 |
+
for (i = 0; i < dl_size; i++) {
|
| 502 |
+
curr_dl = dl_head[i];
|
| 503 |
+
prev_dl = 0;
|
| 504 |
+
while (curr_dl != 0) {
|
| 505 |
+
real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
|
| 506 |
+
real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
|
| 507 |
+
if (!GC_is_marked(real_ptr)) {
|
| 508 |
+
*(word *)real_link = 0;
|
| 509 |
+
next_dl = dl_next(curr_dl);
|
| 510 |
+
if (prev_dl == 0) {
|
| 511 |
+
dl_head[i] = next_dl;
|
| 512 |
+
} else {
|
| 513 |
+
dl_set_next(prev_dl, next_dl);
|
| 514 |
+
}
|
| 515 |
+
GC_clear_mark_bit((ptr_t)curr_dl);
|
| 516 |
+
GC_dl_entries--;
|
| 517 |
+
curr_dl = next_dl;
|
| 518 |
+
} else {
|
| 519 |
+
prev_dl = curr_dl;
|
| 520 |
+
curr_dl = dl_next(curr_dl);
|
| 521 |
+
}
|
| 522 |
+
}
|
| 523 |
+
}
|
| 524 |
+
/* Mark all objects reachable via chains of 1 or more pointers */
|
| 525 |
+
/* from finalizable objects. */
|
| 526 |
+
GC_ASSERT(GC_mark_state == MS_NONE);
|
| 527 |
+
for (i = 0; i < fo_size; i++) {
|
| 528 |
+
for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
|
| 529 |
+
GC_ASSERT(GC_size(curr_fo) >= sizeof(struct finalizable_object));
|
| 530 |
+
real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
| 531 |
+
if (!GC_is_marked(real_ptr)) {
|
| 532 |
+
GC_MARKED_FOR_FINALIZATION(real_ptr);
|
| 533 |
+
GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
|
| 534 |
+
if (GC_is_marked(real_ptr)) {
|
| 535 |
+
WARN("Finalization cycle involving %lx\n", real_ptr);
|
| 536 |
+
}
|
| 537 |
+
}
|
| 538 |
+
}
|
| 539 |
+
}
|
| 540 |
+
/* Enqueue for finalization all objects that are still */
|
| 541 |
+
/* unreachable. */
|
| 542 |
+
GC_bytes_finalized = 0;
|
| 543 |
+
for (i = 0; i < fo_size; i++) {
|
| 544 |
+
curr_fo = fo_head[i];
|
| 545 |
+
prev_fo = 0;
|
| 546 |
+
while (curr_fo != 0) {
|
| 547 |
+
real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
| 548 |
+
if (!GC_is_marked(real_ptr)) {
|
| 549 |
+
if (!GC_java_finalization) {
|
| 550 |
+
GC_set_mark_bit(real_ptr);
|
| 551 |
+
}
|
| 552 |
+
/* Delete from hash table */
|
| 553 |
+
next_fo = fo_next(curr_fo);
|
| 554 |
+
if (prev_fo == 0) {
|
| 555 |
+
fo_head[i] = next_fo;
|
| 556 |
+
} else {
|
| 557 |
+
fo_set_next(prev_fo, next_fo);
|
| 558 |
+
}
|
| 559 |
+
GC_fo_entries--;
|
| 560 |
+
/* Add to list of objects awaiting finalization. */
|
| 561 |
+
fo_set_next(curr_fo, GC_finalize_now);
|
| 562 |
+
GC_finalize_now = curr_fo;
|
| 563 |
+
/* unhide object pointer so any future collections will */
|
| 564 |
+
/* see it. */
|
| 565 |
+
curr_fo -> fo_hidden_base =
|
| 566 |
+
(word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
| 567 |
+
GC_bytes_finalized +=
|
| 568 |
+
curr_fo -> fo_object_size
|
| 569 |
+
+ sizeof(struct finalizable_object);
|
| 570 |
+
GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
|
| 571 |
+
curr_fo = next_fo;
|
| 572 |
+
} else {
|
| 573 |
+
prev_fo = curr_fo;
|
| 574 |
+
curr_fo = fo_next(curr_fo);
|
| 575 |
+
}
|
| 576 |
+
}
|
| 577 |
+
}
|
| 578 |
+
|
| 579 |
+
if (GC_java_finalization) {
|
| 580 |
+
/* make sure we mark everything reachable from objects finalized
|
| 581 |
+
using the no_order mark_proc */
|
| 582 |
+
for (curr_fo = GC_finalize_now;
|
| 583 |
+
curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
|
| 584 |
+
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
|
| 585 |
+
if (!GC_is_marked(real_ptr)) {
|
| 586 |
+
if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
|
| 587 |
+
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
|
| 588 |
+
}
|
| 589 |
+
if (curr_fo -> fo_mark_proc != GC_unreachable_finalize_mark_proc) {
|
| 590 |
+
GC_set_mark_bit(real_ptr);
|
| 591 |
+
}
|
| 592 |
+
}
|
| 593 |
+
}
|
| 594 |
+
|
| 595 |
+
/* now revive finalize-when-unreachable objects reachable from
|
| 596 |
+
other finalizable objects */
|
| 597 |
+
if (need_unreachable_finalization) {
|
| 598 |
+
curr_fo = GC_finalize_now;
|
| 599 |
+
prev_fo = 0;
|
| 600 |
+
while (curr_fo != 0) {
|
| 601 |
+
next_fo = fo_next(curr_fo);
|
| 602 |
+
if (curr_fo -> fo_mark_proc == GC_unreachable_finalize_mark_proc) {
|
| 603 |
+
real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
|
| 604 |
+
if (!GC_is_marked(real_ptr)) {
|
| 605 |
+
GC_set_mark_bit(real_ptr);
|
| 606 |
+
} else {
|
| 607 |
+
if (prev_fo == 0)
|
| 608 |
+
GC_finalize_now = next_fo;
|
| 609 |
+
else
|
| 610 |
+
fo_set_next(prev_fo, next_fo);
|
| 611 |
+
|
| 612 |
+
curr_fo -> fo_hidden_base =
|
| 613 |
+
(word) HIDE_POINTER(curr_fo -> fo_hidden_base);
|
| 614 |
+
GC_bytes_finalized -=
|
| 615 |
+
curr_fo -> fo_object_size + sizeof(struct finalizable_object);
|
| 616 |
+
|
| 617 |
+
i = HASH2(real_ptr, log_fo_table_size);
|
| 618 |
+
fo_set_next (curr_fo, fo_head[i]);
|
| 619 |
+
GC_fo_entries++;
|
| 620 |
+
fo_head[i] = curr_fo;
|
| 621 |
+
curr_fo = prev_fo;
|
| 622 |
+
}
|
| 623 |
+
}
|
| 624 |
+
prev_fo = curr_fo;
|
| 625 |
+
curr_fo = next_fo;
|
| 626 |
+
}
|
| 627 |
+
}
|
| 628 |
+
}
|
| 629 |
+
|
| 630 |
+
/* Remove dangling disappearing links. */
|
| 631 |
+
for (i = 0; i < dl_size; i++) {
|
| 632 |
+
curr_dl = dl_head[i];
|
| 633 |
+
prev_dl = 0;
|
| 634 |
+
while (curr_dl != 0) {
|
| 635 |
+
real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
|
| 636 |
+
if (real_link != 0 && !GC_is_marked(real_link)) {
|
| 637 |
+
next_dl = dl_next(curr_dl);
|
| 638 |
+
if (prev_dl == 0) {
|
| 639 |
+
dl_head[i] = next_dl;
|
| 640 |
+
} else {
|
| 641 |
+
dl_set_next(prev_dl, next_dl);
|
| 642 |
+
}
|
| 643 |
+
GC_clear_mark_bit((ptr_t)curr_dl);
|
| 644 |
+
GC_dl_entries--;
|
| 645 |
+
curr_dl = next_dl;
|
| 646 |
+
} else {
|
| 647 |
+
prev_dl = curr_dl;
|
| 648 |
+
curr_dl = dl_next(curr_dl);
|
| 649 |
+
}
|
| 650 |
+
}
|
| 651 |
+
}
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
#ifndef JAVA_FINALIZATION_NOT_NEEDED
|
| 655 |
+
|
| 656 |
+
/* Enqueue all remaining finalizers to be run - Assumes lock is
|
| 657 |
+
* held, and signals are disabled */
|
| 658 |
+
void GC_enqueue_all_finalizers(void)
|
| 659 |
+
{
|
| 660 |
+
struct finalizable_object * curr_fo, * prev_fo, * next_fo;
|
| 661 |
+
ptr_t real_ptr;
|
| 662 |
+
register int i;
|
| 663 |
+
int fo_size;
|
| 664 |
+
|
| 665 |
+
fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
|
| 666 |
+
GC_bytes_finalized = 0;
|
| 667 |
+
for (i = 0; i < fo_size; i++) {
|
| 668 |
+
curr_fo = fo_head[i];
|
| 669 |
+
prev_fo = 0;
|
| 670 |
+
while (curr_fo != 0) {
|
| 671 |
+
real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
| 672 |
+
GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
|
| 673 |
+
GC_set_mark_bit(real_ptr);
|
| 674 |
+
|
| 675 |
+
/* Delete from hash table */
|
| 676 |
+
next_fo = fo_next(curr_fo);
|
| 677 |
+
if (prev_fo == 0) {
|
| 678 |
+
fo_head[i] = next_fo;
|
| 679 |
+
} else {
|
| 680 |
+
fo_set_next(prev_fo, next_fo);
|
| 681 |
+
}
|
| 682 |
+
GC_fo_entries--;
|
| 683 |
+
|
| 684 |
+
/* Add to list of objects awaiting finalization. */
|
| 685 |
+
fo_set_next(curr_fo, GC_finalize_now);
|
| 686 |
+
GC_finalize_now = curr_fo;
|
| 687 |
+
|
| 688 |
+
/* unhide object pointer so any future collections will */
|
| 689 |
+
/* see it. */
|
| 690 |
+
curr_fo -> fo_hidden_base =
|
| 691 |
+
(word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
|
| 692 |
+
|
| 693 |
+
GC_bytes_finalized +=
|
| 694 |
+
curr_fo -> fo_object_size + sizeof(struct finalizable_object);
|
| 695 |
+
curr_fo = next_fo;
|
| 696 |
+
}
|
| 697 |
+
}
|
| 698 |
+
|
| 699 |
+
return;
|
| 700 |
+
}
|
| 701 |
+
|
| 702 |
+
/* Invoke all remaining finalizers that haven't yet been run.
|
| 703 |
+
* This is needed for strict compliance with the Java standard,
|
| 704 |
+
* which can make the runtime guarantee that all finalizers are run.
|
| 705 |
+
* Unfortunately, the Java standard implies we have to keep running
|
| 706 |
+
* finalizers until there are no more left, a potential infinite loop.
|
| 707 |
+
* YUCK.
|
| 708 |
+
* Note that this is even more dangerous than the usual Java
|
| 709 |
+
* finalizers, in that objects reachable from static variables
|
| 710 |
+
* may have been finalized when these finalizers are run.
|
| 711 |
+
* Finalizers run at this point must be prepared to deal with a
|
| 712 |
+
* mostly broken world.
|
| 713 |
+
* This routine is externally callable, so is called without
|
| 714 |
+
* the allocation lock.
|
| 715 |
+
*/
|
| 716 |
+
GC_API void GC_finalize_all(void)
|
| 717 |
+
{
|
| 718 |
+
DCL_LOCK_STATE;
|
| 719 |
+
|
| 720 |
+
LOCK();
|
| 721 |
+
while (GC_fo_entries > 0) {
|
| 722 |
+
GC_enqueue_all_finalizers();
|
| 723 |
+
UNLOCK();
|
| 724 |
+
GC_INVOKE_FINALIZERS();
|
| 725 |
+
LOCK();
|
| 726 |
+
}
|
| 727 |
+
UNLOCK();
|
| 728 |
+
}
|
| 729 |
+
#endif
|
| 730 |
+
|
| 731 |
+
/* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
|
| 732 |
+
/* finalizers can only be called from some kind of `safe state' and */
|
| 733 |
+
/* getting into that safe state is expensive.) */
|
| 734 |
+
int GC_should_invoke_finalizers(void)
|
| 735 |
+
{
|
| 736 |
+
return GC_finalize_now != 0;
|
| 737 |
+
}
|
| 738 |
+
|
| 739 |
+
/* Invoke finalizers for all objects that are ready to be finalized. */
|
| 740 |
+
/* Should be called without allocation lock. */
|
| 741 |
+
int GC_invoke_finalizers(void)
|
| 742 |
+
{
|
| 743 |
+
struct finalizable_object * curr_fo;
|
| 744 |
+
int count = 0;
|
| 745 |
+
word bytes_freed_before;
|
| 746 |
+
DCL_LOCK_STATE;
|
| 747 |
+
|
| 748 |
+
while (GC_finalize_now != 0) {
|
| 749 |
+
# ifdef THREADS
|
| 750 |
+
LOCK();
|
| 751 |
+
# endif
|
| 752 |
+
if (count == 0) {
|
| 753 |
+
bytes_freed_before = GC_bytes_freed;
|
| 754 |
+
/* Don't do this outside, since we need the lock. */
|
| 755 |
+
}
|
| 756 |
+
curr_fo = GC_finalize_now;
|
| 757 |
+
# ifdef THREADS
|
| 758 |
+
if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
|
| 759 |
+
UNLOCK();
|
| 760 |
+
if (curr_fo == 0) break;
|
| 761 |
+
# else
|
| 762 |
+
GC_finalize_now = fo_next(curr_fo);
|
| 763 |
+
# endif
|
| 764 |
+
fo_set_next(curr_fo, 0);
|
| 765 |
+
(*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
|
| 766 |
+
curr_fo -> fo_client_data);
|
| 767 |
+
curr_fo -> fo_client_data = 0;
|
| 768 |
+
++count;
|
| 769 |
+
# ifdef UNDEFINED
|
| 770 |
+
/* This is probably a bad idea. It throws off accounting if */
|
| 771 |
+
/* nearly all objects are finalizable. O.w. it shouldn't */
|
| 772 |
+
/* matter. */
|
| 773 |
+
GC_free((void *)curr_fo);
|
| 774 |
+
# endif
|
| 775 |
+
}
|
| 776 |
+
/* bytes_freed_before is initialized whenever count != 0 */
|
| 777 |
+
if (count != 0 && bytes_freed_before != GC_bytes_freed) {
|
| 778 |
+
LOCK();
|
| 779 |
+
GC_finalizer_bytes_freed += (GC_bytes_freed - bytes_freed_before);
|
| 780 |
+
UNLOCK();
|
| 781 |
+
}
|
| 782 |
+
return count;
|
| 783 |
+
}
|
| 784 |
+
|
| 785 |
+
void (* GC_finalizer_notifier)() = (void (*) (void))0;
|
| 786 |
+
|
| 787 |
+
static GC_word last_finalizer_notification = 0;
|
| 788 |
+
|
| 789 |
+
void GC_notify_or_invoke_finalizers(void)
|
| 790 |
+
{
|
| 791 |
+
/* This is a convenient place to generate backtraces if appropriate, */
|
| 792 |
+
/* since that code is not callable with the allocation lock. */
|
| 793 |
+
# if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
|
| 794 |
+
static word last_back_trace_gc_no = 1; /* Skip first one. */
|
| 795 |
+
|
| 796 |
+
if (GC_gc_no > last_back_trace_gc_no) {
|
| 797 |
+
word i;
|
| 798 |
+
|
| 799 |
+
# ifdef KEEP_BACK_PTRS
|
| 800 |
+
LOCK();
|
| 801 |
+
/* Stops when GC_gc_no wraps; that's OK. */
|
| 802 |
+
last_back_trace_gc_no = (word)(-1); /* disable others. */
|
| 803 |
+
for (i = 0; i < GC_backtraces; ++i) {
|
| 804 |
+
/* FIXME: This tolerates concurrent heap mutation, */
|
| 805 |
+
/* which may cause occasional mysterious results. */
|
| 806 |
+
/* We need to release the GC lock, since GC_print_callers */
|
| 807 |
+
/* acquires it. It probably shouldn't. */
|
| 808 |
+
UNLOCK();
|
| 809 |
+
GC_generate_random_backtrace_no_gc();
|
| 810 |
+
LOCK();
|
| 811 |
+
}
|
| 812 |
+
last_back_trace_gc_no = GC_gc_no;
|
| 813 |
+
UNLOCK();
|
| 814 |
+
# endif
|
| 815 |
+
# ifdef MAKE_BACK_GRAPH
|
| 816 |
+
if (GC_print_back_height)
|
| 817 |
+
GC_print_back_graph_stats();
|
| 818 |
+
# endif
|
| 819 |
+
}
|
| 820 |
+
# endif
|
| 821 |
+
if (GC_finalize_now == 0) return;
|
| 822 |
+
if (!GC_finalize_on_demand) {
|
| 823 |
+
(void) GC_invoke_finalizers();
|
| 824 |
+
# ifndef THREADS
|
| 825 |
+
GC_ASSERT(GC_finalize_now == 0);
|
| 826 |
+
# endif /* Otherwise GC can run concurrently and add more */
|
| 827 |
+
return;
|
| 828 |
+
}
|
| 829 |
+
if (GC_finalizer_notifier != (void (*) (void))0
|
| 830 |
+
&& last_finalizer_notification != GC_gc_no) {
|
| 831 |
+
last_finalizer_notification = GC_gc_no;
|
| 832 |
+
GC_finalizer_notifier();
|
| 833 |
+
}
|
| 834 |
+
}
|
| 835 |
+
|
| 836 |
+
void * GC_call_with_alloc_lock(GC_fn_type fn, void * client_data)
|
| 837 |
+
{
|
| 838 |
+
void * result;
|
| 839 |
+
DCL_LOCK_STATE;
|
| 840 |
+
|
| 841 |
+
# ifdef THREADS
|
| 842 |
+
LOCK();
|
| 843 |
+
/* FIXME - This looks wrong!! */
|
| 844 |
+
SET_LOCK_HOLDER();
|
| 845 |
+
# endif
|
| 846 |
+
result = (*fn)(client_data);
|
| 847 |
+
# ifdef THREADS
|
| 848 |
+
# ifndef GC_ASSERTIONS
|
| 849 |
+
UNSET_LOCK_HOLDER();
|
| 850 |
+
# endif /* o.w. UNLOCK() does it implicitly */
|
| 851 |
+
UNLOCK();
|
| 852 |
+
# endif
|
| 853 |
+
return(result);
|
| 854 |
+
}
|
| 855 |
+
|
| 856 |
+
#if !defined(NO_DEBUGGING)
|
| 857 |
+
|
| 858 |
+
void GC_print_finalization_stats(void)
|
| 859 |
+
{
|
| 860 |
+
struct finalizable_object *fo = GC_finalize_now;
|
| 861 |
+
size_t ready = 0;
|
| 862 |
+
|
| 863 |
+
GC_printf("%u finalization table entries; %u disappearing links\n",
|
| 864 |
+
GC_fo_entries, GC_dl_entries);
|
| 865 |
+
for (; 0 != fo; fo = fo_next(fo)) ++ready;
|
| 866 |
+
GC_printf("%u objects are eligible for immediate finalization\n", ready);
|
| 867 |
+
}
|
| 868 |
+
|
| 869 |
+
#endif /* NO_DEBUGGING */
|
mosesdecoder/jam-files/engine/boehm_gc/gc.mak
ADDED
|
@@ -0,0 +1,2220 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Microsoft Developer Studio Generated NMAKE File, Format Version 4.10
|
| 2 |
+
# This has been hand-edited way too many times.
|
| 3 |
+
# A clean, manually generated makefile would be an improvement.
|
| 4 |
+
|
| 5 |
+
# TARGTYPE "Win32 (x86) Application" 0x0101
|
| 6 |
+
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
| 7 |
+
|
| 8 |
+
AO_VERSION=1.2
|
| 9 |
+
!IF "$(CFG)" == ""
|
| 10 |
+
CFG=gctest - Win32 Release
|
| 11 |
+
!MESSAGE No configuration specified. Defaulting to cord - Win32 Debug.
|
| 12 |
+
!ENDIF
|
| 13 |
+
|
| 14 |
+
!IF "$(CFG)" != "gc - Win32 Release" && "$(CFG)" != "gc - Win32 Debug" &&\
|
| 15 |
+
"$(CFG)" != "gctest - Win32 Release" && "$(CFG)" != "gctest - Win32 Debug" &&\
|
| 16 |
+
"$(CFG)" != "cord - Win32 Release" && "$(CFG)" != "cord - Win32 Debug"
|
| 17 |
+
!MESSAGE Invalid configuration "$(CFG)" specified.
|
| 18 |
+
!MESSAGE You can specify a configuration when running NMAKE on this makefile
|
| 19 |
+
!MESSAGE by defining the macro CFG on the command line. For example:
|
| 20 |
+
!MESSAGE
|
| 21 |
+
!MESSAGE NMAKE /f "gc.mak" CFG="cord - Win32 Debug"
|
| 22 |
+
!MESSAGE
|
| 23 |
+
!MESSAGE Possible choices for configuration are:
|
| 24 |
+
!MESSAGE
|
| 25 |
+
!MESSAGE "gc - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
| 26 |
+
!MESSAGE "gc - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
| 27 |
+
!MESSAGE "gctest - Win32 Release" (based on "Win32 (x86) Application")
|
| 28 |
+
!MESSAGE "gctest - Win32 Debug" (based on "Win32 (x86) Application")
|
| 29 |
+
!MESSAGE "cord - Win32 Release" (based on "Win32 (x86) Application")
|
| 30 |
+
!MESSAGE "cord - Win32 Debug" (based on "Win32 (x86) Application")
|
| 31 |
+
!MESSAGE
|
| 32 |
+
!ERROR An invalid configuration is specified.
|
| 33 |
+
!ENDIF
|
| 34 |
+
|
| 35 |
+
!IF "$(OS)" == "Windows_NT"
|
| 36 |
+
NULL=
|
| 37 |
+
!ELSE
|
| 38 |
+
NULL=nul
|
| 39 |
+
!ENDIF
|
| 40 |
+
################################################################################
|
| 41 |
+
# Begin Project
|
| 42 |
+
# PROP Target_Last_Scanned "gctest - Win32 Debug"
|
| 43 |
+
|
| 44 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 45 |
+
|
| 46 |
+
# PROP BASE Use_MFC 0
|
| 47 |
+
# PROP BASE Use_Debug_Libraries 0
|
| 48 |
+
# PROP BASE Output_Dir "Release"
|
| 49 |
+
# PROP BASE Intermediate_Dir "Release"
|
| 50 |
+
# PROP BASE Target_Dir ""
|
| 51 |
+
# PROP Use_MFC 0
|
| 52 |
+
# PROP Use_Debug_Libraries 0
|
| 53 |
+
# PROP Output_Dir "Release"
|
| 54 |
+
# PROP Intermediate_Dir "Release"
|
| 55 |
+
# PROP Target_Dir ""
|
| 56 |
+
OUTDIR=.\Release
|
| 57 |
+
INTDIR=.\Release
|
| 58 |
+
|
| 59 |
+
ALL : ".\Release\gc.dll" ".\Release\gc.bsc"
|
| 60 |
+
|
| 61 |
+
CLEAN :
|
| 62 |
+
-@erase ".\Release\allchblk.obj"
|
| 63 |
+
-@erase ".\Release\allchblk.sbr"
|
| 64 |
+
-@erase ".\Release\alloc.obj"
|
| 65 |
+
-@erase ".\Release\alloc.sbr"
|
| 66 |
+
-@erase ".\Release\blacklst.obj"
|
| 67 |
+
-@erase ".\Release\blacklst.sbr"
|
| 68 |
+
-@erase ".\Release\checksums.obj"
|
| 69 |
+
-@erase ".\Release\checksums.sbr"
|
| 70 |
+
-@erase ".\Release\dbg_mlc.obj"
|
| 71 |
+
-@erase ".\Release\dbg_mlc.sbr"
|
| 72 |
+
-@erase ".\Release\dyn_load.obj"
|
| 73 |
+
-@erase ".\Release\dyn_load.sbr"
|
| 74 |
+
-@erase ".\Release\finalize.obj"
|
| 75 |
+
-@erase ".\Release\finalize.sbr"
|
| 76 |
+
-@erase ".\Release\gc.bsc"
|
| 77 |
+
-@erase ".\Release\gc_cpp.obj"
|
| 78 |
+
-@erase ".\Release\gc_cpp.sbr"
|
| 79 |
+
-@erase ".\Release\gc.dll"
|
| 80 |
+
-@erase ".\Release\gc.exp"
|
| 81 |
+
-@erase ".\Release\gc.lib"
|
| 82 |
+
-@erase ".\Release\headers.obj"
|
| 83 |
+
-@erase ".\Release\headers.sbr"
|
| 84 |
+
-@erase ".\Release\mach_dep.obj"
|
| 85 |
+
-@erase ".\Release\mach_dep.sbr"
|
| 86 |
+
-@erase ".\Release\malloc.obj"
|
| 87 |
+
-@erase ".\Release\malloc.sbr"
|
| 88 |
+
-@erase ".\Release\mallocx.obj"
|
| 89 |
+
-@erase ".\Release\mallocx.sbr"
|
| 90 |
+
-@erase ".\Release\mark.obj"
|
| 91 |
+
-@erase ".\Release\mark.sbr"
|
| 92 |
+
-@erase ".\Release\mark_rts.obj"
|
| 93 |
+
-@erase ".\Release\mark_rts.sbr"
|
| 94 |
+
-@erase ".\Release\misc.obj"
|
| 95 |
+
-@erase ".\Release\misc.sbr"
|
| 96 |
+
-@erase ".\Release\new_hblk.obj"
|
| 97 |
+
-@erase ".\Release\new_hblk.sbr"
|
| 98 |
+
-@erase ".\Release\obj_map.obj"
|
| 99 |
+
-@erase ".\Release\obj_map.sbr"
|
| 100 |
+
-@erase ".\Release\os_dep.obj"
|
| 101 |
+
-@erase ".\Release\os_dep.sbr"
|
| 102 |
+
-@erase ".\Release\ptr_chck.obj"
|
| 103 |
+
-@erase ".\Release\ptr_chck.sbr"
|
| 104 |
+
-@erase ".\Release\reclaim.obj"
|
| 105 |
+
-@erase ".\Release\reclaim.sbr"
|
| 106 |
+
-@erase ".\Release\stubborn.obj"
|
| 107 |
+
-@erase ".\Release\stubborn.sbr"
|
| 108 |
+
-@erase ".\Release\typd_mlc.obj"
|
| 109 |
+
-@erase ".\Release\typd_mlc.sbr"
|
| 110 |
+
-@erase ".\Release\win32_threads.obj"
|
| 111 |
+
-@erase ".\Release\win32_threads.sbr"
|
| 112 |
+
-@erase ".\Release\msvc_dbg.obj"
|
| 113 |
+
-@erase ".\Release\msvc_dbg.sbr"
|
| 114 |
+
|
| 115 |
+
"$(OUTDIR)" :
|
| 116 |
+
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
| 117 |
+
|
| 118 |
+
CPP=cl.exe
|
| 119 |
+
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
|
| 120 |
+
# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
|
| 121 |
+
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "GC_BUILD" /D\
|
| 122 |
+
"WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D\
|
| 123 |
+
"GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" \
|
| 124 |
+
/Ilibatomic_ops-$(AO_VERSION)/src /YX /Fo"$(INTDIR)/" /c
|
| 125 |
+
CPP_OBJS=.\Release/
|
| 126 |
+
CPP_SBRS=.\Release/
|
| 127 |
+
|
| 128 |
+
.c{$(CPP_OBJS)}.obj:
|
| 129 |
+
$(CPP) $(CPP_PROJ) $<
|
| 130 |
+
|
| 131 |
+
.cpp{$(CPP_OBJS)}.obj:
|
| 132 |
+
$(CPP) $(CPP_PROJ) $<
|
| 133 |
+
|
| 134 |
+
.cxx{$(CPP_OBJS)}.obj:
|
| 135 |
+
$(CPP) $(CPP_PROJ) $<
|
| 136 |
+
|
| 137 |
+
.c{$(CPP_SBRS)}.sbr:
|
| 138 |
+
$(CPP) $(CPP_PROJ) $<
|
| 139 |
+
|
| 140 |
+
.cpp{$(CPP_SBRS)}.sbr:
|
| 141 |
+
$(CPP) $(CPP_PROJ) $<
|
| 142 |
+
|
| 143 |
+
.cxx{$(CPP_SBRS)}.sbr:
|
| 144 |
+
$(CPP) $(CPP_PROJ) $<
|
| 145 |
+
|
| 146 |
+
MTL=mktyplib.exe
|
| 147 |
+
# ADD BASE MTL /nologo /D "NDEBUG" /win32
|
| 148 |
+
# ADD MTL /nologo /D "NDEBUG" /win32
|
| 149 |
+
MTL_PROJ=/nologo /D "NDEBUG" /win32
|
| 150 |
+
RSC=rc.exe
|
| 151 |
+
# ADD BASE RSC /l 0x809 /d "NDEBUG"
|
| 152 |
+
# ADD RSC /l 0x809 /d "NDEBUG"
|
| 153 |
+
BSC32=bscmake.exe
|
| 154 |
+
# ADD BASE BSC32 /nologo
|
| 155 |
+
# ADD BSC32 /nologo
|
| 156 |
+
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
|
| 157 |
+
BSC32_SBRS= \
|
| 158 |
+
".\Release\allchblk.sbr" \
|
| 159 |
+
".\Release\alloc.sbr" \
|
| 160 |
+
".\Release\blacklst.sbr" \
|
| 161 |
+
".\Release\checksums.sbr" \
|
| 162 |
+
".\Release\dbg_mlc.sbr" \
|
| 163 |
+
".\Release\dyn_load.sbr" \
|
| 164 |
+
".\Release\finalize.sbr" \
|
| 165 |
+
".\Release\gc_cpp.sbr" \
|
| 166 |
+
".\Release\headers.sbr" \
|
| 167 |
+
".\Release\mach_dep.sbr" \
|
| 168 |
+
".\Release\malloc.sbr" \
|
| 169 |
+
".\Release\mallocx.sbr" \
|
| 170 |
+
".\Release\mark.sbr" \
|
| 171 |
+
".\Release\mark_rts.sbr" \
|
| 172 |
+
".\Release\misc.sbr" \
|
| 173 |
+
".\Release\new_hblk.sbr" \
|
| 174 |
+
".\Release\obj_map.sbr" \
|
| 175 |
+
".\Release\os_dep.sbr" \
|
| 176 |
+
".\Release\ptr_chck.sbr" \
|
| 177 |
+
".\Release\reclaim.sbr" \
|
| 178 |
+
".\Release\stubborn.sbr" \
|
| 179 |
+
".\Release\typd_mlc.sbr" \
|
| 180 |
+
".\Release\msvc_dbg.sbr" \
|
| 181 |
+
".\Release\win32_threads.sbr"
|
| 182 |
+
|
| 183 |
+
".\Release\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
|
| 184 |
+
$(BSC32) @<<
|
| 185 |
+
$(BSC32_FLAGS) $(BSC32_SBRS)
|
| 186 |
+
<<
|
| 187 |
+
|
| 188 |
+
LINK32=link.exe
|
| 189 |
+
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
|
| 190 |
+
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
|
| 191 |
+
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
| 192 |
+
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
| 193 |
+
odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
|
| 194 |
+
/pdb:"$(OUTDIR)/gc.pdb" /machine:I386 /out:"$(OUTDIR)/gc.dll"\
|
| 195 |
+
/implib:"$(OUTDIR)/gc.lib"
|
| 196 |
+
LINK32_OBJS= \
|
| 197 |
+
".\Release\allchblk.obj" \
|
| 198 |
+
".\Release\alloc.obj" \
|
| 199 |
+
".\Release\blacklst.obj" \
|
| 200 |
+
".\Release\checksums.obj" \
|
| 201 |
+
".\Release\dbg_mlc.obj" \
|
| 202 |
+
".\Release\dyn_load.obj" \
|
| 203 |
+
".\Release\finalize.obj" \
|
| 204 |
+
".\Release\gc_cpp.obj" \
|
| 205 |
+
".\Release\headers.obj" \
|
| 206 |
+
".\Release\mach_dep.obj" \
|
| 207 |
+
".\Release\malloc.obj" \
|
| 208 |
+
".\Release\mallocx.obj" \
|
| 209 |
+
".\Release\mark.obj" \
|
| 210 |
+
".\Release\mark_rts.obj" \
|
| 211 |
+
".\Release\misc.obj" \
|
| 212 |
+
".\Release\new_hblk.obj" \
|
| 213 |
+
".\Release\obj_map.obj" \
|
| 214 |
+
".\Release\os_dep.obj" \
|
| 215 |
+
".\Release\ptr_chck.obj" \
|
| 216 |
+
".\Release\reclaim.obj" \
|
| 217 |
+
".\Release\stubborn.obj" \
|
| 218 |
+
".\Release\typd_mlc.obj" \
|
| 219 |
+
".\Release\msvc_dbg.obj" \
|
| 220 |
+
".\Release\win32_threads.obj"
|
| 221 |
+
|
| 222 |
+
".\Release\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
| 223 |
+
$(LINK32) @<<
|
| 224 |
+
$(LINK32_FLAGS) $(LINK32_OBJS)
|
| 225 |
+
<<
|
| 226 |
+
|
| 227 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 228 |
+
|
| 229 |
+
# PROP BASE Use_MFC 0
|
| 230 |
+
# PROP BASE Use_Debug_Libraries 1
|
| 231 |
+
# PROP BASE Output_Dir "Debug"
|
| 232 |
+
# PROP BASE Intermediate_Dir "Debug"
|
| 233 |
+
# PROP BASE Target_Dir ""
|
| 234 |
+
# PROP Use_MFC 0
|
| 235 |
+
# PROP Use_Debug_Libraries 1
|
| 236 |
+
# PROP Output_Dir "Debug"
|
| 237 |
+
# PROP Intermediate_Dir "Debug"
|
| 238 |
+
# PROP Target_Dir ""
|
| 239 |
+
OUTDIR=.\Debug
|
| 240 |
+
INTDIR=.\Debug
|
| 241 |
+
|
| 242 |
+
ALL : ".\Debug\gc.dll" ".\Debug\gc.bsc"
|
| 243 |
+
|
| 244 |
+
CLEAN :
|
| 245 |
+
-@erase ".\Debug\allchblk.obj"
|
| 246 |
+
-@erase ".\Debug\allchblk.sbr"
|
| 247 |
+
-@erase ".\Debug\alloc.obj"
|
| 248 |
+
-@erase ".\Debug\alloc.sbr"
|
| 249 |
+
-@erase ".\Debug\blacklst.obj"
|
| 250 |
+
-@erase ".\Debug\blacklst.sbr"
|
| 251 |
+
-@erase ".\Debug\checksums.obj"
|
| 252 |
+
-@erase ".\Debug\checksums.sbr"
|
| 253 |
+
-@erase ".\Debug\dbg_mlc.obj"
|
| 254 |
+
-@erase ".\Debug\dbg_mlc.sbr"
|
| 255 |
+
-@erase ".\Debug\dyn_load.obj"
|
| 256 |
+
-@erase ".\Debug\dyn_load.sbr"
|
| 257 |
+
-@erase ".\Debug\finalize.obj"
|
| 258 |
+
-@erase ".\Debug\finalize.sbr"
|
| 259 |
+
-@erase ".\Debug\gc_cpp.obj"
|
| 260 |
+
-@erase ".\Debug\gc_cpp.sbr"
|
| 261 |
+
-@erase ".\Debug\gc.bsc"
|
| 262 |
+
-@erase ".\Debug\gc.dll"
|
| 263 |
+
-@erase ".\Debug\gc.exp"
|
| 264 |
+
-@erase ".\Debug\gc.lib"
|
| 265 |
+
-@erase ".\Debug\gc.map"
|
| 266 |
+
-@erase ".\Debug\gc.pdb"
|
| 267 |
+
-@erase ".\Debug\headers.obj"
|
| 268 |
+
-@erase ".\Debug\headers.sbr"
|
| 269 |
+
-@erase ".\Debug\mach_dep.obj"
|
| 270 |
+
-@erase ".\Debug\mach_dep.sbr"
|
| 271 |
+
-@erase ".\Debug\malloc.obj"
|
| 272 |
+
-@erase ".\Debug\malloc.sbr"
|
| 273 |
+
-@erase ".\Debug\mallocx.obj"
|
| 274 |
+
-@erase ".\Debug\mallocx.sbr"
|
| 275 |
+
-@erase ".\Debug\mark.obj"
|
| 276 |
+
-@erase ".\Debug\mark.sbr"
|
| 277 |
+
-@erase ".\Debug\mark_rts.obj"
|
| 278 |
+
-@erase ".\Debug\mark_rts.sbr"
|
| 279 |
+
-@erase ".\Debug\misc.obj"
|
| 280 |
+
-@erase ".\Debug\misc.sbr"
|
| 281 |
+
-@erase ".\Debug\new_hblk.obj"
|
| 282 |
+
-@erase ".\Debug\new_hblk.sbr"
|
| 283 |
+
-@erase ".\Debug\obj_map.obj"
|
| 284 |
+
-@erase ".\Debug\obj_map.sbr"
|
| 285 |
+
-@erase ".\Debug\os_dep.obj"
|
| 286 |
+
-@erase ".\Debug\os_dep.sbr"
|
| 287 |
+
-@erase ".\Debug\ptr_chck.obj"
|
| 288 |
+
-@erase ".\Debug\ptr_chck.sbr"
|
| 289 |
+
-@erase ".\Debug\reclaim.obj"
|
| 290 |
+
-@erase ".\Debug\reclaim.sbr"
|
| 291 |
+
-@erase ".\Debug\stubborn.obj"
|
| 292 |
+
-@erase ".\Debug\stubborn.sbr"
|
| 293 |
+
-@erase ".\Debug\typd_mlc.obj"
|
| 294 |
+
-@erase ".\Debug\typd_mlc.sbr"
|
| 295 |
+
-@erase ".\Debug\vc40.idb"
|
| 296 |
+
-@erase ".\Debug\vc40.pdb"
|
| 297 |
+
-@erase ".\Debug\win32_threads.obj"
|
| 298 |
+
-@erase ".\Debug\win32_threads.sbr"
|
| 299 |
+
-@erase ".\Debug\msvc_dbg.obj"
|
| 300 |
+
-@erase ".\Debug\msvc_dbg.sbr"
|
| 301 |
+
|
| 302 |
+
"$(OUTDIR)" :
|
| 303 |
+
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
| 304 |
+
|
| 305 |
+
CPP=cl.exe
|
| 306 |
+
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
|
| 307 |
+
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "GC_BUILD" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
|
| 308 |
+
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "GC_BUILD"\
|
| 309 |
+
/D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" \
|
| 310 |
+
/D "GC_ASSERTIONS" /D "__STDC__" /D\
|
| 311 |
+
"GC_WIN32_THREADS" /FR"$(INTDIR)/" /Fp"$(INTDIR)/gc.pch" /YX /Fo"$(INTDIR)/"\
|
| 312 |
+
/Ilibatomic_ops-$(AO_VERSION)/src /Fd"$(INTDIR)/" /c
|
| 313 |
+
CPP_OBJS=.\Debug/
|
| 314 |
+
CPP_SBRS=.\Debug/
|
| 315 |
+
|
| 316 |
+
.c{$(CPP_OBJS)}.obj:
|
| 317 |
+
$(CPP) $(CPP_PROJ) $<
|
| 318 |
+
|
| 319 |
+
.cpp{$(CPP_OBJS)}.obj:
|
| 320 |
+
$(CPP) $(CPP_PROJ) $<
|
| 321 |
+
|
| 322 |
+
.cxx{$(CPP_OBJS)}.obj:
|
| 323 |
+
$(CPP) $(CPP_PROJ) $<
|
| 324 |
+
|
| 325 |
+
.c{$(CPP_SBRS)}.sbr:
|
| 326 |
+
$(CPP) $(CPP_PROJ) $<
|
| 327 |
+
|
| 328 |
+
.cpp{$(CPP_SBRS)}.sbr:
|
| 329 |
+
$(CPP) $(CPP_PROJ) $<
|
| 330 |
+
|
| 331 |
+
.cxx{$(CPP_SBRS)}.sbr:
|
| 332 |
+
$(CPP) $(CPP_PROJ) $<
|
| 333 |
+
|
| 334 |
+
MTL=mktyplib.exe
|
| 335 |
+
# ADD BASE MTL /nologo /D "_DEBUG" /win32
|
| 336 |
+
# ADD MTL /nologo /D "_DEBUG" /win32
|
| 337 |
+
MTL_PROJ=/nologo /D "_DEBUG" /win32
|
| 338 |
+
RSC=rc.exe
|
| 339 |
+
# ADD BASE RSC /l 0x809 /d "_DEBUG"
|
| 340 |
+
# ADD RSC /l 0x809 /d "_DEBUG"
|
| 341 |
+
BSC32=bscmake.exe
|
| 342 |
+
# ADD BASE BSC32 /nologo
|
| 343 |
+
# ADD BSC32 /nologo
|
| 344 |
+
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gc.bsc"
|
| 345 |
+
BSC32_SBRS= \
|
| 346 |
+
".\Debug\allchblk.sbr" \
|
| 347 |
+
".\Debug\alloc.sbr" \
|
| 348 |
+
".\Debug\blacklst.sbr" \
|
| 349 |
+
".\Debug\checksums.sbr" \
|
| 350 |
+
".\Debug\dbg_mlc.sbr" \
|
| 351 |
+
".\Debug\dyn_load.sbr" \
|
| 352 |
+
".\Debug\finalize.sbr" \
|
| 353 |
+
".\Debug\gc_cpp.sbr" \
|
| 354 |
+
".\Debug\headers.sbr" \
|
| 355 |
+
".\Debug\mach_dep.sbr" \
|
| 356 |
+
".\Debug\malloc.sbr" \
|
| 357 |
+
".\Debug\mallocx.sbr" \
|
| 358 |
+
".\Debug\mark.sbr" \
|
| 359 |
+
".\Debug\mark_rts.sbr" \
|
| 360 |
+
".\Debug\misc.sbr" \
|
| 361 |
+
".\Debug\new_hblk.sbr" \
|
| 362 |
+
".\Debug\obj_map.sbr" \
|
| 363 |
+
".\Debug\os_dep.sbr" \
|
| 364 |
+
".\Debug\ptr_chck.sbr" \
|
| 365 |
+
".\Debug\reclaim.sbr" \
|
| 366 |
+
".\Debug\stubborn.sbr" \
|
| 367 |
+
".\Debug\typd_mlc.sbr" \
|
| 368 |
+
".\Debug\msvc_dbg.sbr" \
|
| 369 |
+
".\Debug\win32_threads.sbr"
|
| 370 |
+
|
| 371 |
+
".\Debug\gc.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
|
| 372 |
+
$(BSC32) @<<
|
| 373 |
+
$(BSC32_FLAGS) $(BSC32_SBRS)
|
| 374 |
+
<<
|
| 375 |
+
|
| 376 |
+
LINK32=link.exe
|
| 377 |
+
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
|
| 378 |
+
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /incremental:no /map /debug /machine:I386
|
| 379 |
+
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
| 380 |
+
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
| 381 |
+
odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
|
| 382 |
+
/pdb:"$(OUTDIR)/gc.pdb" /map:"$(INTDIR)/gc.map" /debug /machine:I386\
|
| 383 |
+
/out:"$(OUTDIR)/gc.dll" /implib:"$(OUTDIR)/gc.lib"
|
| 384 |
+
LINK32_OBJS= \
|
| 385 |
+
".\Debug\allchblk.obj" \
|
| 386 |
+
".\Debug\alloc.obj" \
|
| 387 |
+
".\Debug\blacklst.obj" \
|
| 388 |
+
".\Debug\checksums.obj" \
|
| 389 |
+
".\Debug\dbg_mlc.obj" \
|
| 390 |
+
".\Debug\dyn_load.obj" \
|
| 391 |
+
".\Debug\finalize.obj" \
|
| 392 |
+
".\Debug\gc_cpp.obj" \
|
| 393 |
+
".\Debug\headers.obj" \
|
| 394 |
+
".\Debug\mach_dep.obj" \
|
| 395 |
+
".\Debug\malloc.obj" \
|
| 396 |
+
".\Debug\mallocx.obj" \
|
| 397 |
+
".\Debug\mark.obj" \
|
| 398 |
+
".\Debug\mark_rts.obj" \
|
| 399 |
+
".\Debug\misc.obj" \
|
| 400 |
+
".\Debug\new_hblk.obj" \
|
| 401 |
+
".\Debug\obj_map.obj" \
|
| 402 |
+
".\Debug\os_dep.obj" \
|
| 403 |
+
".\Debug\ptr_chck.obj" \
|
| 404 |
+
".\Debug\reclaim.obj" \
|
| 405 |
+
".\Debug\stubborn.obj" \
|
| 406 |
+
".\Debug\typd_mlc.obj" \
|
| 407 |
+
".\Debug\msvc_dbg.obj" \
|
| 408 |
+
".\Debug\win32_threads.obj"
|
| 409 |
+
|
| 410 |
+
".\Debug\gc.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
| 411 |
+
$(LINK32) @<<
|
| 412 |
+
$(LINK32_FLAGS) $(LINK32_OBJS)
|
| 413 |
+
<<
|
| 414 |
+
|
| 415 |
+
!ELSEIF "$(CFG)" == "gctest - Win32 Release"
|
| 416 |
+
|
| 417 |
+
# PROP BASE Use_MFC 0
|
| 418 |
+
# PROP BASE Use_Debug_Libraries 0
|
| 419 |
+
# PROP BASE Output_Dir "gctest\Release"
|
| 420 |
+
# PROP BASE Intermediate_Dir "gctest\Release"
|
| 421 |
+
# PROP BASE Target_Dir "gctest"
|
| 422 |
+
# PROP Use_MFC 0
|
| 423 |
+
# PROP Use_Debug_Libraries 0
|
| 424 |
+
# PROP Output_Dir "gctest\Release"
|
| 425 |
+
# PROP Intermediate_Dir "gctest\Release"
|
| 426 |
+
# PROP Target_Dir "gctest"
|
| 427 |
+
OUTDIR=.\gctest\Release
|
| 428 |
+
INTDIR=.\gctest\Release
|
| 429 |
+
|
| 430 |
+
ALL : "gc - Win32 Release" ".\Release\gctest.exe"
|
| 431 |
+
|
| 432 |
+
CLEAN :
|
| 433 |
+
-@erase ".\gctest\Release\test.obj"
|
| 434 |
+
-@erase ".\Release\gctest.exe"
|
| 435 |
+
|
| 436 |
+
"$(OUTDIR)" :
|
| 437 |
+
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
| 438 |
+
|
| 439 |
+
test.c : tests\test.c
|
| 440 |
+
copy tests\test.c test.c
|
| 441 |
+
|
| 442 |
+
CPP=cl.exe
|
| 443 |
+
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
|
| 444 |
+
# ADD CPP /nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /YX /c
|
| 445 |
+
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
|
| 446 |
+
"ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS"\
|
| 447 |
+
/Ilibatomic_ops-$(AO_VERSION)/src /Fp"$(INTDIR)/gctest.pch" \
|
| 448 |
+
/YX /Fo"$(INTDIR)/" /c
|
| 449 |
+
CPP_OBJS=.\gctest\Release/
|
| 450 |
+
CPP_SBRS=.\.
|
| 451 |
+
|
| 452 |
+
.c{$(CPP_OBJS)}.obj:
|
| 453 |
+
$(CPP) $(CPP_PROJ) $<
|
| 454 |
+
|
| 455 |
+
.cpp{$(CPP_OBJS)}.obj:
|
| 456 |
+
$(CPP) $(CPP_PROJ) $<
|
| 457 |
+
|
| 458 |
+
.cxx{$(CPP_OBJS)}.obj:
|
| 459 |
+
$(CPP) $(CPP_PROJ) $<
|
| 460 |
+
|
| 461 |
+
.c{$(CPP_SBRS)}.sbr:
|
| 462 |
+
$(CPP) $(CPP_PROJ) $<
|
| 463 |
+
|
| 464 |
+
.cpp{$(CPP_SBRS)}.sbr:
|
| 465 |
+
$(CPP) $(CPP_PROJ) $<
|
| 466 |
+
|
| 467 |
+
.cxx{$(CPP_SBRS)}.sbr:
|
| 468 |
+
$(CPP) $(CPP_PROJ) $<
|
| 469 |
+
|
| 470 |
+
MTL=mktyplib.exe
|
| 471 |
+
# ADD BASE MTL /nologo /D "NDEBUG" /win32
|
| 472 |
+
# ADD MTL /nologo /D "NDEBUG" /win32
|
| 473 |
+
MTL_PROJ=/nologo /D "NDEBUG" /win32
|
| 474 |
+
RSC=rc.exe
|
| 475 |
+
# ADD BASE RSC /l 0x809 /d "NDEBUG"
|
| 476 |
+
# ADD RSC /l 0x809 /d "NDEBUG"
|
| 477 |
+
BSC32=bscmake.exe
|
| 478 |
+
# ADD BASE BSC32 /nologo
|
| 479 |
+
# ADD BSC32 /nologo
|
| 480 |
+
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
|
| 481 |
+
BSC32_SBRS= \
|
| 482 |
+
|
| 483 |
+
LINK32=link.exe
|
| 484 |
+
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
| 485 |
+
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/gctest.exe"
|
| 486 |
+
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
| 487 |
+
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
| 488 |
+
odbccp32.lib /nologo /subsystem:windows /incremental:no\
|
| 489 |
+
/pdb:"$(OUTDIR)/gctest.pdb" /machine:I386 /out:"Release/gctest.exe"
|
| 490 |
+
LINK32_OBJS= \
|
| 491 |
+
".\gctest\Release\test.obj" \
|
| 492 |
+
".\Release\gc.lib"
|
| 493 |
+
|
| 494 |
+
".\Release\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
| 495 |
+
$(LINK32) @<<
|
| 496 |
+
$(LINK32_FLAGS) $(LINK32_OBJS)
|
| 497 |
+
<<
|
| 498 |
+
|
| 499 |
+
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
|
| 500 |
+
|
| 501 |
+
# PROP BASE Use_MFC 0
|
| 502 |
+
# PROP BASE Use_Debug_Libraries 1
|
| 503 |
+
# PROP BASE Output_Dir "gctest\Debug"
|
| 504 |
+
# PROP BASE Intermediate_Dir "gctest\Debug"
|
| 505 |
+
# PROP BASE Target_Dir "gctest"
|
| 506 |
+
# PROP Use_MFC 0
|
| 507 |
+
# PROP Use_Debug_Libraries 1
|
| 508 |
+
# PROP Output_Dir "gctest\Debug"
|
| 509 |
+
# PROP Intermediate_Dir "gctest\Debug"
|
| 510 |
+
# PROP Target_Dir "gctest"
|
| 511 |
+
OUTDIR=.\gctest\Debug
|
| 512 |
+
INTDIR=.\gctest\Debug
|
| 513 |
+
|
| 514 |
+
ALL : "gc - Win32 Debug" ".\Debug\gctest.exe" ".\gctest\Debug\gctest.bsc"
|
| 515 |
+
|
| 516 |
+
CLEAN :
|
| 517 |
+
-@erase ".\Debug\gctest.exe"
|
| 518 |
+
-@erase ".\gctest\Debug\gctest.bsc"
|
| 519 |
+
-@erase ".\gctest\Debug\gctest.map"
|
| 520 |
+
-@erase ".\gctest\Debug\gctest.pdb"
|
| 521 |
+
-@erase ".\gctest\Debug\test.obj"
|
| 522 |
+
-@erase ".\gctest\Debug\test.sbr"
|
| 523 |
+
-@erase ".\gctest\Debug\vc40.idb"
|
| 524 |
+
-@erase ".\gctest\Debug\vc40.pdb"
|
| 525 |
+
|
| 526 |
+
"$(OUTDIR)" :
|
| 527 |
+
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
| 528 |
+
|
| 529 |
+
CPP=cl.exe
|
| 530 |
+
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
|
| 531 |
+
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR /YX /c
|
| 532 |
+
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I include /D "_DEBUG" /D "WIN32" /D "_WINDOWS"\
|
| 533 |
+
/D "ALL_INTERIOR_POINTERS" /D "__STDC__" /D "GC_WIN32_THREADS" /FR"$(INTDIR)/"\
|
| 534 |
+
/Ilibatomic_ops-$(AO_VERSION)/src /Fp"$(INTDIR)/gctest.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
| 535 |
+
CPP_OBJS=.\gctest\Debug/
|
| 536 |
+
CPP_SBRS=.\gctest\Debug/
|
| 537 |
+
|
| 538 |
+
.c{$(CPP_OBJS)}.obj:
|
| 539 |
+
$(CPP) $(CPP_PROJ) $<
|
| 540 |
+
|
| 541 |
+
.cpp{$(CPP_OBJS)}.obj:
|
| 542 |
+
$(CPP) $(CPP_PROJ) $<
|
| 543 |
+
|
| 544 |
+
.cxx{$(CPP_OBJS)}.obj:
|
| 545 |
+
$(CPP) $(CPP_PROJ) $<
|
| 546 |
+
|
| 547 |
+
.c{$(CPP_SBRS)}.sbr:
|
| 548 |
+
$(CPP) $(CPP_PROJ) $<
|
| 549 |
+
|
| 550 |
+
.cpp{$(CPP_SBRS)}.sbr:
|
| 551 |
+
$(CPP) $(CPP_PROJ) $<
|
| 552 |
+
|
| 553 |
+
.cxx{$(CPP_SBRS)}.sbr:
|
| 554 |
+
$(CPP) $(CPP_PROJ) $<
|
| 555 |
+
|
| 556 |
+
MTL=mktyplib.exe
|
| 557 |
+
# ADD BASE MTL /nologo /D "_DEBUG" /win32
|
| 558 |
+
# ADD MTL /nologo /D "_DEBUG" /win32
|
| 559 |
+
MTL_PROJ=/nologo /D "_DEBUG" /win32
|
| 560 |
+
RSC=rc.exe
|
| 561 |
+
# ADD BASE RSC /l 0x809 /d "_DEBUG"
|
| 562 |
+
# ADD RSC /l 0x809 /d "_DEBUG"
|
| 563 |
+
BSC32=bscmake.exe
|
| 564 |
+
# ADD BASE BSC32 /nologo
|
| 565 |
+
# ADD BSC32 /nologo
|
| 566 |
+
BSC32_FLAGS=/nologo /o"$(OUTDIR)/gctest.bsc"
|
| 567 |
+
BSC32_SBRS= \
|
| 568 |
+
".\gctest\Debug\test.sbr"
|
| 569 |
+
|
| 570 |
+
".\gctest\Debug\gctest.bsc" : "$(OUTDIR)" $(BSC32_SBRS)
|
| 571 |
+
$(BSC32) @<<
|
| 572 |
+
$(BSC32_FLAGS) $(BSC32_SBRS)
|
| 573 |
+
<<
|
| 574 |
+
|
| 575 |
+
LINK32=link.exe
|
| 576 |
+
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
|
| 577 |
+
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no /map /debug /machine:I386 /out:"Debug/gctest.exe"
|
| 578 |
+
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
| 579 |
+
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
| 580 |
+
odbccp32.lib /nologo /subsystem:windows /incremental:no\
|
| 581 |
+
/pdb:"$(OUTDIR)/gctest.pdb" /map:"$(INTDIR)/gctest.map" /debug /machine:I386\
|
| 582 |
+
/out:"Debug/gctest.exe"
|
| 583 |
+
LINK32_OBJS= \
|
| 584 |
+
".\Debug\gc.lib" \
|
| 585 |
+
".\gctest\Debug\test.obj"
|
| 586 |
+
|
| 587 |
+
".\Debug\gctest.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
| 588 |
+
$(LINK32) @<<
|
| 589 |
+
$(LINK32_FLAGS) $(LINK32_OBJS)
|
| 590 |
+
<<
|
| 591 |
+
|
| 592 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Release"
|
| 593 |
+
|
| 594 |
+
# PROP BASE Use_MFC 0
|
| 595 |
+
# PROP BASE Use_Debug_Libraries 0
|
| 596 |
+
# PROP BASE Output_Dir "cord\Release"
|
| 597 |
+
# PROP BASE Intermediate_Dir "cord\Release"
|
| 598 |
+
# PROP BASE Target_Dir "cord"
|
| 599 |
+
# PROP Use_MFC 0
|
| 600 |
+
# PROP Use_Debug_Libraries 0
|
| 601 |
+
# PROP Output_Dir "cord\Release"
|
| 602 |
+
# PROP Intermediate_Dir "cord\Release"
|
| 603 |
+
# PROP Target_Dir "cord"
|
| 604 |
+
OUTDIR=.\cord\Release
|
| 605 |
+
INTDIR=.\cord\Release
|
| 606 |
+
|
| 607 |
+
ALL : "gc - Win32 Release" ".\Release\de.exe"
|
| 608 |
+
|
| 609 |
+
CLEAN :
|
| 610 |
+
-@erase ".\cord\Release\cordbscs.obj"
|
| 611 |
+
-@erase ".\cord\Release\cordxtra.obj"
|
| 612 |
+
-@erase ".\cord\Release\de.obj"
|
| 613 |
+
-@erase ".\cord\Release\de_win.obj"
|
| 614 |
+
-@erase ".\cord\Release\de_win.res"
|
| 615 |
+
-@erase ".\Release\de.exe"
|
| 616 |
+
|
| 617 |
+
"$(OUTDIR)" :
|
| 618 |
+
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
| 619 |
+
|
| 620 |
+
CPP=cl.exe
|
| 621 |
+
# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
|
| 622 |
+
# ADD CPP /nologo /MD /W3 /GX /O2 /I "." /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
|
| 623 |
+
CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "." /I include /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D\
|
| 624 |
+
/Ilibatomic_ops-$(AO_VERSION)/src "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX /Fo"$(INTDIR)/" /c
|
| 625 |
+
CPP_OBJS=.\cord\Release/
|
| 626 |
+
CPP_SBRS=.\.
|
| 627 |
+
|
| 628 |
+
.c{$(CPP_OBJS)}.obj:
|
| 629 |
+
$(CPP) $(CPP_PROJ) $<
|
| 630 |
+
|
| 631 |
+
.cpp{$(CPP_OBJS)}.obj:
|
| 632 |
+
$(CPP) $(CPP_PROJ) $<
|
| 633 |
+
|
| 634 |
+
.cxx{$(CPP_OBJS)}.obj:
|
| 635 |
+
$(CPP) $(CPP_PROJ) $<
|
| 636 |
+
|
| 637 |
+
.c{$(CPP_SBRS)}.sbr:
|
| 638 |
+
$(CPP) $(CPP_PROJ) $<
|
| 639 |
+
|
| 640 |
+
.cpp{$(CPP_SBRS)}.sbr:
|
| 641 |
+
$(CPP) $(CPP_PROJ) $<
|
| 642 |
+
|
| 643 |
+
.cxx{$(CPP_SBRS)}.sbr:
|
| 644 |
+
$(CPP) $(CPP_PROJ) $<
|
| 645 |
+
|
| 646 |
+
MTL=mktyplib.exe
|
| 647 |
+
# ADD BASE MTL /nologo /D "NDEBUG" /win32
|
| 648 |
+
# ADD MTL /nologo /D "NDEBUG" /win32
|
| 649 |
+
MTL_PROJ=/nologo /D "NDEBUG" /win32
|
| 650 |
+
RSC=rc.exe
|
| 651 |
+
# ADD BASE RSC /l 0x809 /d "NDEBUG"
|
| 652 |
+
# ADD RSC /l 0x809 /d "NDEBUG"
|
| 653 |
+
RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "NDEBUG"
|
| 654 |
+
BSC32=bscmake.exe
|
| 655 |
+
# ADD BASE BSC32 /nologo
|
| 656 |
+
# ADD BSC32 /nologo
|
| 657 |
+
BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
|
| 658 |
+
BSC32_SBRS= \
|
| 659 |
+
|
| 660 |
+
LINK32=link.exe
|
| 661 |
+
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
|
| 662 |
+
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/de.exe"
|
| 663 |
+
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
| 664 |
+
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
| 665 |
+
odbccp32.lib /nologo /subsystem:windows /incremental:no /pdb:"$(OUTDIR)/de.pdb"\
|
| 666 |
+
/machine:I386 /out:"Release/de.exe"
|
| 667 |
+
LINK32_OBJS= \
|
| 668 |
+
".\cord\Release\cordbscs.obj" \
|
| 669 |
+
".\cord\Release\cordxtra.obj" \
|
| 670 |
+
".\cord\Release\de.obj" \
|
| 671 |
+
".\cord\Release\de_win.obj" \
|
| 672 |
+
".\cord\Release\de_win.res" \
|
| 673 |
+
".\Release\gc.lib"
|
| 674 |
+
|
| 675 |
+
".\Release\de.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
| 676 |
+
$(LINK32) @<<
|
| 677 |
+
$(LINK32_FLAGS) $(LINK32_OBJS)
|
| 678 |
+
<<
|
| 679 |
+
|
| 680 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 681 |
+
|
| 682 |
+
# PROP BASE Use_MFC 0
|
| 683 |
+
# PROP BASE Use_Debug_Libraries 1
|
| 684 |
+
# PROP BASE Output_Dir "cord\Debug"
|
| 685 |
+
# PROP BASE Intermediate_Dir "cord\Debug"
|
| 686 |
+
# PROP BASE Target_Dir "cord"
|
| 687 |
+
# PROP Use_MFC 0
|
| 688 |
+
# PROP Use_Debug_Libraries 1
|
| 689 |
+
# PROP Output_Dir "cord\Debug"
|
| 690 |
+
# PROP Intermediate_Dir "cord\Debug"
|
| 691 |
+
# PROP Target_Dir "cord"
|
| 692 |
+
OUTDIR=.\cord\Debug
|
| 693 |
+
INTDIR=.\cord\Debug
|
| 694 |
+
|
| 695 |
+
ALL : "gc - Win32 Debug" ".\Debug\de.exe"
|
| 696 |
+
|
| 697 |
+
CLEAN :
|
| 698 |
+
-@erase ".\cord\Debug\cordbscs.obj"
|
| 699 |
+
-@erase ".\cord\Debug\cordxtra.obj"
|
| 700 |
+
-@erase ".\cord\Debug\de.obj"
|
| 701 |
+
-@erase ".\cord\Debug\de.pdb"
|
| 702 |
+
-@erase ".\cord\Debug\de_win.obj"
|
| 703 |
+
-@erase ".\cord\Debug\de_win.res"
|
| 704 |
+
-@erase ".\cord\Debug\vc40.idb"
|
| 705 |
+
-@erase ".\cord\Debug\vc40.pdb"
|
| 706 |
+
-@erase ".\Debug\de.exe"
|
| 707 |
+
-@erase ".\Debug\de.ilk"
|
| 708 |
+
|
| 709 |
+
"$(OUTDIR)" :
|
| 710 |
+
if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
|
| 711 |
+
|
| 712 |
+
CPP=cl.exe
|
| 713 |
+
# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
|
| 714 |
+
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "ALL_INTERIOR_POINTERS" /YX /c
|
| 715 |
+
CPP_PROJ=/nologo /MDd /W3 /Gm /GX /Zi /Od /I "." /I include /D "_DEBUG" /D "WIN32" /D\
|
| 716 |
+
"_WINDOWS" /D "ALL_INTERIOR_POINTERS" /Fp"$(INTDIR)/cord.pch" /YX\
|
| 717 |
+
/Ilibatomic_ops-$(AO_VERSION)/src /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
|
| 718 |
+
CPP_OBJS=.\cord\Debug/
|
| 719 |
+
CPP_SBRS=.\.
|
| 720 |
+
|
| 721 |
+
.c{$(CPP_OBJS)}.obj:
|
| 722 |
+
$(CPP) $(CPP_PROJ) $<
|
| 723 |
+
|
| 724 |
+
.cpp{$(CPP_OBJS)}.obj:
|
| 725 |
+
$(CPP) $(CPP_PROJ) $<
|
| 726 |
+
|
| 727 |
+
.cxx{$(CPP_OBJS)}.obj:
|
| 728 |
+
$(CPP) $(CPP_PROJ) $<
|
| 729 |
+
|
| 730 |
+
.c{$(CPP_SBRS)}.sbr:
|
| 731 |
+
$(CPP) $(CPP_PROJ) $<
|
| 732 |
+
|
| 733 |
+
.cpp{$(CPP_SBRS)}.sbr:
|
| 734 |
+
$(CPP) $(CPP_PROJ) $<
|
| 735 |
+
|
| 736 |
+
.cxx{$(CPP_SBRS)}.sbr:
|
| 737 |
+
$(CPP) $(CPP_PROJ) $<
|
| 738 |
+
|
| 739 |
+
MTL=mktyplib.exe
|
| 740 |
+
# ADD BASE MTL /nologo /D "_DEBUG" /win32
|
| 741 |
+
# ADD MTL /nologo /D "_DEBUG" /win32
|
| 742 |
+
MTL_PROJ=/nologo /D "_DEBUG" /win32
|
| 743 |
+
RSC=rc.exe
|
| 744 |
+
# ADD BASE RSC /l 0x809 /d "_DEBUG"
|
| 745 |
+
# ADD RSC /l 0x809 /d "_DEBUG"
|
| 746 |
+
RSC_PROJ=/l 0x809 /fo"$(INTDIR)/de_win.res" /d "_DEBUG"
|
| 747 |
+
BSC32=bscmake.exe
|
| 748 |
+
# ADD BASE BSC32 /nologo
|
| 749 |
+
# ADD BSC32 /nologo
|
| 750 |
+
BSC32_FLAGS=/nologo /o"$(OUTDIR)/cord.bsc"
|
| 751 |
+
BSC32_SBRS= \
|
| 752 |
+
|
| 753 |
+
LINK32=link.exe
|
| 754 |
+
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386
|
| 755 |
+
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/de.exe"
|
| 756 |
+
LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
|
| 757 |
+
advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
|
| 758 |
+
odbccp32.lib /nologo /subsystem:windows /incremental:yes\
|
| 759 |
+
/pdb:"$(OUTDIR)/de.pdb" /debug /machine:I386 /out:"Debug/de.exe"
|
| 760 |
+
LINK32_OBJS= \
|
| 761 |
+
".\cord\Debug\cordbscs.obj" \
|
| 762 |
+
".\cord\Debug\cordxtra.obj" \
|
| 763 |
+
".\cord\Debug\de.obj" \
|
| 764 |
+
".\cord\Debug\de_win.obj" \
|
| 765 |
+
".\cord\Debug\de_win.res" \
|
| 766 |
+
".\Debug\gc.lib"
|
| 767 |
+
|
| 768 |
+
".\Debug\de.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
|
| 769 |
+
$(LINK32) @<<
|
| 770 |
+
$(LINK32_FLAGS) $(LINK32_OBJS)
|
| 771 |
+
<<
|
| 772 |
+
|
| 773 |
+
!ENDIF
|
| 774 |
+
|
| 775 |
+
################################################################################
|
| 776 |
+
# Begin Target
|
| 777 |
+
|
| 778 |
+
# Name "gc - Win32 Release"
|
| 779 |
+
# Name "gc - Win32 Debug"
|
| 780 |
+
|
| 781 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 782 |
+
|
| 783 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 784 |
+
|
| 785 |
+
!ENDIF
|
| 786 |
+
|
| 787 |
+
################################################################################
|
| 788 |
+
# Begin Source File
|
| 789 |
+
|
| 790 |
+
SOURCE=.\gc_cpp.cpp
|
| 791 |
+
|
| 792 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 793 |
+
|
| 794 |
+
DEP_CPP_RECLA=\
|
| 795 |
+
".\include\private\gcconfig.h"\
|
| 796 |
+
".\include\gc.h"\
|
| 797 |
+
".\include\private\gc_hdrs.h"\
|
| 798 |
+
".\include\private\gc_priv.h"\
|
| 799 |
+
".\include\gc_cpp.h"\
|
| 800 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 801 |
+
|
| 802 |
+
NODEP_CPP_RECLA=\
|
| 803 |
+
".\th\PCR_Th.h"\
|
| 804 |
+
".\th\PCR_ThCrSec.h"\
|
| 805 |
+
".\th\PCR_ThCtl.h"\
|
| 806 |
+
|
| 807 |
+
|
| 808 |
+
".\Release\gc_cpp.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 809 |
+
|
| 810 |
+
".\Release\gc_cpp.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 811 |
+
|
| 812 |
+
|
| 813 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 814 |
+
|
| 815 |
+
DEP_CPP_RECLA=\
|
| 816 |
+
".\include\private\gcconfig.h"\
|
| 817 |
+
".\include\gc.h"\
|
| 818 |
+
".\include\private\gc_hdrs.h"\
|
| 819 |
+
".\include\private\gc_priv.h"\
|
| 820 |
+
".\include\gc_cpp.h"\
|
| 821 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 822 |
+
|
| 823 |
+
NODEP_CPP_RECLA=\
|
| 824 |
+
".\th\PCR_Th.h"\
|
| 825 |
+
".\th\PCR_ThCrSec.h"\
|
| 826 |
+
".\th\PCR_ThCtl.h"\
|
| 827 |
+
|
| 828 |
+
|
| 829 |
+
".\Debug\gc_cpp.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 830 |
+
|
| 831 |
+
".\Debug\gc_cpp.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 832 |
+
|
| 833 |
+
|
| 834 |
+
!ENDIF
|
| 835 |
+
|
| 836 |
+
# End Source File
|
| 837 |
+
################################################################################
|
| 838 |
+
# Begin Source File
|
| 839 |
+
|
| 840 |
+
SOURCE=.\reclaim.c
|
| 841 |
+
|
| 842 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 843 |
+
|
| 844 |
+
DEP_CPP_RECLA=\
|
| 845 |
+
".\include\private\gcconfig.h"\
|
| 846 |
+
".\include\gc.h"\
|
| 847 |
+
".\include\private\gc_hdrs.h"\
|
| 848 |
+
".\include\private\gc_priv.h"\
|
| 849 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 850 |
+
|
| 851 |
+
NODEP_CPP_RECLA=\
|
| 852 |
+
".\th\PCR_Th.h"\
|
| 853 |
+
".\th\PCR_ThCrSec.h"\
|
| 854 |
+
".\th\PCR_ThCtl.h"\
|
| 855 |
+
|
| 856 |
+
|
| 857 |
+
".\Release\reclaim.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 858 |
+
|
| 859 |
+
".\Release\reclaim.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 860 |
+
|
| 861 |
+
|
| 862 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 863 |
+
|
| 864 |
+
DEP_CPP_RECLA=\
|
| 865 |
+
".\include\private\gcconfig.h"\
|
| 866 |
+
".\include\gc.h"\
|
| 867 |
+
".\include\private\gc_hdrs.h"\
|
| 868 |
+
".\include\private\gc_priv.h"\
|
| 869 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 870 |
+
|
| 871 |
+
NODEP_CPP_RECLA=\
|
| 872 |
+
".\th\PCR_Th.h"\
|
| 873 |
+
".\th\PCR_ThCrSec.h"\
|
| 874 |
+
".\th\PCR_ThCtl.h"\
|
| 875 |
+
|
| 876 |
+
|
| 877 |
+
".\Debug\reclaim.obj" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 878 |
+
|
| 879 |
+
".\Debug\reclaim.sbr" : $(SOURCE) $(DEP_CPP_RECLA) "$(INTDIR)"
|
| 880 |
+
|
| 881 |
+
|
| 882 |
+
!ENDIF
|
| 883 |
+
|
| 884 |
+
# End Source File
|
| 885 |
+
|
| 886 |
+
################################################################################
|
| 887 |
+
# Begin Source File
|
| 888 |
+
|
| 889 |
+
SOURCE=.\os_dep.c
|
| 890 |
+
|
| 891 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 892 |
+
|
| 893 |
+
DEP_CPP_OS_DE=\
|
| 894 |
+
".\include\private\gcconfig.h"\
|
| 895 |
+
".\include\gc.h"\
|
| 896 |
+
".\include\private\gc_hdrs.h"\
|
| 897 |
+
".\include\private\gc_priv.h"\
|
| 898 |
+
{$(INCLUDE)}"\sys\STAT.H"\
|
| 899 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 900 |
+
|
| 901 |
+
NODEP_CPP_OS_DE=\
|
| 902 |
+
".\il\PCR_IL.h"\
|
| 903 |
+
".\mm\PCR_MM.h"\
|
| 904 |
+
".\th\PCR_Th.h"\
|
| 905 |
+
".\th\PCR_ThCrSec.h"\
|
| 906 |
+
".\th\PCR_ThCtl.h"\
|
| 907 |
+
".\vd\PCR_VD.h"\
|
| 908 |
+
|
| 909 |
+
|
| 910 |
+
".\Release\os_dep.obj" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
|
| 911 |
+
|
| 912 |
+
".\Release\os_dep.sbr" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
|
| 913 |
+
|
| 914 |
+
|
| 915 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 916 |
+
|
| 917 |
+
DEP_CPP_OS_DE=\
|
| 918 |
+
".\include\private\gcconfig.h"\
|
| 919 |
+
".\include\gc.h"\
|
| 920 |
+
".\include\private\gc_hdrs.h"\
|
| 921 |
+
".\include\private\gc_priv.h"\
|
| 922 |
+
{$(INCLUDE)}"\sys\STAT.H"\
|
| 923 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 924 |
+
|
| 925 |
+
NODEP_CPP_OS_DE=\
|
| 926 |
+
".\il\PCR_IL.h"\
|
| 927 |
+
".\mm\PCR_MM.h"\
|
| 928 |
+
".\th\PCR_Th.h"\
|
| 929 |
+
".\th\PCR_ThCrSec.h"\
|
| 930 |
+
".\th\PCR_ThCtl.h"\
|
| 931 |
+
".\vd\PCR_VD.h"\
|
| 932 |
+
|
| 933 |
+
|
| 934 |
+
".\Debug\os_dep.obj" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
|
| 935 |
+
|
| 936 |
+
".\Debug\os_dep.sbr" : $(SOURCE) $(DEP_CPP_OS_DE) "$(INTDIR)"
|
| 937 |
+
|
| 938 |
+
|
| 939 |
+
!ENDIF
|
| 940 |
+
|
| 941 |
+
# End Source File
|
| 942 |
+
################################################################################
|
| 943 |
+
# Begin Source File
|
| 944 |
+
|
| 945 |
+
SOURCE=.\misc.c
|
| 946 |
+
|
| 947 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 948 |
+
|
| 949 |
+
DEP_CPP_MISC_=\
|
| 950 |
+
".\include\private\gcconfig.h"\
|
| 951 |
+
".\include\gc.h"\
|
| 952 |
+
".\include\private\gc_hdrs.h"\
|
| 953 |
+
".\include\private\gc_priv.h"\
|
| 954 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 955 |
+
|
| 956 |
+
NODEP_CPP_MISC_=\
|
| 957 |
+
".\il\PCR_IL.h"\
|
| 958 |
+
".\th\PCR_Th.h"\
|
| 959 |
+
".\th\PCR_ThCrSec.h"\
|
| 960 |
+
".\th\PCR_ThCtl.h"\
|
| 961 |
+
|
| 962 |
+
|
| 963 |
+
".\Release\misc.obj" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
|
| 964 |
+
|
| 965 |
+
".\Release\misc.sbr" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
|
| 966 |
+
|
| 967 |
+
|
| 968 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 969 |
+
|
| 970 |
+
DEP_CPP_MISC_=\
|
| 971 |
+
".\include\private\gcconfig.h"\
|
| 972 |
+
".\include\gc.h"\
|
| 973 |
+
".\include\private\gc_hdrs.h"\
|
| 974 |
+
".\include\private\gc_priv.h"\
|
| 975 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 976 |
+
|
| 977 |
+
NODEP_CPP_MISC_=\
|
| 978 |
+
".\il\PCR_IL.h"\
|
| 979 |
+
".\th\PCR_Th.h"\
|
| 980 |
+
".\th\PCR_ThCrSec.h"\
|
| 981 |
+
".\th\PCR_ThCtl.h"\
|
| 982 |
+
|
| 983 |
+
|
| 984 |
+
".\Debug\misc.obj" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
|
| 985 |
+
|
| 986 |
+
".\Debug\misc.sbr" : $(SOURCE) $(DEP_CPP_MISC_) "$(INTDIR)"
|
| 987 |
+
|
| 988 |
+
|
| 989 |
+
!ENDIF
|
| 990 |
+
|
| 991 |
+
# End Source File
|
| 992 |
+
################################################################################
|
| 993 |
+
# Begin Source File
|
| 994 |
+
|
| 995 |
+
SOURCE=.\mark_rts.c
|
| 996 |
+
|
| 997 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 998 |
+
|
| 999 |
+
DEP_CPP_MARK_=\
|
| 1000 |
+
".\include\private\gcconfig.h"\
|
| 1001 |
+
".\include\gc.h"\
|
| 1002 |
+
".\include\private\gc_hdrs.h"\
|
| 1003 |
+
".\include\private\gc_priv.h"\
|
| 1004 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1005 |
+
|
| 1006 |
+
NODEP_CPP_MARK_=\
|
| 1007 |
+
".\th\PCR_Th.h"\
|
| 1008 |
+
".\th\PCR_ThCrSec.h"\
|
| 1009 |
+
".\th\PCR_ThCtl.h"\
|
| 1010 |
+
|
| 1011 |
+
|
| 1012 |
+
".\Release\mark_rts.obj" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
|
| 1013 |
+
|
| 1014 |
+
".\Release\mark_rts.sbr" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
|
| 1015 |
+
|
| 1016 |
+
|
| 1017 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1018 |
+
|
| 1019 |
+
DEP_CPP_MARK_=\
|
| 1020 |
+
".\include\private\gcconfig.h"\
|
| 1021 |
+
".\include\gc.h"\
|
| 1022 |
+
".\include\private\gc_hdrs.h"\
|
| 1023 |
+
".\include\private\gc_priv.h"\
|
| 1024 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1025 |
+
|
| 1026 |
+
NODEP_CPP_MARK_=\
|
| 1027 |
+
".\th\PCR_Th.h"\
|
| 1028 |
+
".\th\PCR_ThCrSec.h"\
|
| 1029 |
+
".\th\PCR_ThCtl.h"\
|
| 1030 |
+
|
| 1031 |
+
|
| 1032 |
+
".\Debug\mark_rts.obj" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
|
| 1033 |
+
|
| 1034 |
+
".\Debug\mark_rts.sbr" : $(SOURCE) $(DEP_CPP_MARK_) "$(INTDIR)"
|
| 1035 |
+
|
| 1036 |
+
|
| 1037 |
+
!ENDIF
|
| 1038 |
+
|
| 1039 |
+
# End Source File
|
| 1040 |
+
################################################################################
|
| 1041 |
+
# Begin Source File
|
| 1042 |
+
|
| 1043 |
+
SOURCE=.\mach_dep.c
|
| 1044 |
+
|
| 1045 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1046 |
+
|
| 1047 |
+
DEP_CPP_MACH_=\
|
| 1048 |
+
".\include\private\gcconfig.h"\
|
| 1049 |
+
".\include\gc.h"\
|
| 1050 |
+
".\include\private\gc_hdrs.h"\
|
| 1051 |
+
".\include\private\gc_priv.h"\
|
| 1052 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1053 |
+
|
| 1054 |
+
NODEP_CPP_MACH_=\
|
| 1055 |
+
".\th\PCR_Th.h"\
|
| 1056 |
+
".\th\PCR_ThCrSec.h"\
|
| 1057 |
+
".\th\PCR_ThCtl.h"\
|
| 1058 |
+
|
| 1059 |
+
|
| 1060 |
+
".\Release\mach_dep.obj" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
|
| 1061 |
+
|
| 1062 |
+
".\Release\mach_dep.sbr" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
|
| 1063 |
+
|
| 1064 |
+
|
| 1065 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1066 |
+
|
| 1067 |
+
DEP_CPP_MACH_=\
|
| 1068 |
+
".\include\private\gcconfig.h"\
|
| 1069 |
+
".\include\gc.h"\
|
| 1070 |
+
".\include\private\gc_hdrs.h"\
|
| 1071 |
+
".\include\private\gc_priv.h"\
|
| 1072 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1073 |
+
|
| 1074 |
+
NODEP_CPP_MACH_=\
|
| 1075 |
+
".\th\PCR_Th.h"\
|
| 1076 |
+
".\th\PCR_ThCrSec.h"\
|
| 1077 |
+
".\th\PCR_ThCtl.h"\
|
| 1078 |
+
|
| 1079 |
+
|
| 1080 |
+
".\Debug\mach_dep.obj" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
|
| 1081 |
+
|
| 1082 |
+
".\Debug\mach_dep.sbr" : $(SOURCE) $(DEP_CPP_MACH_) "$(INTDIR)"
|
| 1083 |
+
|
| 1084 |
+
|
| 1085 |
+
!ENDIF
|
| 1086 |
+
|
| 1087 |
+
# End Source File
|
| 1088 |
+
################################################################################
|
| 1089 |
+
# Begin Source File
|
| 1090 |
+
|
| 1091 |
+
SOURCE=.\headers.c
|
| 1092 |
+
|
| 1093 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1094 |
+
|
| 1095 |
+
DEP_CPP_HEADE=\
|
| 1096 |
+
".\include\private\gcconfig.h"\
|
| 1097 |
+
".\include\gc.h"\
|
| 1098 |
+
".\include\private\gc_hdrs.h"\
|
| 1099 |
+
".\include\private\gc_priv.h"\
|
| 1100 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1101 |
+
|
| 1102 |
+
NODEP_CPP_HEADE=\
|
| 1103 |
+
".\th\PCR_Th.h"\
|
| 1104 |
+
".\th\PCR_ThCrSec.h"\
|
| 1105 |
+
".\th\PCR_ThCtl.h"\
|
| 1106 |
+
|
| 1107 |
+
|
| 1108 |
+
".\Release\headers.obj" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
|
| 1109 |
+
|
| 1110 |
+
".\Release\headers.sbr" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
|
| 1111 |
+
|
| 1112 |
+
|
| 1113 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1114 |
+
|
| 1115 |
+
DEP_CPP_HEADE=\
|
| 1116 |
+
".\include\private\gcconfig.h"\
|
| 1117 |
+
".\include\gc.h"\
|
| 1118 |
+
".\include\private\gc_hdrs.h"\
|
| 1119 |
+
".\include\private\gc_priv.h"\
|
| 1120 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1121 |
+
|
| 1122 |
+
NODEP_CPP_HEADE=\
|
| 1123 |
+
".\th\PCR_Th.h"\
|
| 1124 |
+
".\th\PCR_ThCrSec.h"\
|
| 1125 |
+
".\th\PCR_ThCtl.h"\
|
| 1126 |
+
|
| 1127 |
+
|
| 1128 |
+
".\Debug\headers.obj" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
|
| 1129 |
+
|
| 1130 |
+
".\Debug\headers.sbr" : $(SOURCE) $(DEP_CPP_HEADE) "$(INTDIR)"
|
| 1131 |
+
|
| 1132 |
+
|
| 1133 |
+
!ENDIF
|
| 1134 |
+
|
| 1135 |
+
# End Source File
|
| 1136 |
+
################################################################################
|
| 1137 |
+
# Begin Source File
|
| 1138 |
+
|
| 1139 |
+
SOURCE=.\alloc.c
|
| 1140 |
+
|
| 1141 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1142 |
+
|
| 1143 |
+
DEP_CPP_ALLOC=\
|
| 1144 |
+
".\include\private\gcconfig.h"\
|
| 1145 |
+
".\include\gc.h"\
|
| 1146 |
+
".\include\private\gc_hdrs.h"\
|
| 1147 |
+
".\include\private\gc_priv.h"\
|
| 1148 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1149 |
+
|
| 1150 |
+
NODEP_CPP_ALLOC=\
|
| 1151 |
+
".\th\PCR_Th.h"\
|
| 1152 |
+
".\th\PCR_ThCrSec.h"\
|
| 1153 |
+
".\th\PCR_ThCtl.h"\
|
| 1154 |
+
|
| 1155 |
+
|
| 1156 |
+
".\Release\alloc.obj" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
|
| 1157 |
+
|
| 1158 |
+
".\Release\alloc.sbr" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
|
| 1159 |
+
|
| 1160 |
+
|
| 1161 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1162 |
+
|
| 1163 |
+
DEP_CPP_ALLOC=\
|
| 1164 |
+
".\include\private\gcconfig.h"\
|
| 1165 |
+
".\include\gc.h"\
|
| 1166 |
+
".\include\private\gc_hdrs.h"\
|
| 1167 |
+
".\include\private\gc_priv.h"\
|
| 1168 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1169 |
+
|
| 1170 |
+
NODEP_CPP_ALLOC=\
|
| 1171 |
+
".\th\PCR_Th.h"\
|
| 1172 |
+
".\th\PCR_ThCrSec.h"\
|
| 1173 |
+
".\th\PCR_ThCtl.h"\
|
| 1174 |
+
|
| 1175 |
+
|
| 1176 |
+
".\Debug\alloc.obj" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
|
| 1177 |
+
|
| 1178 |
+
".\Debug\alloc.sbr" : $(SOURCE) $(DEP_CPP_ALLOC) "$(INTDIR)"
|
| 1179 |
+
|
| 1180 |
+
|
| 1181 |
+
!ENDIF
|
| 1182 |
+
|
| 1183 |
+
# End Source File
|
| 1184 |
+
################################################################################
|
| 1185 |
+
# Begin Source File
|
| 1186 |
+
|
| 1187 |
+
SOURCE=.\allchblk.c
|
| 1188 |
+
|
| 1189 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1190 |
+
|
| 1191 |
+
DEP_CPP_ALLCH=\
|
| 1192 |
+
".\include\private\gcconfig.h"\
|
| 1193 |
+
".\include\gc.h"\
|
| 1194 |
+
".\include\private\gc_hdrs.h"\
|
| 1195 |
+
".\include\private\gc_priv.h"\
|
| 1196 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1197 |
+
|
| 1198 |
+
NODEP_CPP_ALLCH=\
|
| 1199 |
+
".\th\PCR_Th.h"\
|
| 1200 |
+
".\th\PCR_ThCrSec.h"\
|
| 1201 |
+
".\th\PCR_ThCtl.h"\
|
| 1202 |
+
|
| 1203 |
+
|
| 1204 |
+
".\Release\allchblk.obj" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
|
| 1205 |
+
|
| 1206 |
+
".\Release\allchblk.sbr" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
|
| 1207 |
+
|
| 1208 |
+
|
| 1209 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1210 |
+
|
| 1211 |
+
DEP_CPP_ALLCH=\
|
| 1212 |
+
".\include\private\gcconfig.h"\
|
| 1213 |
+
".\include\gc.h"\
|
| 1214 |
+
".\include\private\gc_hdrs.h"\
|
| 1215 |
+
".\include\private\gc_priv.h"\
|
| 1216 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1217 |
+
|
| 1218 |
+
NODEP_CPP_ALLCH=\
|
| 1219 |
+
".\th\PCR_Th.h"\
|
| 1220 |
+
".\th\PCR_ThCrSec.h"\
|
| 1221 |
+
".\th\PCR_ThCtl.h"\
|
| 1222 |
+
|
| 1223 |
+
|
| 1224 |
+
".\Debug\allchblk.obj" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
|
| 1225 |
+
|
| 1226 |
+
".\Debug\allchblk.sbr" : $(SOURCE) $(DEP_CPP_ALLCH) "$(INTDIR)"
|
| 1227 |
+
|
| 1228 |
+
|
| 1229 |
+
!ENDIF
|
| 1230 |
+
|
| 1231 |
+
# End Source File
|
| 1232 |
+
################################################################################
|
| 1233 |
+
# Begin Source File
|
| 1234 |
+
|
| 1235 |
+
SOURCE=.\stubborn.c
|
| 1236 |
+
|
| 1237 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1238 |
+
|
| 1239 |
+
DEP_CPP_STUBB=\
|
| 1240 |
+
".\include\private\gcconfig.h"\
|
| 1241 |
+
".\include\gc.h"\
|
| 1242 |
+
".\include\private\gc_hdrs.h"\
|
| 1243 |
+
".\include\private\gc_priv.h"\
|
| 1244 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1245 |
+
|
| 1246 |
+
NODEP_CPP_STUBB=\
|
| 1247 |
+
".\th\PCR_Th.h"\
|
| 1248 |
+
".\th\PCR_ThCrSec.h"\
|
| 1249 |
+
".\th\PCR_ThCtl.h"\
|
| 1250 |
+
|
| 1251 |
+
|
| 1252 |
+
".\Release\stubborn.obj" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
|
| 1253 |
+
|
| 1254 |
+
".\Release\stubborn.sbr" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
|
| 1255 |
+
|
| 1256 |
+
|
| 1257 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1258 |
+
|
| 1259 |
+
DEP_CPP_STUBB=\
|
| 1260 |
+
".\include\private\gcconfig.h"\
|
| 1261 |
+
".\include\gc.h"\
|
| 1262 |
+
".\include\private\gc_hdrs.h"\
|
| 1263 |
+
".\include\private\gc_priv.h"\
|
| 1264 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1265 |
+
|
| 1266 |
+
NODEP_CPP_STUBB=\
|
| 1267 |
+
".\th\PCR_Th.h"\
|
| 1268 |
+
".\th\PCR_ThCrSec.h"\
|
| 1269 |
+
".\th\PCR_ThCtl.h"\
|
| 1270 |
+
|
| 1271 |
+
|
| 1272 |
+
".\Debug\stubborn.obj" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
|
| 1273 |
+
|
| 1274 |
+
".\Debug\stubborn.sbr" : $(SOURCE) $(DEP_CPP_STUBB) "$(INTDIR)"
|
| 1275 |
+
|
| 1276 |
+
|
| 1277 |
+
!ENDIF
|
| 1278 |
+
|
| 1279 |
+
# End Source File
|
| 1280 |
+
################################################################################
|
| 1281 |
+
# Begin Source File
|
| 1282 |
+
|
| 1283 |
+
SOURCE=.\obj_map.c
|
| 1284 |
+
|
| 1285 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1286 |
+
|
| 1287 |
+
DEP_CPP_OBJ_M=\
|
| 1288 |
+
".\include\private\gcconfig.h"\
|
| 1289 |
+
".\include\gc.h"\
|
| 1290 |
+
".\include\private\gc_hdrs.h"\
|
| 1291 |
+
".\include\private\gc_priv.h"\
|
| 1292 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1293 |
+
|
| 1294 |
+
NODEP_CPP_OBJ_M=\
|
| 1295 |
+
".\th\PCR_Th.h"\
|
| 1296 |
+
".\th\PCR_ThCrSec.h"\
|
| 1297 |
+
".\th\PCR_ThCtl.h"\
|
| 1298 |
+
|
| 1299 |
+
|
| 1300 |
+
".\Release\obj_map.obj" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
|
| 1301 |
+
|
| 1302 |
+
".\Release\obj_map.sbr" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
|
| 1303 |
+
|
| 1304 |
+
|
| 1305 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1306 |
+
|
| 1307 |
+
DEP_CPP_OBJ_M=\
|
| 1308 |
+
".\include\private\gcconfig.h"\
|
| 1309 |
+
".\include\gc.h"\
|
| 1310 |
+
".\include\private\gc_hdrs.h"\
|
| 1311 |
+
".\include\private\gc_priv.h"\
|
| 1312 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1313 |
+
|
| 1314 |
+
NODEP_CPP_OBJ_M=\
|
| 1315 |
+
".\th\PCR_Th.h"\
|
| 1316 |
+
".\th\PCR_ThCrSec.h"\
|
| 1317 |
+
".\th\PCR_ThCtl.h"\
|
| 1318 |
+
|
| 1319 |
+
|
| 1320 |
+
".\Debug\obj_map.obj" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
|
| 1321 |
+
|
| 1322 |
+
".\Debug\obj_map.sbr" : $(SOURCE) $(DEP_CPP_OBJ_M) "$(INTDIR)"
|
| 1323 |
+
|
| 1324 |
+
|
| 1325 |
+
!ENDIF
|
| 1326 |
+
|
| 1327 |
+
# End Source File
|
| 1328 |
+
################################################################################
|
| 1329 |
+
# Begin Source File
|
| 1330 |
+
|
| 1331 |
+
SOURCE=.\new_hblk.c
|
| 1332 |
+
|
| 1333 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1334 |
+
|
| 1335 |
+
DEP_CPP_NEW_H=\
|
| 1336 |
+
".\include\private\gcconfig.h"\
|
| 1337 |
+
".\include\gc.h"\
|
| 1338 |
+
".\include\private\gc_hdrs.h"\
|
| 1339 |
+
".\include\private\gc_priv.h"\
|
| 1340 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1341 |
+
|
| 1342 |
+
NODEP_CPP_NEW_H=\
|
| 1343 |
+
".\th\PCR_Th.h"\
|
| 1344 |
+
".\th\PCR_ThCrSec.h"\
|
| 1345 |
+
".\th\PCR_ThCtl.h"\
|
| 1346 |
+
|
| 1347 |
+
|
| 1348 |
+
".\Release\new_hblk.obj" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
|
| 1349 |
+
|
| 1350 |
+
".\Release\new_hblk.sbr" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
|
| 1351 |
+
|
| 1352 |
+
|
| 1353 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1354 |
+
|
| 1355 |
+
DEP_CPP_NEW_H=\
|
| 1356 |
+
".\include\private\gcconfig.h"\
|
| 1357 |
+
".\include\gc.h"\
|
| 1358 |
+
".\include\private\gc_hdrs.h"\
|
| 1359 |
+
".\include\private\gc_priv.h"\
|
| 1360 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1361 |
+
|
| 1362 |
+
NODEP_CPP_NEW_H=\
|
| 1363 |
+
".\th\PCR_Th.h"\
|
| 1364 |
+
".\th\PCR_ThCrSec.h"\
|
| 1365 |
+
".\th\PCR_ThCtl.h"\
|
| 1366 |
+
|
| 1367 |
+
|
| 1368 |
+
".\Debug\new_hblk.obj" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
|
| 1369 |
+
|
| 1370 |
+
".\Debug\new_hblk.sbr" : $(SOURCE) $(DEP_CPP_NEW_H) "$(INTDIR)"
|
| 1371 |
+
|
| 1372 |
+
|
| 1373 |
+
!ENDIF
|
| 1374 |
+
|
| 1375 |
+
# End Source File
|
| 1376 |
+
################################################################################
|
| 1377 |
+
# Begin Source File
|
| 1378 |
+
|
| 1379 |
+
SOURCE=.\mark.c
|
| 1380 |
+
|
| 1381 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1382 |
+
|
| 1383 |
+
DEP_CPP_MARK_C=\
|
| 1384 |
+
".\include\private\gcconfig.h"\
|
| 1385 |
+
".\include\gc.h"\
|
| 1386 |
+
".\include\private\gc_hdrs.h"\
|
| 1387 |
+
".\include\private\gc_pmark.h"\
|
| 1388 |
+
".\include\gc_mark.h"\
|
| 1389 |
+
".\include\private\gc_priv.h"\
|
| 1390 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1391 |
+
|
| 1392 |
+
NODEP_CPP_MARK_C=\
|
| 1393 |
+
".\th\PCR_Th.h"\
|
| 1394 |
+
".\th\PCR_ThCrSec.h"\
|
| 1395 |
+
".\th\PCR_ThCtl.h"\
|
| 1396 |
+
|
| 1397 |
+
|
| 1398 |
+
".\Release\mark.obj" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
|
| 1399 |
+
|
| 1400 |
+
".\Release\mark.sbr" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
|
| 1401 |
+
|
| 1402 |
+
|
| 1403 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1404 |
+
|
| 1405 |
+
DEP_CPP_MARK_C=\
|
| 1406 |
+
".\include\private\gcconfig.h"\
|
| 1407 |
+
".\include\gc.h"\
|
| 1408 |
+
".\include\private\gc_hdrs.h"\
|
| 1409 |
+
".\include\private\gc_pmark.h"\
|
| 1410 |
+
".\include\gc_mark.h"\
|
| 1411 |
+
".\include\private\gc_priv.h"\
|
| 1412 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1413 |
+
|
| 1414 |
+
NODEP_CPP_MARK_C=\
|
| 1415 |
+
".\th\PCR_Th.h"\
|
| 1416 |
+
".\th\PCR_ThCrSec.h"\
|
| 1417 |
+
".\th\PCR_ThCtl.h"\
|
| 1418 |
+
|
| 1419 |
+
|
| 1420 |
+
".\Debug\mark.obj" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
|
| 1421 |
+
|
| 1422 |
+
".\Debug\mark.sbr" : $(SOURCE) $(DEP_CPP_MARK_C) "$(INTDIR)"
|
| 1423 |
+
|
| 1424 |
+
|
| 1425 |
+
!ENDIF
|
| 1426 |
+
|
| 1427 |
+
# End Source File
|
| 1428 |
+
################################################################################
|
| 1429 |
+
# Begin Source File
|
| 1430 |
+
|
| 1431 |
+
SOURCE=.\malloc.c
|
| 1432 |
+
|
| 1433 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1434 |
+
|
| 1435 |
+
DEP_CPP_MALLO=\
|
| 1436 |
+
".\include\private\gcconfig.h"\
|
| 1437 |
+
".\include\gc.h"\
|
| 1438 |
+
".\include\private\gc_hdrs.h"\
|
| 1439 |
+
".\include\private\gc_priv.h"\
|
| 1440 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1441 |
+
|
| 1442 |
+
NODEP_CPP_MALLO=\
|
| 1443 |
+
".\th\PCR_Th.h"\
|
| 1444 |
+
".\th\PCR_ThCrSec.h"\
|
| 1445 |
+
".\th\PCR_ThCtl.h"\
|
| 1446 |
+
|
| 1447 |
+
|
| 1448 |
+
".\Release\malloc.obj" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
|
| 1449 |
+
|
| 1450 |
+
".\Release\malloc.sbr" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
|
| 1451 |
+
|
| 1452 |
+
|
| 1453 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1454 |
+
|
| 1455 |
+
DEP_CPP_MALLO=\
|
| 1456 |
+
".\include\private\gcconfig.h"\
|
| 1457 |
+
".\include\gc.h"\
|
| 1458 |
+
".\include\private\gc_hdrs.h"\
|
| 1459 |
+
".\include\private\gc_priv.h"\
|
| 1460 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1461 |
+
|
| 1462 |
+
NODEP_CPP_MALLO=\
|
| 1463 |
+
".\th\PCR_Th.h"\
|
| 1464 |
+
".\th\PCR_ThCrSec.h"\
|
| 1465 |
+
".\th\PCR_ThCtl.h"\
|
| 1466 |
+
|
| 1467 |
+
|
| 1468 |
+
".\Debug\malloc.obj" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
|
| 1469 |
+
|
| 1470 |
+
".\Debug\malloc.sbr" : $(SOURCE) $(DEP_CPP_MALLO) "$(INTDIR)"
|
| 1471 |
+
|
| 1472 |
+
|
| 1473 |
+
!ENDIF
|
| 1474 |
+
|
| 1475 |
+
# End Source File
|
| 1476 |
+
################################################################################
|
| 1477 |
+
# Begin Source File
|
| 1478 |
+
|
| 1479 |
+
SOURCE=.\mallocx.c
|
| 1480 |
+
|
| 1481 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1482 |
+
|
| 1483 |
+
DEP_CPP_MALLX=\
|
| 1484 |
+
".\include\private\gcconfig.h"\
|
| 1485 |
+
".\include\gc.h"\
|
| 1486 |
+
".\include\private\gc_hdrs.h"\
|
| 1487 |
+
".\include\private\gc_priv.h"\
|
| 1488 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1489 |
+
|
| 1490 |
+
NODEP_CPP_MALLX=\
|
| 1491 |
+
".\th\PCR_Th.h"\
|
| 1492 |
+
".\th\PCR_ThCrSec.h"\
|
| 1493 |
+
".\th\PCR_ThCtl.h"\
|
| 1494 |
+
|
| 1495 |
+
|
| 1496 |
+
".\Release\mallocx.obj" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
|
| 1497 |
+
|
| 1498 |
+
".\Release\mallocx.sbr" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
|
| 1499 |
+
|
| 1500 |
+
|
| 1501 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1502 |
+
|
| 1503 |
+
DEP_CPP_MALLX=\
|
| 1504 |
+
".\include\private\gcconfig.h"\
|
| 1505 |
+
".\include\gc.h"\
|
| 1506 |
+
".\include\private\gc_hdrs.h"\
|
| 1507 |
+
".\include\private\gc_priv.h"\
|
| 1508 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1509 |
+
|
| 1510 |
+
NODEP_CPP_MALLX=\
|
| 1511 |
+
".\th\PCR_Th.h"\
|
| 1512 |
+
".\th\PCR_ThCrSec.h"\
|
| 1513 |
+
".\th\PCR_ThCtl.h"\
|
| 1514 |
+
|
| 1515 |
+
|
| 1516 |
+
".\Debug\mallocx.obj" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
|
| 1517 |
+
|
| 1518 |
+
".\Debug\mallocx.sbr" : $(SOURCE) $(DEP_CPP_MALLX) "$(INTDIR)"
|
| 1519 |
+
|
| 1520 |
+
|
| 1521 |
+
!ENDIF
|
| 1522 |
+
|
| 1523 |
+
# End Source File
|
| 1524 |
+
################################################################################
|
| 1525 |
+
# Begin Source File
|
| 1526 |
+
|
| 1527 |
+
SOURCE=.\finalize.c
|
| 1528 |
+
|
| 1529 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1530 |
+
|
| 1531 |
+
DEP_CPP_FINAL=\
|
| 1532 |
+
".\include\private\gcconfig.h"\
|
| 1533 |
+
".\include\gc.h"\
|
| 1534 |
+
".\include\private\gc_hdrs.h"\
|
| 1535 |
+
".\include\private\gc_pmark.h"\
|
| 1536 |
+
".\include\gc_mark.h"\
|
| 1537 |
+
".\include\private\gc_priv.h"\
|
| 1538 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1539 |
+
|
| 1540 |
+
NODEP_CPP_FINAL=\
|
| 1541 |
+
".\th\PCR_Th.h"\
|
| 1542 |
+
".\th\PCR_ThCrSec.h"\
|
| 1543 |
+
".\th\PCR_ThCtl.h"\
|
| 1544 |
+
|
| 1545 |
+
|
| 1546 |
+
".\Release\finalize.obj" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
|
| 1547 |
+
|
| 1548 |
+
".\Release\finalize.sbr" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
|
| 1549 |
+
|
| 1550 |
+
|
| 1551 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1552 |
+
|
| 1553 |
+
DEP_CPP_FINAL=\
|
| 1554 |
+
".\include\private\gcconfig.h"\
|
| 1555 |
+
".\include\gc.h"\
|
| 1556 |
+
".\include\private\gc_hdrs.h"\
|
| 1557 |
+
".\include\private\gc_pmark.h"\
|
| 1558 |
+
".\include\gc_mark.h"\
|
| 1559 |
+
".\include\private\gc_priv.h"\
|
| 1560 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1561 |
+
|
| 1562 |
+
NODEP_CPP_FINAL=\
|
| 1563 |
+
".\th\PCR_Th.h"\
|
| 1564 |
+
".\th\PCR_ThCrSec.h"\
|
| 1565 |
+
".\th\PCR_ThCtl.h"\
|
| 1566 |
+
|
| 1567 |
+
|
| 1568 |
+
".\Debug\finalize.obj" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
|
| 1569 |
+
|
| 1570 |
+
".\Debug\finalize.sbr" : $(SOURCE) $(DEP_CPP_FINAL) "$(INTDIR)"
|
| 1571 |
+
|
| 1572 |
+
|
| 1573 |
+
!ENDIF
|
| 1574 |
+
|
| 1575 |
+
# End Source File
|
| 1576 |
+
################################################################################
|
| 1577 |
+
# Begin Source File
|
| 1578 |
+
|
| 1579 |
+
SOURCE=.\dbg_mlc.c
|
| 1580 |
+
|
| 1581 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1582 |
+
|
| 1583 |
+
DEP_CPP_DBG_M=\
|
| 1584 |
+
".\include\private\gcconfig.h"\
|
| 1585 |
+
".\include\gc.h"\
|
| 1586 |
+
".\include\private\gc_hdrs.h"\
|
| 1587 |
+
".\include\private\gc_priv.h"\
|
| 1588 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1589 |
+
|
| 1590 |
+
NODEP_CPP_DBG_M=\
|
| 1591 |
+
".\th\PCR_Th.h"\
|
| 1592 |
+
".\th\PCR_ThCrSec.h"\
|
| 1593 |
+
".\th\PCR_ThCtl.h"\
|
| 1594 |
+
|
| 1595 |
+
|
| 1596 |
+
".\Release\dbg_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
|
| 1597 |
+
|
| 1598 |
+
".\Release\dbg_mlc.sbr" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
|
| 1599 |
+
|
| 1600 |
+
|
| 1601 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1602 |
+
|
| 1603 |
+
DEP_CPP_DBG_M=\
|
| 1604 |
+
".\include\private\gcconfig.h"\
|
| 1605 |
+
".\include\gc.h"\
|
| 1606 |
+
".\include\private\gc_hdrs.h"\
|
| 1607 |
+
".\include\private\gc_priv.h"\
|
| 1608 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1609 |
+
|
| 1610 |
+
NODEP_CPP_DBG_M=\
|
| 1611 |
+
".\th\PCR_Th.h"\
|
| 1612 |
+
".\th\PCR_ThCrSec.h"\
|
| 1613 |
+
".\th\PCR_ThCtl.h"\
|
| 1614 |
+
|
| 1615 |
+
|
| 1616 |
+
".\Debug\dbg_mlc.obj" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
|
| 1617 |
+
|
| 1618 |
+
".\Debug\dbg_mlc.sbr" : $(SOURCE) $(DEP_CPP_DBG_M) "$(INTDIR)"
|
| 1619 |
+
|
| 1620 |
+
|
| 1621 |
+
!ENDIF
|
| 1622 |
+
|
| 1623 |
+
# End Source File
|
| 1624 |
+
################################################################################
|
| 1625 |
+
# Begin Source File
|
| 1626 |
+
|
| 1627 |
+
SOURCE=.\blacklst.c
|
| 1628 |
+
|
| 1629 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1630 |
+
|
| 1631 |
+
DEP_CPP_BLACK=\
|
| 1632 |
+
".\include\private\gcconfig.h"\
|
| 1633 |
+
".\include\gc.h"\
|
| 1634 |
+
".\include\private\gc_hdrs.h"\
|
| 1635 |
+
".\include\private\gc_priv.h"\
|
| 1636 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1637 |
+
|
| 1638 |
+
NODEP_CPP_BLACK=\
|
| 1639 |
+
".\th\PCR_Th.h"\
|
| 1640 |
+
".\th\PCR_ThCrSec.h"\
|
| 1641 |
+
".\th\PCR_ThCtl.h"\
|
| 1642 |
+
|
| 1643 |
+
|
| 1644 |
+
".\Release\blacklst.obj" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
|
| 1645 |
+
|
| 1646 |
+
".\Release\blacklst.sbr" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
|
| 1647 |
+
|
| 1648 |
+
|
| 1649 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1650 |
+
|
| 1651 |
+
DEP_CPP_BLACK=\
|
| 1652 |
+
".\include\private\gcconfig.h"\
|
| 1653 |
+
".\include\gc.h"\
|
| 1654 |
+
".\include\private\gc_hdrs.h"\
|
| 1655 |
+
".\include\private\gc_priv.h"\
|
| 1656 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1657 |
+
|
| 1658 |
+
NODEP_CPP_BLACK=\
|
| 1659 |
+
".\th\PCR_Th.h"\
|
| 1660 |
+
".\th\PCR_ThCrSec.h"\
|
| 1661 |
+
".\th\PCR_ThCtl.h"\
|
| 1662 |
+
|
| 1663 |
+
|
| 1664 |
+
".\Debug\blacklst.obj" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
|
| 1665 |
+
|
| 1666 |
+
".\Debug\blacklst.sbr" : $(SOURCE) $(DEP_CPP_BLACK) "$(INTDIR)"
|
| 1667 |
+
|
| 1668 |
+
|
| 1669 |
+
!ENDIF
|
| 1670 |
+
|
| 1671 |
+
# End Source File
|
| 1672 |
+
################################################################################
|
| 1673 |
+
# Begin Source File
|
| 1674 |
+
|
| 1675 |
+
SOURCE=.\typd_mlc.c
|
| 1676 |
+
|
| 1677 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1678 |
+
|
| 1679 |
+
DEP_CPP_TYPD_=\
|
| 1680 |
+
".\include\private\gcconfig.h"\
|
| 1681 |
+
".\include\gc.h"\
|
| 1682 |
+
".\include\private\gc_hdrs.h"\
|
| 1683 |
+
".\include\private\gc_pmark.h"\
|
| 1684 |
+
".\include\gc_mark.h"\
|
| 1685 |
+
".\include\private\gc_priv.h"\
|
| 1686 |
+
".\include\gc_typed.h"\
|
| 1687 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1688 |
+
|
| 1689 |
+
NODEP_CPP_TYPD_=\
|
| 1690 |
+
".\th\PCR_Th.h"\
|
| 1691 |
+
".\th\PCR_ThCrSec.h"\
|
| 1692 |
+
".\th\PCR_ThCtl.h"\
|
| 1693 |
+
|
| 1694 |
+
|
| 1695 |
+
".\Release\typd_mlc.obj" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
|
| 1696 |
+
|
| 1697 |
+
".\Release\typd_mlc.sbr" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
|
| 1698 |
+
|
| 1699 |
+
|
| 1700 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1701 |
+
|
| 1702 |
+
DEP_CPP_TYPD_=\
|
| 1703 |
+
".\include\private\gcconfig.h"\
|
| 1704 |
+
".\include\gc.h"\
|
| 1705 |
+
".\include\private\gc_hdrs.h"\
|
| 1706 |
+
".\include\private\gc_pmark.h"\
|
| 1707 |
+
".\include\gc_mark.h"\
|
| 1708 |
+
".\include\private\gc_priv.h"\
|
| 1709 |
+
".\include\gc_typed.h"\
|
| 1710 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1711 |
+
|
| 1712 |
+
NODEP_CPP_TYPD_=\
|
| 1713 |
+
".\th\PCR_Th.h"\
|
| 1714 |
+
".\th\PCR_ThCrSec.h"\
|
| 1715 |
+
".\th\PCR_ThCtl.h"\
|
| 1716 |
+
|
| 1717 |
+
|
| 1718 |
+
".\Debug\typd_mlc.obj" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
|
| 1719 |
+
|
| 1720 |
+
".\Debug\typd_mlc.sbr" : $(SOURCE) $(DEP_CPP_TYPD_) "$(INTDIR)"
|
| 1721 |
+
|
| 1722 |
+
|
| 1723 |
+
!ENDIF
|
| 1724 |
+
|
| 1725 |
+
# End Source File
|
| 1726 |
+
################################################################################
|
| 1727 |
+
# Begin Source File
|
| 1728 |
+
|
| 1729 |
+
SOURCE=.\ptr_chck.c
|
| 1730 |
+
|
| 1731 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1732 |
+
|
| 1733 |
+
DEP_CPP_PTR_C=\
|
| 1734 |
+
".\include\private\gcconfig.h"\
|
| 1735 |
+
".\include\gc.h"\
|
| 1736 |
+
".\include\private\gc_hdrs.h"\
|
| 1737 |
+
".\include\private\gc_pmark.h"\
|
| 1738 |
+
".\include\gc_mark.h"\
|
| 1739 |
+
".\include\private\gc_priv.h"\
|
| 1740 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1741 |
+
|
| 1742 |
+
NODEP_CPP_PTR_C=\
|
| 1743 |
+
".\th\PCR_Th.h"\
|
| 1744 |
+
".\th\PCR_ThCrSec.h"\
|
| 1745 |
+
".\th\PCR_ThCtl.h"\
|
| 1746 |
+
|
| 1747 |
+
|
| 1748 |
+
".\Release\ptr_chck.obj" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
|
| 1749 |
+
|
| 1750 |
+
".\Release\ptr_chck.sbr" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
|
| 1751 |
+
|
| 1752 |
+
|
| 1753 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1754 |
+
|
| 1755 |
+
DEP_CPP_PTR_C=\
|
| 1756 |
+
".\include\private\gcconfig.h"\
|
| 1757 |
+
".\include\gc.h"\
|
| 1758 |
+
".\include\private\gc_hdrs.h"\
|
| 1759 |
+
".\include\private\gc_pmark.h"\
|
| 1760 |
+
".\include\gc_mark.h"\
|
| 1761 |
+
".\include\private\gc_priv.h"\
|
| 1762 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1763 |
+
|
| 1764 |
+
NODEP_CPP_PTR_C=\
|
| 1765 |
+
".\th\PCR_Th.h"\
|
| 1766 |
+
".\th\PCR_ThCrSec.h"\
|
| 1767 |
+
".\th\PCR_ThCtl.h"\
|
| 1768 |
+
|
| 1769 |
+
|
| 1770 |
+
".\Debug\ptr_chck.obj" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
|
| 1771 |
+
|
| 1772 |
+
".\Debug\ptr_chck.sbr" : $(SOURCE) $(DEP_CPP_PTR_C) "$(INTDIR)"
|
| 1773 |
+
|
| 1774 |
+
|
| 1775 |
+
!ENDIF
|
| 1776 |
+
|
| 1777 |
+
# End Source File
|
| 1778 |
+
################################################################################
|
| 1779 |
+
# Begin Source File
|
| 1780 |
+
|
| 1781 |
+
SOURCE=.\dyn_load.c
|
| 1782 |
+
|
| 1783 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1784 |
+
|
| 1785 |
+
DEP_CPP_DYN_L=\
|
| 1786 |
+
".\include\private\gcconfig.h"\
|
| 1787 |
+
".\include\gc.h"\
|
| 1788 |
+
".\include\private\gc_hdrs.h"\
|
| 1789 |
+
".\include\private\gc_priv.h"\
|
| 1790 |
+
{$(INCLUDE)}"\sys\STAT.H"\
|
| 1791 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1792 |
+
|
| 1793 |
+
NODEP_CPP_DYN_L=\
|
| 1794 |
+
".\il\PCR_IL.h"\
|
| 1795 |
+
".\mm\PCR_MM.h"\
|
| 1796 |
+
".\th\PCR_Th.h"\
|
| 1797 |
+
".\th\PCR_ThCrSec.h"\
|
| 1798 |
+
".\th\PCR_ThCtl.h"\
|
| 1799 |
+
|
| 1800 |
+
|
| 1801 |
+
".\Release\dyn_load.obj" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
|
| 1802 |
+
|
| 1803 |
+
".\Release\dyn_load.sbr" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
|
| 1804 |
+
|
| 1805 |
+
|
| 1806 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1807 |
+
|
| 1808 |
+
DEP_CPP_DYN_L=\
|
| 1809 |
+
".\include\private\gcconfig.h"\
|
| 1810 |
+
".\include\gc.h"\
|
| 1811 |
+
".\include\private\gc_hdrs.h"\
|
| 1812 |
+
".\include\private\gc_priv.h"\
|
| 1813 |
+
{$(INCLUDE)}"\sys\STAT.H"\
|
| 1814 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1815 |
+
|
| 1816 |
+
NODEP_CPP_DYN_L=\
|
| 1817 |
+
".\il\PCR_IL.h"\
|
| 1818 |
+
".\mm\PCR_MM.h"\
|
| 1819 |
+
".\th\PCR_Th.h"\
|
| 1820 |
+
".\th\PCR_ThCrSec.h"\
|
| 1821 |
+
".\th\PCR_ThCtl.h"\
|
| 1822 |
+
|
| 1823 |
+
|
| 1824 |
+
".\Debug\dyn_load.obj" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
|
| 1825 |
+
|
| 1826 |
+
".\Debug\dyn_load.sbr" : $(SOURCE) $(DEP_CPP_DYN_L) "$(INTDIR)"
|
| 1827 |
+
|
| 1828 |
+
|
| 1829 |
+
!ENDIF
|
| 1830 |
+
|
| 1831 |
+
# End Source File
|
| 1832 |
+
################################################################################
|
| 1833 |
+
# Begin Source File
|
| 1834 |
+
|
| 1835 |
+
SOURCE=.\win32_threads.c
|
| 1836 |
+
|
| 1837 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1838 |
+
|
| 1839 |
+
DEP_CPP_WIN32=\
|
| 1840 |
+
".\include\private\gcconfig.h"\
|
| 1841 |
+
".\include\gc.h"\
|
| 1842 |
+
".\include\private\gc_hdrs.h"\
|
| 1843 |
+
".\include\private\gc_priv.h"\
|
| 1844 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1845 |
+
|
| 1846 |
+
NODEP_CPP_WIN32=\
|
| 1847 |
+
".\th\PCR_Th.h"\
|
| 1848 |
+
".\th\PCR_ThCrSec.h"\
|
| 1849 |
+
".\th\PCR_ThCtl.h"\
|
| 1850 |
+
|
| 1851 |
+
|
| 1852 |
+
".\Release\win32_threads.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1853 |
+
|
| 1854 |
+
".\Release\win32_threads.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1855 |
+
|
| 1856 |
+
|
| 1857 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1858 |
+
|
| 1859 |
+
DEP_CPP_WIN32=\
|
| 1860 |
+
".\include\private\gcconfig.h"\
|
| 1861 |
+
".\include\gc.h"\
|
| 1862 |
+
".\include\private\gc_hdrs.h"\
|
| 1863 |
+
".\include\private\gc_priv.h"\
|
| 1864 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1865 |
+
|
| 1866 |
+
NODEP_CPP_WIN32=\
|
| 1867 |
+
".\th\PCR_Th.h"\
|
| 1868 |
+
".\th\PCR_ThCrSec.h"\
|
| 1869 |
+
".\th\PCR_ThCtl.h"\
|
| 1870 |
+
|
| 1871 |
+
|
| 1872 |
+
".\Debug\win32_threads.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1873 |
+
|
| 1874 |
+
".\Debug\win32_threads.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1875 |
+
|
| 1876 |
+
|
| 1877 |
+
!ENDIF
|
| 1878 |
+
|
| 1879 |
+
# End Source File
|
| 1880 |
+
################################################################################
|
| 1881 |
+
# Begin Source File
|
| 1882 |
+
|
| 1883 |
+
SOURCE=.\msvc_dbg.c
|
| 1884 |
+
|
| 1885 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1886 |
+
|
| 1887 |
+
DEP_CPP_WIN32=\
|
| 1888 |
+
".\include\private\gcconfig.h"\
|
| 1889 |
+
".\include\gc.h"\
|
| 1890 |
+
".\include\private\gc_hdrs.h"\
|
| 1891 |
+
".\include\private\gc_priv.h"\
|
| 1892 |
+
".\include\private\msvc_dbg.h"\
|
| 1893 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1894 |
+
|
| 1895 |
+
NODEP_CPP_WIN32=\
|
| 1896 |
+
".\th\PCR_Th.h"\
|
| 1897 |
+
".\th\PCR_ThCrSec.h"\
|
| 1898 |
+
".\th\PCR_ThCtl.h"\
|
| 1899 |
+
|
| 1900 |
+
|
| 1901 |
+
".\Release\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1902 |
+
|
| 1903 |
+
".\Release\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1904 |
+
|
| 1905 |
+
|
| 1906 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1907 |
+
|
| 1908 |
+
DEP_CPP_WIN32=\
|
| 1909 |
+
".\include\private\gcconfig.h"\
|
| 1910 |
+
".\include\gc.h"\
|
| 1911 |
+
".\include\private\gc_hdrs.h"\
|
| 1912 |
+
".\include\private\gc_priv.h"\
|
| 1913 |
+
".\include\private\msvc_dbg.h"\
|
| 1914 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1915 |
+
|
| 1916 |
+
NODEP_CPP_WIN32=\
|
| 1917 |
+
".\th\PCR_Th.h"\
|
| 1918 |
+
".\th\PCR_ThCrSec.h"\
|
| 1919 |
+
".\th\PCR_ThCtl.h"\
|
| 1920 |
+
|
| 1921 |
+
|
| 1922 |
+
".\Debug\msvc_dbg.obj" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1923 |
+
|
| 1924 |
+
".\Debug\msvc_dbg.sbr" : $(SOURCE) $(DEP_CPP_WIN32) "$(INTDIR)"
|
| 1925 |
+
|
| 1926 |
+
|
| 1927 |
+
!ENDIF
|
| 1928 |
+
|
| 1929 |
+
# End Source File
|
| 1930 |
+
################################################################################
|
| 1931 |
+
# Begin Source File
|
| 1932 |
+
|
| 1933 |
+
SOURCE=.\checksums.c
|
| 1934 |
+
|
| 1935 |
+
!IF "$(CFG)" == "gc - Win32 Release"
|
| 1936 |
+
|
| 1937 |
+
DEP_CPP_CHECK=\
|
| 1938 |
+
".\include\private\gcconfig.h"\
|
| 1939 |
+
".\include\gc.h"\
|
| 1940 |
+
".\include\private\gc_hdrs.h"\
|
| 1941 |
+
".\include\private\gc_priv.h"\
|
| 1942 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1943 |
+
|
| 1944 |
+
NODEP_CPP_CHECK=\
|
| 1945 |
+
".\th\PCR_Th.h"\
|
| 1946 |
+
".\th\PCR_ThCrSec.h"\
|
| 1947 |
+
".\th\PCR_ThCtl.h"\
|
| 1948 |
+
|
| 1949 |
+
|
| 1950 |
+
".\Release\checksums.obj" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
|
| 1951 |
+
|
| 1952 |
+
".\Release\checksums.sbr" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
|
| 1953 |
+
|
| 1954 |
+
|
| 1955 |
+
!ELSEIF "$(CFG)" == "gc - Win32 Debug"
|
| 1956 |
+
|
| 1957 |
+
DEP_CPP_CHECK=\
|
| 1958 |
+
".\include\private\gcconfig.h"\
|
| 1959 |
+
".\include\gc.h"\
|
| 1960 |
+
".\include\private\gc_hdrs.h"\
|
| 1961 |
+
".\include\private\gc_priv.h"\
|
| 1962 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 1963 |
+
|
| 1964 |
+
NODEP_CPP_CHECK=\
|
| 1965 |
+
".\th\PCR_Th.h"\
|
| 1966 |
+
".\th\PCR_ThCrSec.h"\
|
| 1967 |
+
".\th\PCR_ThCtl.h"\
|
| 1968 |
+
|
| 1969 |
+
|
| 1970 |
+
".\Debug\checksums.obj" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
|
| 1971 |
+
|
| 1972 |
+
".\Debug\checksums.sbr" : $(SOURCE) $(DEP_CPP_CHECK) "$(INTDIR)"
|
| 1973 |
+
|
| 1974 |
+
|
| 1975 |
+
!ENDIF
|
| 1976 |
+
|
| 1977 |
+
# End Source File
|
| 1978 |
+
# End Target
|
| 1979 |
+
################################################################################
|
| 1980 |
+
# Begin Target
|
| 1981 |
+
|
| 1982 |
+
# Name "gctest - Win32 Release"
|
| 1983 |
+
# Name "gctest - Win32 Debug"
|
| 1984 |
+
|
| 1985 |
+
!IF "$(CFG)" == "gctest - Win32 Release"
|
| 1986 |
+
|
| 1987 |
+
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
|
| 1988 |
+
|
| 1989 |
+
!ENDIF
|
| 1990 |
+
|
| 1991 |
+
################################################################################
|
| 1992 |
+
# Begin Project Dependency
|
| 1993 |
+
|
| 1994 |
+
# Project_Dep_Name "gc"
|
| 1995 |
+
|
| 1996 |
+
!IF "$(CFG)" == "gctest - Win32 Release"
|
| 1997 |
+
|
| 1998 |
+
"gc - Win32 Release" :
|
| 1999 |
+
$(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
|
| 2000 |
+
|
| 2001 |
+
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
|
| 2002 |
+
|
| 2003 |
+
"gc - Win32 Debug" :
|
| 2004 |
+
$(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
|
| 2005 |
+
|
| 2006 |
+
!ENDIF
|
| 2007 |
+
|
| 2008 |
+
# End Project Dependency
|
| 2009 |
+
################################################################################
|
| 2010 |
+
# Begin Source File
|
| 2011 |
+
|
| 2012 |
+
SOURCE=.\tests\test.c
|
| 2013 |
+
DEP_CPP_TEST_=\
|
| 2014 |
+
".\include\private\gcconfig.h"\
|
| 2015 |
+
".\include\gc.h"\
|
| 2016 |
+
".\include\private\gc_hdrs.h"\
|
| 2017 |
+
".\include\private\gc_priv.h"\
|
| 2018 |
+
".\include\gc_typed.h"\
|
| 2019 |
+
{$(INCLUDE)}"\sys\TYPES.H"\
|
| 2020 |
+
|
| 2021 |
+
NODEP_CPP_TEST_=\
|
| 2022 |
+
".\th\PCR_Th.h"\
|
| 2023 |
+
".\th\PCR_ThCrSec.h"\
|
| 2024 |
+
".\th\PCR_ThCtl.h"\
|
| 2025 |
+
|
| 2026 |
+
|
| 2027 |
+
!IF "$(CFG)" == "gctest - Win32 Release"
|
| 2028 |
+
|
| 2029 |
+
|
| 2030 |
+
".\gctest\Release\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
| 2031 |
+
|
| 2032 |
+
|
| 2033 |
+
!ELSEIF "$(CFG)" == "gctest - Win32 Debug"
|
| 2034 |
+
|
| 2035 |
+
|
| 2036 |
+
".\gctest\Debug\test.obj" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
| 2037 |
+
|
| 2038 |
+
".\gctest\Debug\test.sbr" : $(SOURCE) $(DEP_CPP_TEST_) "$(INTDIR)"
|
| 2039 |
+
|
| 2040 |
+
|
| 2041 |
+
!ENDIF
|
| 2042 |
+
|
| 2043 |
+
# End Source File
|
| 2044 |
+
# End Target
|
| 2045 |
+
################################################################################
|
| 2046 |
+
# Begin Target
|
| 2047 |
+
|
| 2048 |
+
# Name "cord - Win32 Release"
|
| 2049 |
+
# Name "cord - Win32 Debug"
|
| 2050 |
+
|
| 2051 |
+
!IF "$(CFG)" == "cord - Win32 Release"
|
| 2052 |
+
|
| 2053 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 2054 |
+
|
| 2055 |
+
!ENDIF
|
| 2056 |
+
|
| 2057 |
+
################################################################################
|
| 2058 |
+
# Begin Project Dependency
|
| 2059 |
+
|
| 2060 |
+
# Project_Dep_Name "gc"
|
| 2061 |
+
|
| 2062 |
+
!IF "$(CFG)" == "cord - Win32 Release"
|
| 2063 |
+
|
| 2064 |
+
"gc - Win32 Release" :
|
| 2065 |
+
$(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Release"
|
| 2066 |
+
|
| 2067 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 2068 |
+
|
| 2069 |
+
"gc - Win32 Debug" :
|
| 2070 |
+
$(MAKE) /$(MAKEFLAGS) /F ".\gc.mak" CFG="gc - Win32 Debug"
|
| 2071 |
+
|
| 2072 |
+
!ENDIF
|
| 2073 |
+
|
| 2074 |
+
# End Project Dependency
|
| 2075 |
+
################################################################################
|
| 2076 |
+
# Begin Source File
|
| 2077 |
+
|
| 2078 |
+
SOURCE=.\cord\de_win.c
|
| 2079 |
+
DEP_CPP_DE_WI=\
|
| 2080 |
+
".\include\cord.h"\
|
| 2081 |
+
".\cord\de_cmds.h"\
|
| 2082 |
+
".\cord\de_win.h"\
|
| 2083 |
+
".\include\private\cord_pos.h"\
|
| 2084 |
+
|
| 2085 |
+
NODEP_CPP_DE_WI=\
|
| 2086 |
+
".\include\gc.h"\
|
| 2087 |
+
|
| 2088 |
+
|
| 2089 |
+
!IF "$(CFG)" == "cord - Win32 Release"
|
| 2090 |
+
|
| 2091 |
+
|
| 2092 |
+
".\cord\Release\de_win.obj" : $(SOURCE) $(DEP_CPP_DE_WI) "$(INTDIR)"
|
| 2093 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2094 |
+
|
| 2095 |
+
|
| 2096 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 2097 |
+
|
| 2098 |
+
|
| 2099 |
+
".\cord\Debug\de_win.obj" : $(SOURCE) $(DEP_CPP_DE_WI) "$(INTDIR)"
|
| 2100 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2101 |
+
|
| 2102 |
+
|
| 2103 |
+
!ENDIF
|
| 2104 |
+
|
| 2105 |
+
# End Source File
|
| 2106 |
+
################################################################################
|
| 2107 |
+
# Begin Source File
|
| 2108 |
+
|
| 2109 |
+
SOURCE=.\cord\de.c
|
| 2110 |
+
DEP_CPP_DE_C2e=\
|
| 2111 |
+
".\include\cord.h"\
|
| 2112 |
+
".\cord\de_cmds.h"\
|
| 2113 |
+
".\cord\de_win.h"\
|
| 2114 |
+
".\include\private\cord_pos.h"\
|
| 2115 |
+
|
| 2116 |
+
NODEP_CPP_DE_C2e=\
|
| 2117 |
+
".\include\gc.h"\
|
| 2118 |
+
|
| 2119 |
+
|
| 2120 |
+
!IF "$(CFG)" == "cord - Win32 Release"
|
| 2121 |
+
|
| 2122 |
+
|
| 2123 |
+
".\cord\Release\de.obj" : $(SOURCE) $(DEP_CPP_DE_C2e) "$(INTDIR)"
|
| 2124 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2125 |
+
|
| 2126 |
+
|
| 2127 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 2128 |
+
|
| 2129 |
+
|
| 2130 |
+
".\cord\Debug\de.obj" : $(SOURCE) $(DEP_CPP_DE_C2e) "$(INTDIR)"
|
| 2131 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2132 |
+
|
| 2133 |
+
|
| 2134 |
+
!ENDIF
|
| 2135 |
+
|
| 2136 |
+
# End Source File
|
| 2137 |
+
################################################################################
|
| 2138 |
+
# Begin Source File
|
| 2139 |
+
|
| 2140 |
+
SOURCE=.\cord\cordxtra.c
|
| 2141 |
+
DEP_CPP_CORDX=\
|
| 2142 |
+
".\include\cord.h"\
|
| 2143 |
+
".\include\ec.h"\
|
| 2144 |
+
".\include\private\cord_pos.h"\
|
| 2145 |
+
|
| 2146 |
+
NODEP_CPP_CORDX=\
|
| 2147 |
+
".\include\gc.h"\
|
| 2148 |
+
|
| 2149 |
+
|
| 2150 |
+
!IF "$(CFG)" == "cord - Win32 Release"
|
| 2151 |
+
|
| 2152 |
+
|
| 2153 |
+
".\cord\Release\cordxtra.obj" : $(SOURCE) $(DEP_CPP_CORDX) "$(INTDIR)"
|
| 2154 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2155 |
+
|
| 2156 |
+
|
| 2157 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 2158 |
+
|
| 2159 |
+
|
| 2160 |
+
".\cord\Debug\cordxtra.obj" : $(SOURCE) $(DEP_CPP_CORDX) "$(INTDIR)"
|
| 2161 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2162 |
+
|
| 2163 |
+
|
| 2164 |
+
!ENDIF
|
| 2165 |
+
|
| 2166 |
+
# End Source File
|
| 2167 |
+
################################################################################
|
| 2168 |
+
# Begin Source File
|
| 2169 |
+
|
| 2170 |
+
SOURCE=.\cord\cordbscs.c
|
| 2171 |
+
DEP_CPP_CORDB=\
|
| 2172 |
+
".\include\cord.h"\
|
| 2173 |
+
".\include\private\cord_pos.h"\
|
| 2174 |
+
|
| 2175 |
+
NODEP_CPP_CORDB=\
|
| 2176 |
+
".\include\gc.h"\
|
| 2177 |
+
|
| 2178 |
+
|
| 2179 |
+
!IF "$(CFG)" == "cord - Win32 Release"
|
| 2180 |
+
|
| 2181 |
+
|
| 2182 |
+
".\cord\Release\cordbscs.obj" : $(SOURCE) $(DEP_CPP_CORDB) "$(INTDIR)"
|
| 2183 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2184 |
+
|
| 2185 |
+
|
| 2186 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 2187 |
+
|
| 2188 |
+
|
| 2189 |
+
".\cord\Debug\cordbscs.obj" : $(SOURCE) $(DEP_CPP_CORDB) "$(INTDIR)"
|
| 2190 |
+
$(CPP) $(CPP_PROJ) $(SOURCE)
|
| 2191 |
+
|
| 2192 |
+
|
| 2193 |
+
!ENDIF
|
| 2194 |
+
|
| 2195 |
+
# End Source File
|
| 2196 |
+
################################################################################
|
| 2197 |
+
# Begin Source File
|
| 2198 |
+
|
| 2199 |
+
SOURCE=.\cord\de_win.RC
|
| 2200 |
+
|
| 2201 |
+
!IF "$(CFG)" == "cord - Win32 Release"
|
| 2202 |
+
|
| 2203 |
+
|
| 2204 |
+
".\cord\Release\de_win.res" : $(SOURCE) "$(INTDIR)"
|
| 2205 |
+
$(RSC) /l 0x809 /fo"$(INTDIR)/de_win.res" /i "cord" /d "NDEBUG" $(SOURCE)
|
| 2206 |
+
|
| 2207 |
+
|
| 2208 |
+
!ELSEIF "$(CFG)" == "cord - Win32 Debug"
|
| 2209 |
+
|
| 2210 |
+
|
| 2211 |
+
".\cord\Debug\de_win.res" : $(SOURCE) "$(INTDIR)"
|
| 2212 |
+
$(RSC) /l 0x809 /fo"$(INTDIR)/de_win.res" /i "cord" /d "_DEBUG" $(SOURCE)
|
| 2213 |
+
|
| 2214 |
+
|
| 2215 |
+
!ENDIF
|
| 2216 |
+
|
| 2217 |
+
# End Source File
|
| 2218 |
+
# End Target
|
| 2219 |
+
# End Project
|
| 2220 |
+
################################################################################
|
mosesdecoder/jam-files/engine/boehm_gc/gc_cpp.cpp
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
|
|
|
| 1 |
+
// Visual C++ seems to prefer a .cpp extension to .cc
|
| 2 |
+
#include "gc_cpp.cc"
|
mosesdecoder/jam-files/engine/boehm_gc/hpux_test_and_clear.s
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.SPACE $PRIVATE$
|
| 2 |
+
.SUBSPA $DATA$,QUAD=1,ALIGN=8,ACCESS=31
|
| 3 |
+
.SUBSPA $BSS$,QUAD=1,ALIGN=8,ACCESS=31,ZERO,SORT=82
|
| 4 |
+
.SPACE $TEXT$
|
| 5 |
+
.SUBSPA $LIT$,QUAD=0,ALIGN=8,ACCESS=44
|
| 6 |
+
.SUBSPA $CODE$,QUAD=0,ALIGN=8,ACCESS=44,CODE_ONLY
|
| 7 |
+
.IMPORT $global$,DATA
|
| 8 |
+
.IMPORT $$dyncall,MILLICODE
|
| 9 |
+
.SPACE $TEXT$
|
| 10 |
+
.SUBSPA $CODE$
|
| 11 |
+
|
| 12 |
+
.align 4
|
| 13 |
+
.EXPORT GC_test_and_clear,ENTRY,PRIV_LEV=3,ARGW0=GR,RTNVAL=GR
|
| 14 |
+
GC_test_and_clear
|
| 15 |
+
.PROC
|
| 16 |
+
.CALLINFO FRAME=0,NO_CALLS
|
| 17 |
+
.ENTRY
|
| 18 |
+
ldcw,co (%r26),%r28
|
| 19 |
+
bv,n 0(%r2)
|
| 20 |
+
.EXIT
|
| 21 |
+
.PROCEND
|
mosesdecoder/jam-files/engine/boehm_gc/mips_ultrix_mach_dep.s
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# define call_push(x) move $4,x; jal GC_push_one
|
| 2 |
+
|
| 3 |
+
.text
|
| 4 |
+
# Mark from machine registers that are saved by C compiler
|
| 5 |
+
.globl GC_push_regs
|
| 6 |
+
.ent GC_push_regs
|
| 7 |
+
GC_push_regs:
|
| 8 |
+
subu $sp,8 ## Need to save only return address
|
| 9 |
+
sw $31,4($sp)
|
| 10 |
+
.mask 0x80000000,-4
|
| 11 |
+
.frame $sp,8,$31
|
| 12 |
+
call_push($2)
|
| 13 |
+
call_push($3)
|
| 14 |
+
call_push($16)
|
| 15 |
+
call_push($17)
|
| 16 |
+
call_push($18)
|
| 17 |
+
call_push($19)
|
| 18 |
+
call_push($20)
|
| 19 |
+
call_push($21)
|
| 20 |
+
call_push($22)
|
| 21 |
+
call_push($23)
|
| 22 |
+
call_push($30)
|
| 23 |
+
lw $31,4($sp)
|
| 24 |
+
addu $sp,8
|
| 25 |
+
j $31
|
| 26 |
+
.end GC_push_regs
|
mosesdecoder/jam-files/engine/boehm_gc/misc.c
ADDED
|
@@ -0,0 +1,1177 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
| 3 |
+
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
| 4 |
+
* Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
|
| 5 |
+
*
|
| 6 |
+
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 7 |
+
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 8 |
+
*
|
| 9 |
+
* Permission is hereby granted to use or copy this program
|
| 10 |
+
* for any purpose, provided the above notices are retained on all copies.
|
| 11 |
+
* Permission to modify the code and to distribute modified code is granted,
|
| 12 |
+
* provided the above notices are retained, and a notice that the code was
|
| 13 |
+
* modified is included with the above copyright notice.
|
| 14 |
+
*/
|
| 15 |
+
/* Boehm, July 31, 1995 5:02 pm PDT */
|
| 16 |
+
|
| 17 |
+
|
| 18 |
+
#include <stdio.h>
|
| 19 |
+
#include <limits.h>
|
| 20 |
+
#include <stdarg.h>
|
| 21 |
+
#ifndef _WIN32_WCE
|
| 22 |
+
#include <signal.h>
|
| 23 |
+
#endif
|
| 24 |
+
|
| 25 |
+
#define I_HIDE_POINTERS /* To make GC_call_with_alloc_lock visible */
|
| 26 |
+
#include "private/gc_pmark.h"
|
| 27 |
+
|
| 28 |
+
#ifdef GC_SOLARIS_THREADS
|
| 29 |
+
# include <sys/syscall.h>
|
| 30 |
+
#endif
|
| 31 |
+
#if defined(MSWIN32) || defined(MSWINCE)
|
| 32 |
+
# define WIN32_LEAN_AND_MEAN
|
| 33 |
+
# define NOSERVICE
|
| 34 |
+
# include <windows.h>
|
| 35 |
+
# include <tchar.h>
|
| 36 |
+
#endif
|
| 37 |
+
|
| 38 |
+
#ifdef UNIX_LIKE
|
| 39 |
+
# include <fcntl.h>
|
| 40 |
+
# include <sys/types.h>
|
| 41 |
+
# include <sys/stat.h>
|
| 42 |
+
|
| 43 |
+
int GC_log; /* Forward decl, so we can set it. */
|
| 44 |
+
#endif
|
| 45 |
+
|
| 46 |
+
#ifdef NONSTOP
|
| 47 |
+
# include <floss.h>
|
| 48 |
+
#endif
|
| 49 |
+
|
| 50 |
+
#if defined(THREADS) && defined(PCR)
|
| 51 |
+
# include "il/PCR_IL.h"
|
| 52 |
+
PCR_Th_ML GC_allocate_ml;
|
| 53 |
+
#endif
|
| 54 |
+
/* For other platforms with threads, the lock and possibly */
|
| 55 |
+
/* GC_lock_holder variables are defined in the thread support code. */
|
| 56 |
+
|
| 57 |
+
#if defined(NOSYS) || defined(ECOS)
|
| 58 |
+
#undef STACKBASE
|
| 59 |
+
#endif
|
| 60 |
+
|
| 61 |
+
/* Dont unnecessarily call GC_register_main_static_data() in case */
|
| 62 |
+
/* dyn_load.c isn't linked in. */
|
| 63 |
+
#ifdef DYNAMIC_LOADING
|
| 64 |
+
# define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
|
| 65 |
+
#else
|
| 66 |
+
# define GC_REGISTER_MAIN_STATIC_DATA() TRUE
|
| 67 |
+
#endif
|
| 68 |
+
|
| 69 |
+
GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
|
| 70 |
+
|
| 71 |
+
|
| 72 |
+
GC_bool GC_debugging_started = FALSE;
|
| 73 |
+
/* defined here so we don't have to load debug_malloc.o */
|
| 74 |
+
|
| 75 |
+
void (*GC_check_heap) (void) = (void (*) (void))0;
|
| 76 |
+
void (*GC_print_all_smashed) (void) = (void (*) (void))0;
|
| 77 |
+
|
| 78 |
+
void (*GC_start_call_back) (void) = (void (*) (void))0;
|
| 79 |
+
|
| 80 |
+
ptr_t GC_stackbottom = 0;
|
| 81 |
+
|
| 82 |
+
#ifdef IA64
|
| 83 |
+
ptr_t GC_register_stackbottom = 0;
|
| 84 |
+
#endif
|
| 85 |
+
|
| 86 |
+
GC_bool GC_dont_gc = 0;
|
| 87 |
+
|
| 88 |
+
GC_bool GC_dont_precollect = 0;
|
| 89 |
+
|
| 90 |
+
GC_bool GC_quiet = 0;
|
| 91 |
+
|
| 92 |
+
#ifndef SMALL_CONFIG
|
| 93 |
+
GC_bool GC_print_stats = 0;
|
| 94 |
+
#endif
|
| 95 |
+
|
| 96 |
+
GC_bool GC_print_back_height = 0;
|
| 97 |
+
|
| 98 |
+
#ifndef NO_DEBUGGING
|
| 99 |
+
GC_bool GC_dump_regularly = 0; /* Generate regular debugging dumps. */
|
| 100 |
+
#endif
|
| 101 |
+
|
| 102 |
+
#ifdef KEEP_BACK_PTRS
|
| 103 |
+
long GC_backtraces = 0; /* Number of random backtraces to */
|
| 104 |
+
/* generate for each GC. */
|
| 105 |
+
#endif
|
| 106 |
+
|
| 107 |
+
#ifdef FIND_LEAK
|
| 108 |
+
int GC_find_leak = 1;
|
| 109 |
+
#else
|
| 110 |
+
int GC_find_leak = 0;
|
| 111 |
+
#endif
|
| 112 |
+
|
| 113 |
+
#ifdef ALL_INTERIOR_POINTERS
|
| 114 |
+
int GC_all_interior_pointers = 1;
|
| 115 |
+
#else
|
| 116 |
+
int GC_all_interior_pointers = 0;
|
| 117 |
+
#endif
|
| 118 |
+
|
| 119 |
+
long GC_large_alloc_warn_interval = 5;
|
| 120 |
+
/* Interval between unsuppressed warnings. */
|
| 121 |
+
|
| 122 |
+
long GC_large_alloc_warn_suppressed = 0;
|
| 123 |
+
/* Number of warnings suppressed so far. */
|
| 124 |
+
|
| 125 |
+
/*ARGSUSED*/
|
| 126 |
+
void * GC_default_oom_fn(size_t bytes_requested)
|
| 127 |
+
{
|
| 128 |
+
return(0);
|
| 129 |
+
}
|
| 130 |
+
|
| 131 |
+
void * (*GC_oom_fn) (size_t bytes_requested) = GC_default_oom_fn;
|
| 132 |
+
|
| 133 |
+
void * GC_project2(void *arg1, void *arg2)
|
| 134 |
+
{
|
| 135 |
+
return arg2;
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
/* Set things up so that GC_size_map[i] >= granules(i), */
|
| 139 |
+
/* but not too much bigger */
|
| 140 |
+
/* and so that size_map contains relatively few distinct entries */
|
| 141 |
+
/* This was originally stolen from Russ Atkinson's Cedar */
|
| 142 |
+
/* quantization alogrithm (but we precompute it). */
|
| 143 |
+
void GC_init_size_map(void)
|
| 144 |
+
{
|
| 145 |
+
int i;
|
| 146 |
+
|
| 147 |
+
/* Map size 0 to something bigger. */
|
| 148 |
+
/* This avoids problems at lower levels. */
|
| 149 |
+
GC_size_map[0] = 1;
|
| 150 |
+
for (i = 1; i <= GRANULES_TO_BYTES(TINY_FREELISTS-1) - EXTRA_BYTES; i++) {
|
| 151 |
+
GC_size_map[i] = ROUNDED_UP_GRANULES(i);
|
| 152 |
+
GC_ASSERT(GC_size_map[i] < TINY_FREELISTS);
|
| 153 |
+
}
|
| 154 |
+
/* We leave the rest of the array to be filled in on demand. */
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
/* Fill in additional entries in GC_size_map, including the ith one */
|
| 158 |
+
/* We assume the ith entry is currently 0. */
|
| 159 |
+
/* Note that a filled in section of the array ending at n always */
|
| 160 |
+
/* has length at least n/4. */
|
| 161 |
+
void GC_extend_size_map(size_t i)
|
| 162 |
+
{
|
| 163 |
+
size_t orig_granule_sz = ROUNDED_UP_GRANULES(i);
|
| 164 |
+
size_t granule_sz = orig_granule_sz;
|
| 165 |
+
size_t byte_sz = GRANULES_TO_BYTES(granule_sz);
|
| 166 |
+
/* The size we try to preserve. */
|
| 167 |
+
/* Close to i, unless this would */
|
| 168 |
+
/* introduce too many distinct sizes. */
|
| 169 |
+
size_t smaller_than_i = byte_sz - (byte_sz >> 3);
|
| 170 |
+
size_t much_smaller_than_i = byte_sz - (byte_sz >> 2);
|
| 171 |
+
size_t low_limit; /* The lowest indexed entry we */
|
| 172 |
+
/* initialize. */
|
| 173 |
+
size_t j;
|
| 174 |
+
|
| 175 |
+
if (GC_size_map[smaller_than_i] == 0) {
|
| 176 |
+
low_limit = much_smaller_than_i;
|
| 177 |
+
while (GC_size_map[low_limit] != 0) low_limit++;
|
| 178 |
+
} else {
|
| 179 |
+
low_limit = smaller_than_i + 1;
|
| 180 |
+
while (GC_size_map[low_limit] != 0) low_limit++;
|
| 181 |
+
granule_sz = ROUNDED_UP_GRANULES(low_limit);
|
| 182 |
+
granule_sz += granule_sz >> 3;
|
| 183 |
+
if (granule_sz < orig_granule_sz) granule_sz = orig_granule_sz;
|
| 184 |
+
}
|
| 185 |
+
/* For these larger sizes, we use an even number of granules. */
|
| 186 |
+
/* This makes it easier to, for example, construct a 16byte-aligned */
|
| 187 |
+
/* allocator even if GRANULE_BYTES is 8. */
|
| 188 |
+
granule_sz += 1;
|
| 189 |
+
granule_sz &= ~1;
|
| 190 |
+
if (granule_sz > MAXOBJGRANULES) {
|
| 191 |
+
granule_sz = MAXOBJGRANULES;
|
| 192 |
+
}
|
| 193 |
+
/* If we can fit the same number of larger objects in a block, */
|
| 194 |
+
/* do so. */
|
| 195 |
+
{
|
| 196 |
+
size_t number_of_objs = HBLK_GRANULES/granule_sz;
|
| 197 |
+
granule_sz = HBLK_GRANULES/number_of_objs;
|
| 198 |
+
granule_sz &= ~1;
|
| 199 |
+
}
|
| 200 |
+
byte_sz = GRANULES_TO_BYTES(granule_sz);
|
| 201 |
+
/* We may need one extra byte; */
|
| 202 |
+
/* don't always fill in GC_size_map[byte_sz] */
|
| 203 |
+
byte_sz -= EXTRA_BYTES;
|
| 204 |
+
|
| 205 |
+
for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = granule_sz;
|
| 206 |
+
}
|
| 207 |
+
|
| 208 |
+
|
| 209 |
+
/*
|
| 210 |
+
* The following is a gross hack to deal with a problem that can occur
|
| 211 |
+
* on machines that are sloppy about stack frame sizes, notably SPARC.
|
| 212 |
+
* Bogus pointers may be written to the stack and not cleared for
|
| 213 |
+
* a LONG time, because they always fall into holes in stack frames
|
| 214 |
+
* that are not written. We partially address this by clearing
|
| 215 |
+
* sections of the stack whenever we get control.
|
| 216 |
+
*/
|
| 217 |
+
word GC_stack_last_cleared = 0; /* GC_no when we last did this */
|
| 218 |
+
# ifdef THREADS
|
| 219 |
+
# define BIG_CLEAR_SIZE 2048 /* Clear this much now and then. */
|
| 220 |
+
# define SMALL_CLEAR_SIZE 256 /* Clear this much every time. */
|
| 221 |
+
# endif
|
| 222 |
+
# define CLEAR_SIZE 213 /* Granularity for GC_clear_stack_inner */
|
| 223 |
+
# define DEGRADE_RATE 50
|
| 224 |
+
|
| 225 |
+
ptr_t GC_min_sp; /* Coolest stack pointer value from which we've */
|
| 226 |
+
/* already cleared the stack. */
|
| 227 |
+
|
| 228 |
+
ptr_t GC_high_water;
|
| 229 |
+
/* "hottest" stack pointer value we have seen */
|
| 230 |
+
/* recently. Degrades over time. */
|
| 231 |
+
|
| 232 |
+
word GC_bytes_allocd_at_reset;
|
| 233 |
+
|
| 234 |
+
#if defined(ASM_CLEAR_CODE)
|
| 235 |
+
extern void *GC_clear_stack_inner(void *, ptr_t);
|
| 236 |
+
#else
|
| 237 |
+
/* Clear the stack up to about limit. Return arg. */
|
| 238 |
+
/*ARGSUSED*/
|
| 239 |
+
void * GC_clear_stack_inner(void *arg, ptr_t limit)
|
| 240 |
+
{
|
| 241 |
+
word dummy[CLEAR_SIZE];
|
| 242 |
+
|
| 243 |
+
BZERO(dummy, CLEAR_SIZE*sizeof(word));
|
| 244 |
+
if ((ptr_t)(dummy) COOLER_THAN limit) {
|
| 245 |
+
(void) GC_clear_stack_inner(arg, limit);
|
| 246 |
+
}
|
| 247 |
+
/* Make sure the recursive call is not a tail call, and the bzero */
|
| 248 |
+
/* call is not recognized as dead code. */
|
| 249 |
+
GC_noop1((word)dummy);
|
| 250 |
+
return(arg);
|
| 251 |
+
}
|
| 252 |
+
#endif
|
| 253 |
+
|
| 254 |
+
/* Clear some of the inaccessible part of the stack. Returns its */
|
| 255 |
+
/* argument, so it can be used in a tail call position, hence clearing */
|
| 256 |
+
/* another frame. */
|
| 257 |
+
void * GC_clear_stack(void *arg)
|
| 258 |
+
{
|
| 259 |
+
ptr_t sp = GC_approx_sp(); /* Hotter than actual sp */
|
| 260 |
+
# ifdef THREADS
|
| 261 |
+
word dummy[SMALL_CLEAR_SIZE];
|
| 262 |
+
static unsigned random_no = 0;
|
| 263 |
+
/* Should be more random than it is ... */
|
| 264 |
+
/* Used to occasionally clear a bigger */
|
| 265 |
+
/* chunk. */
|
| 266 |
+
# endif
|
| 267 |
+
ptr_t limit;
|
| 268 |
+
|
| 269 |
+
# define SLOP 400
|
| 270 |
+
/* Extra bytes we clear every time. This clears our own */
|
| 271 |
+
/* activation record, and should cause more frequent */
|
| 272 |
+
/* clearing near the cold end of the stack, a good thing. */
|
| 273 |
+
# define GC_SLOP 4000
|
| 274 |
+
/* We make GC_high_water this much hotter than we really saw */
|
| 275 |
+
/* saw it, to cover for GC noise etc. above our current frame. */
|
| 276 |
+
# define CLEAR_THRESHOLD 100000
|
| 277 |
+
/* We restart the clearing process after this many bytes of */
|
| 278 |
+
/* allocation. Otherwise very heavily recursive programs */
|
| 279 |
+
/* with sparse stacks may result in heaps that grow almost */
|
| 280 |
+
/* without bounds. As the heap gets larger, collection */
|
| 281 |
+
/* frequency decreases, thus clearing frequency would decrease, */
|
| 282 |
+
/* thus more junk remains accessible, thus the heap gets */
|
| 283 |
+
/* larger ... */
|
| 284 |
+
# ifdef THREADS
|
| 285 |
+
if (++random_no % 13 == 0) {
|
| 286 |
+
limit = sp;
|
| 287 |
+
MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
|
| 288 |
+
limit = (ptr_t)((word)limit & ~0xf);
|
| 289 |
+
/* Make it sufficiently aligned for assembly */
|
| 290 |
+
/* implementations of GC_clear_stack_inner. */
|
| 291 |
+
return GC_clear_stack_inner(arg, limit);
|
| 292 |
+
} else {
|
| 293 |
+
BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word));
|
| 294 |
+
return arg;
|
| 295 |
+
}
|
| 296 |
+
# else
|
| 297 |
+
if (GC_gc_no > GC_stack_last_cleared) {
|
| 298 |
+
/* Start things over, so we clear the entire stack again */
|
| 299 |
+
if (GC_stack_last_cleared == 0) GC_high_water = (ptr_t)GC_stackbottom;
|
| 300 |
+
GC_min_sp = GC_high_water;
|
| 301 |
+
GC_stack_last_cleared = GC_gc_no;
|
| 302 |
+
GC_bytes_allocd_at_reset = GC_bytes_allocd;
|
| 303 |
+
}
|
| 304 |
+
/* Adjust GC_high_water */
|
| 305 |
+
MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
|
| 306 |
+
if (sp HOTTER_THAN GC_high_water) {
|
| 307 |
+
GC_high_water = sp;
|
| 308 |
+
}
|
| 309 |
+
MAKE_HOTTER(GC_high_water, GC_SLOP);
|
| 310 |
+
limit = GC_min_sp;
|
| 311 |
+
MAKE_HOTTER(limit, SLOP);
|
| 312 |
+
if (sp COOLER_THAN limit) {
|
| 313 |
+
limit = (ptr_t)((word)limit & ~0xf);
|
| 314 |
+
/* Make it sufficiently aligned for assembly */
|
| 315 |
+
/* implementations of GC_clear_stack_inner. */
|
| 316 |
+
GC_min_sp = sp;
|
| 317 |
+
return(GC_clear_stack_inner(arg, limit));
|
| 318 |
+
} else if (GC_bytes_allocd - GC_bytes_allocd_at_reset > CLEAR_THRESHOLD) {
|
| 319 |
+
/* Restart clearing process, but limit how much clearing we do. */
|
| 320 |
+
GC_min_sp = sp;
|
| 321 |
+
MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
|
| 322 |
+
if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water;
|
| 323 |
+
GC_bytes_allocd_at_reset = GC_bytes_allocd;
|
| 324 |
+
}
|
| 325 |
+
return(arg);
|
| 326 |
+
# endif
|
| 327 |
+
}
|
| 328 |
+
|
| 329 |
+
|
| 330 |
+
/* Return a pointer to the base address of p, given a pointer to a */
|
| 331 |
+
/* an address within an object. Return 0 o.w. */
|
| 332 |
+
void * GC_base(void * p)
|
| 333 |
+
{
|
| 334 |
+
ptr_t r;
|
| 335 |
+
struct hblk *h;
|
| 336 |
+
bottom_index *bi;
|
| 337 |
+
hdr *candidate_hdr;
|
| 338 |
+
ptr_t limit;
|
| 339 |
+
|
| 340 |
+
r = p;
|
| 341 |
+
if (!GC_is_initialized) return 0;
|
| 342 |
+
h = HBLKPTR(r);
|
| 343 |
+
GET_BI(r, bi);
|
| 344 |
+
candidate_hdr = HDR_FROM_BI(bi, r);
|
| 345 |
+
if (candidate_hdr == 0) return(0);
|
| 346 |
+
/* If it's a pointer to the middle of a large object, move it */
|
| 347 |
+
/* to the beginning. */
|
| 348 |
+
while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
|
| 349 |
+
h = FORWARDED_ADDR(h,candidate_hdr);
|
| 350 |
+
r = (ptr_t)h;
|
| 351 |
+
candidate_hdr = HDR(h);
|
| 352 |
+
}
|
| 353 |
+
if (HBLK_IS_FREE(candidate_hdr)) return(0);
|
| 354 |
+
/* Make sure r points to the beginning of the object */
|
| 355 |
+
r = (ptr_t)((word)r & ~(WORDS_TO_BYTES(1) - 1));
|
| 356 |
+
{
|
| 357 |
+
size_t offset = HBLKDISPL(r);
|
| 358 |
+
signed_word sz = candidate_hdr -> hb_sz;
|
| 359 |
+
size_t obj_displ = offset % sz;
|
| 360 |
+
|
| 361 |
+
r -= obj_displ;
|
| 362 |
+
limit = r + sz;
|
| 363 |
+
if (limit > (ptr_t)(h + 1) && sz <= HBLKSIZE) {
|
| 364 |
+
return(0);
|
| 365 |
+
}
|
| 366 |
+
if ((ptr_t)p >= limit) return(0);
|
| 367 |
+
}
|
| 368 |
+
return((void *)r);
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
|
| 372 |
+
/* Return the size of an object, given a pointer to its base. */
|
| 373 |
+
/* (For small obects this also happens to work from interior pointers, */
|
| 374 |
+
/* but that shouldn't be relied upon.) */
|
| 375 |
+
size_t GC_size(void * p)
|
| 376 |
+
{
|
| 377 |
+
hdr * hhdr = HDR(p);
|
| 378 |
+
|
| 379 |
+
return hhdr -> hb_sz;
|
| 380 |
+
}
|
| 381 |
+
|
| 382 |
+
size_t GC_get_heap_size(void)
|
| 383 |
+
{
|
| 384 |
+
return GC_heapsize;
|
| 385 |
+
}
|
| 386 |
+
|
| 387 |
+
size_t GC_get_free_bytes(void)
|
| 388 |
+
{
|
| 389 |
+
return GC_large_free_bytes;
|
| 390 |
+
}
|
| 391 |
+
|
| 392 |
+
size_t GC_get_bytes_since_gc(void)
|
| 393 |
+
{
|
| 394 |
+
return GC_bytes_allocd;
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
size_t GC_get_total_bytes(void)
|
| 398 |
+
{
|
| 399 |
+
return GC_bytes_allocd+GC_bytes_allocd_before_gc;
|
| 400 |
+
}
|
| 401 |
+
|
| 402 |
+
GC_bool GC_is_initialized = FALSE;
|
| 403 |
+
|
| 404 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 405 |
+
extern void GC_init_parallel(void);
|
| 406 |
+
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
|
| 407 |
+
|
| 408 |
+
void GC_init(void)
|
| 409 |
+
{
|
| 410 |
+
DCL_LOCK_STATE;
|
| 411 |
+
|
| 412 |
+
#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
|
| 413 |
+
if (!GC_is_initialized) {
|
| 414 |
+
BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
|
| 415 |
+
HMODULE hK32 = GetModuleHandleA("kernel32.dll");
|
| 416 |
+
if (hK32)
|
| 417 |
+
pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
|
| 418 |
+
GetProcAddress (hK32,
|
| 419 |
+
"InitializeCriticalSectionAndSpinCount");
|
| 420 |
+
if (pfn)
|
| 421 |
+
pfn(&GC_allocate_ml, 4000);
|
| 422 |
+
else
|
| 423 |
+
InitializeCriticalSection (&GC_allocate_ml);
|
| 424 |
+
}
|
| 425 |
+
#endif /* MSWIN32 */
|
| 426 |
+
|
| 427 |
+
LOCK();
|
| 428 |
+
GC_init_inner();
|
| 429 |
+
UNLOCK();
|
| 430 |
+
|
| 431 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 432 |
+
/* Make sure marker threads and started and thread local */
|
| 433 |
+
/* allocation is initialized, in case we didn't get */
|
| 434 |
+
/* called from GC_init_parallel(); */
|
| 435 |
+
{
|
| 436 |
+
GC_init_parallel();
|
| 437 |
+
}
|
| 438 |
+
# endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
|
| 439 |
+
|
| 440 |
+
# if defined(DYNAMIC_LOADING) && defined(DARWIN)
|
| 441 |
+
{
|
| 442 |
+
/* This must be called WITHOUT the allocation lock held
|
| 443 |
+
and before any threads are created */
|
| 444 |
+
extern void GC_init_dyld();
|
| 445 |
+
GC_init_dyld();
|
| 446 |
+
}
|
| 447 |
+
# endif
|
| 448 |
+
}
|
| 449 |
+
|
| 450 |
+
#if defined(MSWIN32) || defined(MSWINCE)
|
| 451 |
+
CRITICAL_SECTION GC_write_cs;
|
| 452 |
+
#endif
|
| 453 |
+
|
| 454 |
+
#ifdef MSWIN32
|
| 455 |
+
extern void GC_init_win32(void);
|
| 456 |
+
#endif
|
| 457 |
+
|
| 458 |
+
extern void GC_setpagesize();
|
| 459 |
+
|
| 460 |
+
|
| 461 |
+
#ifdef MSWIN32
|
| 462 |
+
extern GC_bool GC_no_win32_dlls;
|
| 463 |
+
#else
|
| 464 |
+
# define GC_no_win32_dlls FALSE
|
| 465 |
+
#endif
|
| 466 |
+
|
| 467 |
+
void GC_exit_check(void)
|
| 468 |
+
{
|
| 469 |
+
GC_gcollect();
|
| 470 |
+
}
|
| 471 |
+
|
| 472 |
+
#ifdef SEARCH_FOR_DATA_START
|
| 473 |
+
extern void GC_init_linux_data_start(void);
|
| 474 |
+
#endif
|
| 475 |
+
|
| 476 |
+
#ifdef UNIX_LIKE
|
| 477 |
+
|
| 478 |
+
extern void GC_set_and_save_fault_handler(void (*handler)(int));
|
| 479 |
+
|
| 480 |
+
static void looping_handler(sig)
|
| 481 |
+
int sig;
|
| 482 |
+
{
|
| 483 |
+
GC_err_printf("Caught signal %d: looping in handler\n", sig);
|
| 484 |
+
for(;;);
|
| 485 |
+
}
|
| 486 |
+
|
| 487 |
+
static GC_bool installed_looping_handler = FALSE;
|
| 488 |
+
|
| 489 |
+
static void maybe_install_looping_handler()
|
| 490 |
+
{
|
| 491 |
+
/* Install looping handler before the write fault handler, so we */
|
| 492 |
+
/* handle write faults correctly. */
|
| 493 |
+
if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
|
| 494 |
+
GC_set_and_save_fault_handler(looping_handler);
|
| 495 |
+
installed_looping_handler = TRUE;
|
| 496 |
+
}
|
| 497 |
+
}
|
| 498 |
+
|
| 499 |
+
#else /* !UNIX_LIKE */
|
| 500 |
+
|
| 501 |
+
# define maybe_install_looping_handler()
|
| 502 |
+
|
| 503 |
+
#endif
|
| 504 |
+
|
| 505 |
+
void GC_init_inner()
|
| 506 |
+
{
|
| 507 |
+
# if !defined(THREADS) && defined(GC_ASSERTIONS)
|
| 508 |
+
word dummy;
|
| 509 |
+
# endif
|
| 510 |
+
word initial_heap_sz = (word)MINHINCR;
|
| 511 |
+
|
| 512 |
+
if (GC_is_initialized) return;
|
| 513 |
+
# if defined(MSWIN32) || defined(MSWINCE)
|
| 514 |
+
InitializeCriticalSection(&GC_write_cs);
|
| 515 |
+
# endif
|
| 516 |
+
# if (!defined(SMALL_CONFIG))
|
| 517 |
+
if (0 != GETENV("GC_PRINT_STATS")) {
|
| 518 |
+
GC_print_stats = 1;
|
| 519 |
+
}
|
| 520 |
+
if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) {
|
| 521 |
+
GC_print_stats = VERBOSE;
|
| 522 |
+
}
|
| 523 |
+
# if defined(UNIX_LIKE)
|
| 524 |
+
{
|
| 525 |
+
char * file_name = GETENV("GC_LOG_FILE");
|
| 526 |
+
if (0 != file_name) {
|
| 527 |
+
int log_d = open(file_name, O_CREAT|O_WRONLY|O_APPEND, 0666);
|
| 528 |
+
if (log_d < 0) {
|
| 529 |
+
GC_log_printf("Failed to open %s as log file\n", file_name);
|
| 530 |
+
} else {
|
| 531 |
+
GC_log = log_d;
|
| 532 |
+
}
|
| 533 |
+
}
|
| 534 |
+
}
|
| 535 |
+
# endif
|
| 536 |
+
# endif
|
| 537 |
+
# ifndef NO_DEBUGGING
|
| 538 |
+
if (0 != GETENV("GC_DUMP_REGULARLY")) {
|
| 539 |
+
GC_dump_regularly = 1;
|
| 540 |
+
}
|
| 541 |
+
# endif
|
| 542 |
+
# ifdef KEEP_BACK_PTRS
|
| 543 |
+
{
|
| 544 |
+
char * backtraces_string = GETENV("GC_BACKTRACES");
|
| 545 |
+
if (0 != backtraces_string) {
|
| 546 |
+
GC_backtraces = atol(backtraces_string);
|
| 547 |
+
if (backtraces_string[0] == '\0') GC_backtraces = 1;
|
| 548 |
+
}
|
| 549 |
+
}
|
| 550 |
+
# endif
|
| 551 |
+
if (0 != GETENV("GC_FIND_LEAK")) {
|
| 552 |
+
GC_find_leak = 1;
|
| 553 |
+
atexit(GC_exit_check);
|
| 554 |
+
}
|
| 555 |
+
if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
|
| 556 |
+
GC_all_interior_pointers = 1;
|
| 557 |
+
}
|
| 558 |
+
if (0 != GETENV("GC_DONT_GC")) {
|
| 559 |
+
GC_dont_gc = 1;
|
| 560 |
+
}
|
| 561 |
+
if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) {
|
| 562 |
+
GC_print_back_height = 1;
|
| 563 |
+
}
|
| 564 |
+
if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
|
| 565 |
+
GC_large_alloc_warn_interval = LONG_MAX;
|
| 566 |
+
}
|
| 567 |
+
{
|
| 568 |
+
char * addr_string = GETENV("GC_TRACE");
|
| 569 |
+
if (0 != addr_string) {
|
| 570 |
+
# ifndef ENABLE_TRACE
|
| 571 |
+
WARN("Tracing not enabled: Ignoring GC_TRACE value\n", 0);
|
| 572 |
+
# else
|
| 573 |
+
# ifdef STRTOULL
|
| 574 |
+
long long addr = strtoull(addr_string, NULL, 16);
|
| 575 |
+
# else
|
| 576 |
+
long addr = strtoul(addr_string, NULL, 16);
|
| 577 |
+
# endif
|
| 578 |
+
if (addr < 0x1000)
|
| 579 |
+
WARN("Unlikely trace address: 0x%lx\n", (GC_word)addr);
|
| 580 |
+
GC_trace_addr = (ptr_t)addr;
|
| 581 |
+
# endif
|
| 582 |
+
}
|
| 583 |
+
}
|
| 584 |
+
{
|
| 585 |
+
char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
|
| 586 |
+
if (0 != time_limit_string) {
|
| 587 |
+
long time_limit = atol(time_limit_string);
|
| 588 |
+
if (time_limit < 5) {
|
| 589 |
+
WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
|
| 590 |
+
"or bad syntax: Ignoring\n", 0);
|
| 591 |
+
} else {
|
| 592 |
+
GC_time_limit = time_limit;
|
| 593 |
+
}
|
| 594 |
+
}
|
| 595 |
+
}
|
| 596 |
+
{
|
| 597 |
+
char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
|
| 598 |
+
if (0 != interval_string) {
|
| 599 |
+
long interval = atol(interval_string);
|
| 600 |
+
if (interval <= 0) {
|
| 601 |
+
WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
|
| 602 |
+
"bad value: Ignoring\n", 0);
|
| 603 |
+
} else {
|
| 604 |
+
GC_large_alloc_warn_interval = interval;
|
| 605 |
+
}
|
| 606 |
+
}
|
| 607 |
+
}
|
| 608 |
+
maybe_install_looping_handler();
|
| 609 |
+
/* Adjust normal object descriptor for extra allocation. */
|
| 610 |
+
if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
|
| 611 |
+
GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
|
| 612 |
+
}
|
| 613 |
+
GC_setpagesize();
|
| 614 |
+
GC_exclude_static_roots(beginGC_arrays, endGC_arrays);
|
| 615 |
+
GC_exclude_static_roots(beginGC_obj_kinds, endGC_obj_kinds);
|
| 616 |
+
# ifdef SEPARATE_GLOBALS
|
| 617 |
+
GC_exclude_static_roots(beginGC_objfreelist, endGC_objfreelist);
|
| 618 |
+
GC_exclude_static_roots(beginGC_aobjfreelist, endGC_aobjfreelist);
|
| 619 |
+
# endif
|
| 620 |
+
# ifdef MSWIN32
|
| 621 |
+
GC_init_win32();
|
| 622 |
+
# endif
|
| 623 |
+
# if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
|
| 624 |
+
WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
|
| 625 |
+
/* If thread stacks are cached, they tend to be scanned in */
|
| 626 |
+
/* entirety as part of the root set. This wil grow them to */
|
| 627 |
+
/* maximum size, and is generally not desirable. */
|
| 628 |
+
# endif
|
| 629 |
+
# if defined(SEARCH_FOR_DATA_START)
|
| 630 |
+
GC_init_linux_data_start();
|
| 631 |
+
# endif
|
| 632 |
+
# if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
|
| 633 |
+
GC_init_netbsd_elf();
|
| 634 |
+
# endif
|
| 635 |
+
# if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
|
| 636 |
+
|| defined(GC_SOLARIS_THREADS)
|
| 637 |
+
if (GC_stackbottom == 0) {
|
| 638 |
+
GC_stackbottom = GC_get_main_stack_base();
|
| 639 |
+
# if (defined(LINUX) || defined(HPUX)) && defined(IA64)
|
| 640 |
+
GC_register_stackbottom = GC_get_register_stack_base();
|
| 641 |
+
# endif
|
| 642 |
+
} else {
|
| 643 |
+
# if (defined(LINUX) || defined(HPUX)) && defined(IA64)
|
| 644 |
+
if (GC_register_stackbottom == 0) {
|
| 645 |
+
WARN("GC_register_stackbottom should be set with GC_stackbottom\n", 0);
|
| 646 |
+
/* The following may fail, since we may rely on */
|
| 647 |
+
/* alignment properties that may not hold with a user set */
|
| 648 |
+
/* GC_stackbottom. */
|
| 649 |
+
GC_register_stackbottom = GC_get_register_stack_base();
|
| 650 |
+
}
|
| 651 |
+
# endif
|
| 652 |
+
}
|
| 653 |
+
# endif
|
| 654 |
+
/* Ignore gcc -Wall warnings on the following. */
|
| 655 |
+
GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
|
| 656 |
+
GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
|
| 657 |
+
GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
|
| 658 |
+
# ifndef THREADS
|
| 659 |
+
# ifdef STACK_GROWS_DOWN
|
| 660 |
+
GC_ASSERT((word)(&dummy) <= (word)GC_stackbottom);
|
| 661 |
+
# else
|
| 662 |
+
GC_ASSERT((word)(&dummy) >= (word)GC_stackbottom);
|
| 663 |
+
# endif
|
| 664 |
+
# endif
|
| 665 |
+
# if !defined(_AUX_SOURCE) || defined(__GNUC__)
|
| 666 |
+
GC_ASSERT((word)(-1) > (word)0);
|
| 667 |
+
/* word should be unsigned */
|
| 668 |
+
# endif
|
| 669 |
+
GC_ASSERT((ptr_t)(word)(-1) > (ptr_t)0);
|
| 670 |
+
/* Ptr_t comparisons should behave as unsigned comparisons. */
|
| 671 |
+
GC_ASSERT((signed_word)(-1) < (signed_word)0);
|
| 672 |
+
# if !defined(SMALL_CONFIG)
|
| 673 |
+
if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
|
| 674 |
+
/* This used to test for !GC_no_win32_dlls. Why? */
|
| 675 |
+
GC_setpagesize();
|
| 676 |
+
/* For GWW_MPROTECT on Win32, this needs to happen before any */
|
| 677 |
+
/* heap memory is allocated. */
|
| 678 |
+
GC_dirty_init();
|
| 679 |
+
GC_ASSERT(GC_bytes_allocd == 0)
|
| 680 |
+
GC_incremental = TRUE;
|
| 681 |
+
}
|
| 682 |
+
# endif /* !SMALL_CONFIG */
|
| 683 |
+
|
| 684 |
+
/* Add initial guess of root sets. Do this first, since sbrk(0) */
|
| 685 |
+
/* might be used. */
|
| 686 |
+
if (GC_REGISTER_MAIN_STATIC_DATA()) GC_register_data_segments();
|
| 687 |
+
GC_init_headers();
|
| 688 |
+
GC_bl_init();
|
| 689 |
+
GC_mark_init();
|
| 690 |
+
{
|
| 691 |
+
char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
|
| 692 |
+
if (sz_str != NULL) {
|
| 693 |
+
initial_heap_sz = atoi(sz_str);
|
| 694 |
+
if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
|
| 695 |
+
WARN("Bad initial heap size %s - ignoring it.\n",
|
| 696 |
+
sz_str);
|
| 697 |
+
}
|
| 698 |
+
initial_heap_sz = divHBLKSZ(initial_heap_sz);
|
| 699 |
+
}
|
| 700 |
+
}
|
| 701 |
+
{
|
| 702 |
+
char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
|
| 703 |
+
if (sz_str != NULL) {
|
| 704 |
+
word max_heap_sz = (word)atol(sz_str);
|
| 705 |
+
if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
|
| 706 |
+
WARN("Bad maximum heap size %s - ignoring it.\n",
|
| 707 |
+
sz_str);
|
| 708 |
+
}
|
| 709 |
+
if (0 == GC_max_retries) GC_max_retries = 2;
|
| 710 |
+
GC_set_max_heap_size(max_heap_sz);
|
| 711 |
+
}
|
| 712 |
+
}
|
| 713 |
+
if (!GC_expand_hp_inner(initial_heap_sz)) {
|
| 714 |
+
GC_err_printf("Can't start up: not enough memory\n");
|
| 715 |
+
EXIT();
|
| 716 |
+
}
|
| 717 |
+
GC_initialize_offsets();
|
| 718 |
+
GC_register_displacement_inner(0L);
|
| 719 |
+
# if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
|
| 720 |
+
if (!GC_all_interior_pointers) {
|
| 721 |
+
/* TLS ABI uses pointer-sized offsets for dtv. */
|
| 722 |
+
GC_register_displacement_inner(sizeof(void *));
|
| 723 |
+
}
|
| 724 |
+
# endif
|
| 725 |
+
GC_init_size_map();
|
| 726 |
+
# ifdef PCR
|
| 727 |
+
if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
|
| 728 |
+
!= PCR_ERes_okay) {
|
| 729 |
+
ABORT("Can't lock load state\n");
|
| 730 |
+
} else if (PCR_IL_Unlock() != PCR_ERes_okay) {
|
| 731 |
+
ABORT("Can't unlock load state\n");
|
| 732 |
+
}
|
| 733 |
+
PCR_IL_Unlock();
|
| 734 |
+
GC_pcr_install();
|
| 735 |
+
# endif
|
| 736 |
+
GC_is_initialized = TRUE;
|
| 737 |
+
# if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
|
| 738 |
+
GC_thr_init();
|
| 739 |
+
# endif
|
| 740 |
+
COND_DUMP;
|
| 741 |
+
/* Get black list set up and/or incremental GC started */
|
| 742 |
+
if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
|
| 743 |
+
# ifdef STUBBORN_ALLOC
|
| 744 |
+
GC_stubborn_init();
|
| 745 |
+
# endif
|
| 746 |
+
# if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
|
| 747 |
+
{
|
| 748 |
+
extern void GC_init_lib_bounds(void);
|
| 749 |
+
GC_init_lib_bounds();
|
| 750 |
+
}
|
| 751 |
+
# endif
|
| 752 |
+
/* Convince lint that some things are used */
|
| 753 |
+
# ifdef LINT
|
| 754 |
+
{
|
| 755 |
+
extern char * GC_copyright[];
|
| 756 |
+
extern int GC_read();
|
| 757 |
+
extern void GC_register_finalizer_no_order();
|
| 758 |
+
|
| 759 |
+
GC_noop(GC_copyright, GC_find_header,
|
| 760 |
+
GC_push_one, GC_call_with_alloc_lock, GC_read,
|
| 761 |
+
GC_dont_expand,
|
| 762 |
+
# ifndef NO_DEBUGGING
|
| 763 |
+
GC_dump,
|
| 764 |
+
# endif
|
| 765 |
+
GC_register_finalizer_no_order);
|
| 766 |
+
}
|
| 767 |
+
# endif
|
| 768 |
+
}
|
| 769 |
+
|
| 770 |
+
void GC_enable_incremental(void)
|
| 771 |
+
{
|
| 772 |
+
# if !defined(SMALL_CONFIG) && !defined(KEEP_BACK_PTRS)
|
| 773 |
+
/* If we are keeping back pointers, the GC itself dirties all */
|
| 774 |
+
/* pages on which objects have been marked, making */
|
| 775 |
+
/* incremental GC pointless. */
|
| 776 |
+
if (!GC_find_leak) {
|
| 777 |
+
DCL_LOCK_STATE;
|
| 778 |
+
|
| 779 |
+
LOCK();
|
| 780 |
+
if (GC_incremental) goto out;
|
| 781 |
+
GC_setpagesize();
|
| 782 |
+
/* if (GC_no_win32_dlls) goto out; Should be win32S test? */
|
| 783 |
+
maybe_install_looping_handler(); /* Before write fault handler! */
|
| 784 |
+
GC_incremental = TRUE;
|
| 785 |
+
if (!GC_is_initialized) {
|
| 786 |
+
GC_init_inner();
|
| 787 |
+
} else {
|
| 788 |
+
GC_dirty_init();
|
| 789 |
+
}
|
| 790 |
+
if (!GC_dirty_maintained) goto out;
|
| 791 |
+
if (GC_dont_gc) {
|
| 792 |
+
/* Can't easily do it. */
|
| 793 |
+
UNLOCK();
|
| 794 |
+
return;
|
| 795 |
+
}
|
| 796 |
+
if (GC_bytes_allocd > 0) {
|
| 797 |
+
/* There may be unmarked reachable objects */
|
| 798 |
+
GC_gcollect_inner();
|
| 799 |
+
} /* else we're OK in assuming everything's */
|
| 800 |
+
/* clean since nothing can point to an */
|
| 801 |
+
/* unmarked object. */
|
| 802 |
+
GC_read_dirty();
|
| 803 |
+
out:
|
| 804 |
+
UNLOCK();
|
| 805 |
+
} else {
|
| 806 |
+
GC_init();
|
| 807 |
+
}
|
| 808 |
+
# else
|
| 809 |
+
GC_init();
|
| 810 |
+
# endif
|
| 811 |
+
}
|
| 812 |
+
|
| 813 |
+
|
| 814 |
+
#if defined(MSWIN32) || defined(MSWINCE)
|
| 815 |
+
# if defined(_MSC_VER) && defined(_DEBUG)
|
| 816 |
+
# include <crtdbg.h>
|
| 817 |
+
# endif
|
| 818 |
+
# ifdef OLD_WIN32_LOG_FILE
|
| 819 |
+
# define LOG_FILE _T("gc.log")
|
| 820 |
+
# endif
|
| 821 |
+
|
| 822 |
+
HANDLE GC_stdout = 0;
|
| 823 |
+
|
| 824 |
+
void GC_deinit()
|
| 825 |
+
{
|
| 826 |
+
if (GC_is_initialized) {
|
| 827 |
+
DeleteCriticalSection(&GC_write_cs);
|
| 828 |
+
}
|
| 829 |
+
}
|
| 830 |
+
|
| 831 |
+
# ifndef THREADS
|
| 832 |
+
# define GC_need_to_lock 0 /* Not defined without threads */
|
| 833 |
+
# endif
|
| 834 |
+
int GC_write(const char *buf, size_t len)
|
| 835 |
+
{
|
| 836 |
+
BOOL tmp;
|
| 837 |
+
DWORD written;
|
| 838 |
+
if (len == 0)
|
| 839 |
+
return 0;
|
| 840 |
+
if (GC_need_to_lock) EnterCriticalSection(&GC_write_cs);
|
| 841 |
+
if (GC_stdout == INVALID_HANDLE_VALUE) {
|
| 842 |
+
if (GC_need_to_lock) LeaveCriticalSection(&GC_write_cs);
|
| 843 |
+
return -1;
|
| 844 |
+
} else if (GC_stdout == 0) {
|
| 845 |
+
char * file_name = GETENV("GC_LOG_FILE");
|
| 846 |
+
char logPath[_MAX_PATH + 5];
|
| 847 |
+
|
| 848 |
+
if (0 == file_name) {
|
| 849 |
+
# ifdef OLD_WIN32_LOG_FILE
|
| 850 |
+
strcpy(logPath, LOG_FILE);
|
| 851 |
+
# else
|
| 852 |
+
GetModuleFileName(NULL, logPath, _MAX_PATH);
|
| 853 |
+
strcat(logPath, ".log");
|
| 854 |
+
# endif
|
| 855 |
+
file_name = logPath;
|
| 856 |
+
}
|
| 857 |
+
GC_stdout = CreateFile(logPath, GENERIC_WRITE,
|
| 858 |
+
FILE_SHARE_READ,
|
| 859 |
+
NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
|
| 860 |
+
NULL);
|
| 861 |
+
if (GC_stdout == INVALID_HANDLE_VALUE)
|
| 862 |
+
ABORT("Open of log file failed");
|
| 863 |
+
}
|
| 864 |
+
tmp = WriteFile(GC_stdout, buf, (DWORD)len, &written, NULL);
|
| 865 |
+
if (!tmp)
|
| 866 |
+
DebugBreak();
|
| 867 |
+
# if defined(_MSC_VER) && defined(_DEBUG)
|
| 868 |
+
_CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf);
|
| 869 |
+
# endif
|
| 870 |
+
if (GC_need_to_lock) LeaveCriticalSection(&GC_write_cs);
|
| 871 |
+
return tmp ? (int)written : -1;
|
| 872 |
+
}
|
| 873 |
+
# undef GC_need_to_lock
|
| 874 |
+
|
| 875 |
+
#endif
|
| 876 |
+
|
| 877 |
+
#if defined(OS2) || defined(MACOS)
|
| 878 |
+
FILE * GC_stdout = NULL;
|
| 879 |
+
FILE * GC_stderr = NULL;
|
| 880 |
+
FILE * GC_log = NULL;
|
| 881 |
+
int GC_tmp; /* Should really be local ... */
|
| 882 |
+
|
| 883 |
+
void GC_set_files()
|
| 884 |
+
{
|
| 885 |
+
if (GC_stdout == NULL) {
|
| 886 |
+
GC_stdout = stdout;
|
| 887 |
+
}
|
| 888 |
+
if (GC_stderr == NULL) {
|
| 889 |
+
GC_stderr = stderr;
|
| 890 |
+
}
|
| 891 |
+
if (GC_log == NULL) {
|
| 892 |
+
GC_log = stderr;
|
| 893 |
+
}
|
| 894 |
+
}
|
| 895 |
+
#endif
|
| 896 |
+
|
| 897 |
+
#if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
|
| 898 |
+
int GC_stdout = 1;
|
| 899 |
+
int GC_stderr = 2;
|
| 900 |
+
int GC_log = 2;
|
| 901 |
+
# if !defined(AMIGA)
|
| 902 |
+
# include <unistd.h>
|
| 903 |
+
# endif
|
| 904 |
+
#endif
|
| 905 |
+
|
| 906 |
+
#if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) \
|
| 907 |
+
&& !defined(MACOS) && !defined(ECOS) && !defined(NOSYS)
|
| 908 |
+
int GC_write(fd, buf, len)
|
| 909 |
+
int fd;
|
| 910 |
+
const char *buf;
|
| 911 |
+
size_t len;
|
| 912 |
+
{
|
| 913 |
+
register int bytes_written = 0;
|
| 914 |
+
register int result;
|
| 915 |
+
|
| 916 |
+
while (bytes_written < len) {
|
| 917 |
+
# ifdef GC_SOLARIS_THREADS
|
| 918 |
+
result = syscall(SYS_write, fd, buf + bytes_written,
|
| 919 |
+
len - bytes_written);
|
| 920 |
+
# else
|
| 921 |
+
result = write(fd, buf + bytes_written, len - bytes_written);
|
| 922 |
+
# endif
|
| 923 |
+
if (-1 == result) return(result);
|
| 924 |
+
bytes_written += result;
|
| 925 |
+
}
|
| 926 |
+
return(bytes_written);
|
| 927 |
+
}
|
| 928 |
+
#endif /* UN*X */
|
| 929 |
+
|
| 930 |
+
#ifdef ECOS
|
| 931 |
+
int GC_write(fd, buf, len)
|
| 932 |
+
{
|
| 933 |
+
_Jv_diag_write (buf, len);
|
| 934 |
+
return len;
|
| 935 |
+
}
|
| 936 |
+
#endif
|
| 937 |
+
|
| 938 |
+
#ifdef NOSYS
|
| 939 |
+
int GC_write(fd, buf, len)
|
| 940 |
+
{
|
| 941 |
+
/* No writing. */
|
| 942 |
+
return len;
|
| 943 |
+
}
|
| 944 |
+
#endif
|
| 945 |
+
|
| 946 |
+
|
| 947 |
+
#if defined(MSWIN32) || defined(MSWINCE)
|
| 948 |
+
/* FIXME: This is pretty ugly ... */
|
| 949 |
+
# define WRITE(f, buf, len) GC_write(buf, len)
|
| 950 |
+
#else
|
| 951 |
+
# if defined(OS2) || defined(MACOS)
|
| 952 |
+
# define WRITE(f, buf, len) (GC_set_files(), \
|
| 953 |
+
GC_tmp = fwrite((buf), 1, (len), (f)), \
|
| 954 |
+
fflush(f), GC_tmp)
|
| 955 |
+
# else
|
| 956 |
+
# define WRITE(f, buf, len) GC_write((f), (buf), (len))
|
| 957 |
+
# endif
|
| 958 |
+
#endif
|
| 959 |
+
|
| 960 |
+
#define BUFSZ 1024
|
| 961 |
+
#ifdef _MSC_VER
|
| 962 |
+
# define vsnprintf _vsnprintf
|
| 963 |
+
#endif
|
| 964 |
+
/* A version of printf that is unlikely to call malloc, and is thus safer */
|
| 965 |
+
/* to call from the collector in case malloc has been bound to GC_malloc. */
|
| 966 |
+
/* Floating point arguments ans formats should be avoided, since fp */
|
| 967 |
+
/* conversion is more likely to allocate. */
|
| 968 |
+
/* Assumes that no more than BUFSZ-1 characters are written at once. */
|
| 969 |
+
void GC_printf(const char *format, ...)
|
| 970 |
+
{
|
| 971 |
+
va_list args;
|
| 972 |
+
char buf[BUFSZ+1];
|
| 973 |
+
|
| 974 |
+
va_start(args, format);
|
| 975 |
+
if (GC_quiet) return;
|
| 976 |
+
buf[BUFSZ] = 0x15;
|
| 977 |
+
(void) vsnprintf(buf, BUFSZ, format, args);
|
| 978 |
+
va_end(args);
|
| 979 |
+
if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
|
| 980 |
+
if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
|
| 981 |
+
}
|
| 982 |
+
|
| 983 |
+
void GC_err_printf(const char *format, ...)
|
| 984 |
+
{
|
| 985 |
+
va_list args;
|
| 986 |
+
char buf[BUFSZ+1];
|
| 987 |
+
|
| 988 |
+
va_start(args, format);
|
| 989 |
+
buf[BUFSZ] = 0x15;
|
| 990 |
+
(void) vsnprintf(buf, BUFSZ, format, args);
|
| 991 |
+
va_end(args);
|
| 992 |
+
if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
|
| 993 |
+
if (WRITE(GC_stderr, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
|
| 994 |
+
}
|
| 995 |
+
|
| 996 |
+
void GC_log_printf(const char *format, ...)
|
| 997 |
+
{
|
| 998 |
+
va_list args;
|
| 999 |
+
char buf[BUFSZ+1];
|
| 1000 |
+
|
| 1001 |
+
va_start(args, format);
|
| 1002 |
+
buf[BUFSZ] = 0x15;
|
| 1003 |
+
(void) vsnprintf(buf, BUFSZ, format, args);
|
| 1004 |
+
va_end(args);
|
| 1005 |
+
if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
|
| 1006 |
+
if (WRITE(GC_log, buf, strlen(buf)) < 0) ABORT("write to log failed");
|
| 1007 |
+
}
|
| 1008 |
+
|
| 1009 |
+
void GC_err_puts(const char *s)
|
| 1010 |
+
{
|
| 1011 |
+
if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
|
| 1012 |
+
}
|
| 1013 |
+
|
| 1014 |
+
#if defined(LINUX) && !defined(SMALL_CONFIG)
|
| 1015 |
+
void GC_err_write(buf, len)
|
| 1016 |
+
const char *buf;
|
| 1017 |
+
size_t len;
|
| 1018 |
+
{
|
| 1019 |
+
if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed");
|
| 1020 |
+
}
|
| 1021 |
+
#endif
|
| 1022 |
+
|
| 1023 |
+
void GC_default_warn_proc(char *msg, GC_word arg)
|
| 1024 |
+
{
|
| 1025 |
+
GC_err_printf(msg, arg);
|
| 1026 |
+
}
|
| 1027 |
+
|
| 1028 |
+
GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
|
| 1029 |
+
|
| 1030 |
+
GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
|
| 1031 |
+
{
|
| 1032 |
+
GC_warn_proc result;
|
| 1033 |
+
|
| 1034 |
+
# ifdef GC_WIN32_THREADS
|
| 1035 |
+
GC_ASSERT(GC_is_initialized);
|
| 1036 |
+
# endif
|
| 1037 |
+
LOCK();
|
| 1038 |
+
result = GC_current_warn_proc;
|
| 1039 |
+
GC_current_warn_proc = p;
|
| 1040 |
+
UNLOCK();
|
| 1041 |
+
return(result);
|
| 1042 |
+
}
|
| 1043 |
+
|
| 1044 |
+
GC_word GC_set_free_space_divisor (GC_word value)
|
| 1045 |
+
{
|
| 1046 |
+
GC_word old = GC_free_space_divisor;
|
| 1047 |
+
GC_free_space_divisor = value;
|
| 1048 |
+
return old;
|
| 1049 |
+
}
|
| 1050 |
+
|
| 1051 |
+
#ifndef PCR
|
| 1052 |
+
void GC_abort(const char *msg)
|
| 1053 |
+
{
|
| 1054 |
+
# if defined(MSWIN32)
|
| 1055 |
+
(void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
|
| 1056 |
+
# else
|
| 1057 |
+
GC_err_printf("%s\n", msg);
|
| 1058 |
+
# endif
|
| 1059 |
+
if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
|
| 1060 |
+
/* In many cases it's easier to debug a running process. */
|
| 1061 |
+
/* It's arguably nicer to sleep, but that makes it harder */
|
| 1062 |
+
/* to look at the thread if the debugger doesn't know much */
|
| 1063 |
+
/* about threads. */
|
| 1064 |
+
for(;;) {}
|
| 1065 |
+
}
|
| 1066 |
+
# if defined(MSWIN32) || defined(MSWINCE)
|
| 1067 |
+
DebugBreak();
|
| 1068 |
+
# else
|
| 1069 |
+
(void) abort();
|
| 1070 |
+
# endif
|
| 1071 |
+
}
|
| 1072 |
+
#endif
|
| 1073 |
+
|
| 1074 |
+
void GC_enable()
|
| 1075 |
+
{
|
| 1076 |
+
LOCK();
|
| 1077 |
+
GC_dont_gc--;
|
| 1078 |
+
UNLOCK();
|
| 1079 |
+
}
|
| 1080 |
+
|
| 1081 |
+
void GC_disable()
|
| 1082 |
+
{
|
| 1083 |
+
LOCK();
|
| 1084 |
+
GC_dont_gc++;
|
| 1085 |
+
UNLOCK();
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
+
/* Helper procedures for new kind creation. */
|
| 1089 |
+
void ** GC_new_free_list_inner()
|
| 1090 |
+
{
|
| 1091 |
+
void *result = GC_INTERNAL_MALLOC((MAXOBJGRANULES+1)*sizeof(ptr_t),
|
| 1092 |
+
PTRFREE);
|
| 1093 |
+
if (result == 0) ABORT("Failed to allocate freelist for new kind");
|
| 1094 |
+
BZERO(result, (MAXOBJGRANULES+1)*sizeof(ptr_t));
|
| 1095 |
+
return result;
|
| 1096 |
+
}
|
| 1097 |
+
|
| 1098 |
+
void ** GC_new_free_list()
|
| 1099 |
+
{
|
| 1100 |
+
void *result;
|
| 1101 |
+
LOCK();
|
| 1102 |
+
result = GC_new_free_list_inner();
|
| 1103 |
+
UNLOCK();
|
| 1104 |
+
return result;
|
| 1105 |
+
}
|
| 1106 |
+
|
| 1107 |
+
unsigned GC_new_kind_inner(void **fl, GC_word descr, int adjust, int clear)
|
| 1108 |
+
{
|
| 1109 |
+
unsigned result = GC_n_kinds++;
|
| 1110 |
+
|
| 1111 |
+
if (GC_n_kinds > MAXOBJKINDS) ABORT("Too many kinds");
|
| 1112 |
+
GC_obj_kinds[result].ok_freelist = fl;
|
| 1113 |
+
GC_obj_kinds[result].ok_reclaim_list = 0;
|
| 1114 |
+
GC_obj_kinds[result].ok_descriptor = descr;
|
| 1115 |
+
GC_obj_kinds[result].ok_relocate_descr = adjust;
|
| 1116 |
+
GC_obj_kinds[result].ok_init = clear;
|
| 1117 |
+
return result;
|
| 1118 |
+
}
|
| 1119 |
+
|
| 1120 |
+
unsigned GC_new_kind(void **fl, GC_word descr, int adjust, int clear)
|
| 1121 |
+
{
|
| 1122 |
+
unsigned result;
|
| 1123 |
+
LOCK();
|
| 1124 |
+
result = GC_new_kind_inner(fl, descr, adjust, clear);
|
| 1125 |
+
UNLOCK();
|
| 1126 |
+
return result;
|
| 1127 |
+
}
|
| 1128 |
+
|
| 1129 |
+
unsigned GC_new_proc_inner(GC_mark_proc proc)
|
| 1130 |
+
{
|
| 1131 |
+
unsigned result = GC_n_mark_procs++;
|
| 1132 |
+
|
| 1133 |
+
if (GC_n_mark_procs > MAX_MARK_PROCS) ABORT("Too many mark procedures");
|
| 1134 |
+
GC_mark_procs[result] = proc;
|
| 1135 |
+
return result;
|
| 1136 |
+
}
|
| 1137 |
+
|
| 1138 |
+
unsigned GC_new_proc(GC_mark_proc proc)
|
| 1139 |
+
{
|
| 1140 |
+
unsigned result;
|
| 1141 |
+
LOCK();
|
| 1142 |
+
result = GC_new_proc_inner(proc);
|
| 1143 |
+
UNLOCK();
|
| 1144 |
+
return result;
|
| 1145 |
+
}
|
| 1146 |
+
|
| 1147 |
+
void * GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
|
| 1148 |
+
{
|
| 1149 |
+
int dummy;
|
| 1150 |
+
struct GC_stack_base base;
|
| 1151 |
+
|
| 1152 |
+
base.mem_base = (void *)&dummy;
|
| 1153 |
+
# ifdef IA64
|
| 1154 |
+
base.reg_base = (void *)GC_save_regs_in_stack();
|
| 1155 |
+
/* Unnecessarily flushes register stack, */
|
| 1156 |
+
/* but that probably doesn't hurt. */
|
| 1157 |
+
# endif
|
| 1158 |
+
return fn(&base, arg);
|
| 1159 |
+
}
|
| 1160 |
+
|
| 1161 |
+
#if !defined(NO_DEBUGGING)
|
| 1162 |
+
|
| 1163 |
+
void GC_dump()
|
| 1164 |
+
{
|
| 1165 |
+
GC_printf("***Static roots:\n");
|
| 1166 |
+
GC_print_static_roots();
|
| 1167 |
+
GC_printf("\n***Heap sections:\n");
|
| 1168 |
+
GC_print_heap_sects();
|
| 1169 |
+
GC_printf("\n***Free blocks:\n");
|
| 1170 |
+
GC_print_hblkfreelist();
|
| 1171 |
+
GC_printf("\n***Blocks in use:\n");
|
| 1172 |
+
GC_print_block_list();
|
| 1173 |
+
GC_printf("\n***Finalization statistics:\n");
|
| 1174 |
+
GC_print_finalization_stats();
|
| 1175 |
+
}
|
| 1176 |
+
|
| 1177 |
+
#endif /* NO_DEBUGGING */
|
mosesdecoder/jam-files/engine/boehm_gc/os_dep.c
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
mosesdecoder/jam-files/engine/boehm_gc/pcr_interface.c
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
|
| 3 |
+
*
|
| 4 |
+
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 5 |
+
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 6 |
+
*
|
| 7 |
+
* Permission is hereby granted to use or copy this program
|
| 8 |
+
* for any purpose, provided the above notices are retained on all copies.
|
| 9 |
+
* Permission to modify the code and to distribute modified code is granted,
|
| 10 |
+
* provided the above notices are retained, and a notice that the code was
|
| 11 |
+
* modified is included with the above copyright notice.
|
| 12 |
+
*/
|
| 13 |
+
# include "private/gc_priv.h"
|
| 14 |
+
|
| 15 |
+
# ifdef PCR
|
| 16 |
+
/*
|
| 17 |
+
* Note that POSIX PCR requires an ANSI C compiler. Hence we are allowed
|
| 18 |
+
* to make the same assumption here.
|
| 19 |
+
* We wrap all of the allocator functions to avoid questions of
|
| 20 |
+
* compatibility between the prototyped and nonprototyped versions of the f
|
| 21 |
+
*/
|
| 22 |
+
# include "config/PCR_StdTypes.h"
|
| 23 |
+
# include "mm/PCR_MM.h"
|
| 24 |
+
# include <errno.h>
|
| 25 |
+
|
| 26 |
+
# define MY_MAGIC 17L
|
| 27 |
+
# define MY_DEBUGMAGIC 42L
|
| 28 |
+
|
| 29 |
+
void * GC_AllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear )
|
| 30 |
+
{
|
| 31 |
+
if (ptrFree) {
|
| 32 |
+
void * result = (void *)GC_malloc_atomic(size);
|
| 33 |
+
if (clear && result != 0) BZERO(result, size);
|
| 34 |
+
return(result);
|
| 35 |
+
} else {
|
| 36 |
+
return((void *)GC_malloc(size));
|
| 37 |
+
}
|
| 38 |
+
}
|
| 39 |
+
|
| 40 |
+
void * GC_DebugAllocProc(size_t size, PCR_Bool ptrFree, PCR_Bool clear )
|
| 41 |
+
{
|
| 42 |
+
if (ptrFree) {
|
| 43 |
+
void * result = (void *)GC_debug_malloc_atomic(size, __FILE__,
|
| 44 |
+
__LINE__);
|
| 45 |
+
if (clear && result != 0) BZERO(result, size);
|
| 46 |
+
return(result);
|
| 47 |
+
} else {
|
| 48 |
+
return((void *)GC_debug_malloc(size, __FILE__, __LINE__));
|
| 49 |
+
}
|
| 50 |
+
}
|
| 51 |
+
|
| 52 |
+
# define GC_ReallocProc GC_realloc
|
| 53 |
+
void * GC_DebugReallocProc(void * old_object, size_t new_size_in_bytes)
|
| 54 |
+
{
|
| 55 |
+
return(GC_debug_realloc(old_object, new_size_in_bytes, __FILE__, __LINE__));
|
| 56 |
+
}
|
| 57 |
+
|
| 58 |
+
# define GC_FreeProc GC_free
|
| 59 |
+
# define GC_DebugFreeProc GC_debug_free
|
| 60 |
+
|
| 61 |
+
typedef struct {
|
| 62 |
+
PCR_ERes (*ed_proc)(void *p, size_t size, PCR_Any data);
|
| 63 |
+
GC_bool ed_pointerfree;
|
| 64 |
+
PCR_ERes ed_fail_code;
|
| 65 |
+
PCR_Any ed_client_data;
|
| 66 |
+
} enumerate_data;
|
| 67 |
+
|
| 68 |
+
void GC_enumerate_block(struct hblk *h; enumerate_data * ed)
|
| 69 |
+
{
|
| 70 |
+
register hdr * hhdr;
|
| 71 |
+
register int sz;
|
| 72 |
+
ptr_t p;
|
| 73 |
+
ptr_t lim;
|
| 74 |
+
word descr;
|
| 75 |
+
# error This code was updated without testing.
|
| 76 |
+
# error and its precursor was clearly broken.
|
| 77 |
+
|
| 78 |
+
hhdr = HDR(h);
|
| 79 |
+
descr = hhdr -> hb_descr;
|
| 80 |
+
sz = hhdr -> hb_sz;
|
| 81 |
+
if (descr != 0 && ed -> ed_pointerfree
|
| 82 |
+
|| descr == 0 && !(ed -> ed_pointerfree)) return;
|
| 83 |
+
lim = (ptr_t)(h+1) - sz;
|
| 84 |
+
p = (ptr_t)h;
|
| 85 |
+
do {
|
| 86 |
+
if (PCR_ERes_IsErr(ed -> ed_fail_code)) return;
|
| 87 |
+
ed -> ed_fail_code =
|
| 88 |
+
(*(ed -> ed_proc))(p, sz, ed -> ed_client_data);
|
| 89 |
+
p+= sz;
|
| 90 |
+
} while (p <= lim);
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
struct PCR_MM_ProcsRep * GC_old_allocator = 0;
|
| 94 |
+
|
| 95 |
+
PCR_ERes GC_EnumerateProc(
|
| 96 |
+
PCR_Bool ptrFree,
|
| 97 |
+
PCR_ERes (*proc)(void *p, size_t size, PCR_Any data),
|
| 98 |
+
PCR_Any data
|
| 99 |
+
)
|
| 100 |
+
{
|
| 101 |
+
enumerate_data ed;
|
| 102 |
+
|
| 103 |
+
ed.ed_proc = proc;
|
| 104 |
+
ed.ed_pointerfree = ptrFree;
|
| 105 |
+
ed.ed_fail_code = PCR_ERes_okay;
|
| 106 |
+
ed.ed_client_data = data;
|
| 107 |
+
GC_apply_to_all_blocks(GC_enumerate_block, &ed);
|
| 108 |
+
if (ed.ed_fail_code != PCR_ERes_okay) {
|
| 109 |
+
return(ed.ed_fail_code);
|
| 110 |
+
} else {
|
| 111 |
+
/* Also enumerate objects allocated by my predecessors */
|
| 112 |
+
return((*(GC_old_allocator->mmp_enumerate))(ptrFree, proc, data));
|
| 113 |
+
}
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
void GC_DummyFreeProc(void *p) {}
|
| 117 |
+
|
| 118 |
+
void GC_DummyShutdownProc(void) {}
|
| 119 |
+
|
| 120 |
+
struct PCR_MM_ProcsRep GC_Rep = {
|
| 121 |
+
MY_MAGIC,
|
| 122 |
+
GC_AllocProc,
|
| 123 |
+
GC_ReallocProc,
|
| 124 |
+
GC_DummyFreeProc, /* mmp_free */
|
| 125 |
+
GC_FreeProc, /* mmp_unsafeFree */
|
| 126 |
+
GC_EnumerateProc,
|
| 127 |
+
GC_DummyShutdownProc /* mmp_shutdown */
|
| 128 |
+
};
|
| 129 |
+
|
| 130 |
+
struct PCR_MM_ProcsRep GC_DebugRep = {
|
| 131 |
+
MY_DEBUGMAGIC,
|
| 132 |
+
GC_DebugAllocProc,
|
| 133 |
+
GC_DebugReallocProc,
|
| 134 |
+
GC_DummyFreeProc, /* mmp_free */
|
| 135 |
+
GC_DebugFreeProc, /* mmp_unsafeFree */
|
| 136 |
+
GC_EnumerateProc,
|
| 137 |
+
GC_DummyShutdownProc /* mmp_shutdown */
|
| 138 |
+
};
|
| 139 |
+
|
| 140 |
+
GC_bool GC_use_debug = 0;
|
| 141 |
+
|
| 142 |
+
void GC_pcr_install()
|
| 143 |
+
{
|
| 144 |
+
PCR_MM_Install((GC_use_debug? &GC_DebugRep : &GC_Rep), &GC_old_allocator);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
PCR_ERes
|
| 148 |
+
PCR_GC_Setup(void)
|
| 149 |
+
{
|
| 150 |
+
return PCR_ERes_okay;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
PCR_ERes
|
| 154 |
+
PCR_GC_Run(void)
|
| 155 |
+
{
|
| 156 |
+
|
| 157 |
+
if( !PCR_Base_TestPCRArg("-nogc") ) {
|
| 158 |
+
GC_quiet = ( PCR_Base_TestPCRArg("-gctrace") ? 0 : 1 );
|
| 159 |
+
GC_use_debug = (GC_bool)PCR_Base_TestPCRArg("-debug_alloc");
|
| 160 |
+
GC_init();
|
| 161 |
+
if( !PCR_Base_TestPCRArg("-nogc_incremental") ) {
|
| 162 |
+
/*
|
| 163 |
+
* awful hack to test whether VD is implemented ...
|
| 164 |
+
*/
|
| 165 |
+
if( PCR_VD_Start( 0, NIL, 0) != PCR_ERes_FromErr(ENOSYS) ) {
|
| 166 |
+
GC_enable_incremental();
|
| 167 |
+
}
|
| 168 |
+
}
|
| 169 |
+
}
|
| 170 |
+
return PCR_ERes_okay;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
void GC_push_thread_structures(void)
|
| 174 |
+
{
|
| 175 |
+
/* PCR doesn't work unless static roots are pushed. Can't get here. */
|
| 176 |
+
ABORT("In GC_push_thread_structures()");
|
| 177 |
+
}
|
| 178 |
+
|
| 179 |
+
# endif
|
mosesdecoder/jam-files/engine/boehm_gc/pthread_support.c
ADDED
|
@@ -0,0 +1,1495 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright (c) 1994 by Xerox Corporation. All rights reserved.
|
| 3 |
+
* Copyright (c) 1996 by Silicon Graphics. All rights reserved.
|
| 4 |
+
* Copyright (c) 1998 by Fergus Henderson. All rights reserved.
|
| 5 |
+
* Copyright (c) 2000-2005 by Hewlett-Packard Company. All rights reserved.
|
| 6 |
+
*
|
| 7 |
+
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 8 |
+
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 9 |
+
*
|
| 10 |
+
* Permission is hereby granted to use or copy this program
|
| 11 |
+
* for any purpose, provided the above notices are retained on all copies.
|
| 12 |
+
* Permission to modify the code and to distribute modified code is granted,
|
| 13 |
+
* provided the above notices are retained, and a notice that the code was
|
| 14 |
+
* modified is included with the above copyright notice.
|
| 15 |
+
*/
|
| 16 |
+
/*
|
| 17 |
+
* Support code originally for LinuxThreads, the clone()-based kernel
|
| 18 |
+
* thread package for Linux which is included in libc6.
|
| 19 |
+
*
|
| 20 |
+
* This code no doubt makes some assumptions beyond what is
|
| 21 |
+
* guaranteed by the pthread standard, though it now does
|
| 22 |
+
* very little of that. It now also supports NPTL, and many
|
| 23 |
+
* other Posix thread implementations. We are trying to merge
|
| 24 |
+
* all flavors of pthread dupport code into this file.
|
| 25 |
+
*/
|
| 26 |
+
/* DG/UX ix86 support <takis@xfree86.org> */
|
| 27 |
+
/*
|
| 28 |
+
* Linux_threads.c now also includes some code to support HPUX and
|
| 29 |
+
* OSF1 (Compaq Tru64 Unix, really). The OSF1 support is based on Eric Benson's
|
| 30 |
+
* patch.
|
| 31 |
+
*
|
| 32 |
+
* Eric also suggested an alternate basis for a lock implementation in
|
| 33 |
+
* his code:
|
| 34 |
+
* + #elif defined(OSF1)
|
| 35 |
+
* + unsigned long GC_allocate_lock = 0;
|
| 36 |
+
* + msemaphore GC_allocate_semaphore;
|
| 37 |
+
* + # define GC_TRY_LOCK() \
|
| 38 |
+
* + ((msem_lock(&GC_allocate_semaphore, MSEM_IF_NOWAIT) == 0) \
|
| 39 |
+
* + ? (GC_allocate_lock = 1) \
|
| 40 |
+
* + : 0)
|
| 41 |
+
* + # define GC_LOCK_TAKEN GC_allocate_lock
|
| 42 |
+
*/
|
| 43 |
+
|
| 44 |
+
/*#define DEBUG_THREADS 1*/
|
| 45 |
+
|
| 46 |
+
# include "private/pthread_support.h"
|
| 47 |
+
|
| 48 |
+
# if defined(GC_PTHREADS) && !defined(GC_WIN32_THREADS)
|
| 49 |
+
|
| 50 |
+
# if defined(GC_DGUX386_THREADS) && !defined(_POSIX4A_DRAFT10_SOURCE)
|
| 51 |
+
# define _POSIX4A_DRAFT10_SOURCE 1
|
| 52 |
+
# endif
|
| 53 |
+
|
| 54 |
+
# if defined(GC_DGUX386_THREADS) && !defined(_USING_POSIX4A_DRAFT10)
|
| 55 |
+
# define _USING_POSIX4A_DRAFT10 1
|
| 56 |
+
# endif
|
| 57 |
+
|
| 58 |
+
# include <stdlib.h>
|
| 59 |
+
# include <pthread.h>
|
| 60 |
+
# include <sched.h>
|
| 61 |
+
# include <time.h>
|
| 62 |
+
# include <errno.h>
|
| 63 |
+
# include <unistd.h>
|
| 64 |
+
# include <sys/mman.h>
|
| 65 |
+
# include <sys/time.h>
|
| 66 |
+
# include <sys/types.h>
|
| 67 |
+
# include <sys/stat.h>
|
| 68 |
+
# include <fcntl.h>
|
| 69 |
+
# include <signal.h>
|
| 70 |
+
|
| 71 |
+
# include "gc_inline.h"
|
| 72 |
+
|
| 73 |
+
#if defined(GC_DARWIN_THREADS)
|
| 74 |
+
# include "private/darwin_semaphore.h"
|
| 75 |
+
#else
|
| 76 |
+
# include <semaphore.h>
|
| 77 |
+
#endif /* !GC_DARWIN_THREADS */
|
| 78 |
+
|
| 79 |
+
#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
|
| 80 |
+
# include <sys/sysctl.h>
|
| 81 |
+
#endif /* GC_DARWIN_THREADS */
|
| 82 |
+
|
| 83 |
+
#if defined(GC_NETBSD_THREADS)
|
| 84 |
+
# include <sys/param.h>
|
| 85 |
+
# include <sys/sysctl.h>
|
| 86 |
+
#endif /* GC_NETBSD_THREADS */
|
| 87 |
+
|
| 88 |
+
/* Allocator lock definitions. */
|
| 89 |
+
#if !defined(USE_SPIN_LOCK)
|
| 90 |
+
pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
|
| 91 |
+
#endif
|
| 92 |
+
unsigned long GC_lock_holder = NO_THREAD;
|
| 93 |
+
/* Used only for assertions, and to prevent */
|
| 94 |
+
/* recursive reentry in the system call wrapper. */
|
| 95 |
+
|
| 96 |
+
#if defined(GC_DGUX386_THREADS)
|
| 97 |
+
# include <sys/dg_sys_info.h>
|
| 98 |
+
# include <sys/_int_psem.h>
|
| 99 |
+
/* sem_t is an uint in DG/UX */
|
| 100 |
+
typedef unsigned int sem_t;
|
| 101 |
+
#endif /* GC_DGUX386_THREADS */
|
| 102 |
+
|
| 103 |
+
#ifndef __GNUC__
|
| 104 |
+
# define __inline__
|
| 105 |
+
#endif
|
| 106 |
+
|
| 107 |
+
/* Undefine macros used to redirect pthread primitives. */
|
| 108 |
+
# undef pthread_create
|
| 109 |
+
# if !defined(GC_DARWIN_THREADS)
|
| 110 |
+
# undef pthread_sigmask
|
| 111 |
+
# endif
|
| 112 |
+
# undef pthread_join
|
| 113 |
+
# undef pthread_detach
|
| 114 |
+
# if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
|
| 115 |
+
&& !defined(_PTHREAD_USE_PTDNAM_)
|
| 116 |
+
/* Restore the original mangled names on Tru64 UNIX. */
|
| 117 |
+
# define pthread_create __pthread_create
|
| 118 |
+
# define pthread_join __pthread_join
|
| 119 |
+
# define pthread_detach __pthread_detach
|
| 120 |
+
# endif
|
| 121 |
+
|
| 122 |
+
#ifdef GC_USE_LD_WRAP
|
| 123 |
+
# define WRAP_FUNC(f) __wrap_##f
|
| 124 |
+
# define REAL_FUNC(f) __real_##f
|
| 125 |
+
#else
|
| 126 |
+
# ifdef GC_USE_DLOPEN_WRAP
|
| 127 |
+
# include <dlfcn.h>
|
| 128 |
+
# define WRAP_FUNC(f) f
|
| 129 |
+
# define REAL_FUNC(f) GC_real_##f
|
| 130 |
+
/* We define both GC_f and plain f to be the wrapped function. */
|
| 131 |
+
/* In that way plain calls work, as do calls from files that */
|
| 132 |
+
/* included gc.h, wich redefined f to GC_f. */
|
| 133 |
+
/* FIXME: Needs work for DARWIN and True64 (OSF1) */
|
| 134 |
+
typedef int (* GC_pthread_create_t)(pthread_t *, const pthread_attr_t *,
|
| 135 |
+
void * (*)(void *), void *);
|
| 136 |
+
static GC_pthread_create_t GC_real_pthread_create;
|
| 137 |
+
typedef int (* GC_pthread_sigmask_t)(int, const sigset_t *, sigset_t *);
|
| 138 |
+
static GC_pthread_sigmask_t GC_real_pthread_sigmask;
|
| 139 |
+
typedef int (* GC_pthread_join_t)(pthread_t, void **);
|
| 140 |
+
static GC_pthread_join_t GC_real_pthread_join;
|
| 141 |
+
typedef int (* GC_pthread_detach_t)(pthread_t);
|
| 142 |
+
static GC_pthread_detach_t GC_real_pthread_detach;
|
| 143 |
+
# else
|
| 144 |
+
# define WRAP_FUNC(f) GC_##f
|
| 145 |
+
# if !defined(GC_DGUX386_THREADS)
|
| 146 |
+
# define REAL_FUNC(f) f
|
| 147 |
+
# else /* GC_DGUX386_THREADS */
|
| 148 |
+
# define REAL_FUNC(f) __d10_##f
|
| 149 |
+
# endif /* GC_DGUX386_THREADS */
|
| 150 |
+
# endif
|
| 151 |
+
#endif
|
| 152 |
+
|
| 153 |
+
#if defined(GC_USE_DL_WRAP) || defined(GC_USE_DLOPEN_WRAP)
|
| 154 |
+
/* Define GC_ functions as aliases for the plain ones, which will */
|
| 155 |
+
/* be intercepted. This allows files which include gc.h, and hence */
|
| 156 |
+
/* generate referemces to the GC_ symbols, to see the right symbols. */
|
| 157 |
+
int GC_pthread_create(pthread_t * t, const pthread_attr_t * a,
|
| 158 |
+
void * (* fn)(void *), void * arg) {
|
| 159 |
+
return pthread_create(t, a, fn, arg);
|
| 160 |
+
}
|
| 161 |
+
int GC_pthread_sigmask(int how, const sigset_t *mask, sigset_t *old) {
|
| 162 |
+
return pthread_sigmask(how, mask, old);
|
| 163 |
+
}
|
| 164 |
+
int GC_pthread_join(pthread_t t, void **res) {
|
| 165 |
+
return pthread_join(t, res);
|
| 166 |
+
}
|
| 167 |
+
int GC_pthread_detach(pthread_t t) {
|
| 168 |
+
return pthread_detach(t);
|
| 169 |
+
}
|
| 170 |
+
#endif /* Linker-based interception. */
|
| 171 |
+
|
| 172 |
+
#ifdef GC_USE_DLOPEN_WRAP
|
| 173 |
+
static GC_bool GC_syms_initialized = FALSE;
|
| 174 |
+
|
| 175 |
+
void GC_init_real_syms(void)
|
| 176 |
+
{
|
| 177 |
+
void *dl_handle;
|
| 178 |
+
# define LIBPTHREAD_NAME "libpthread.so.0"
|
| 179 |
+
# define LIBPTHREAD_NAME_LEN 16 /* incl. trailing 0 */
|
| 180 |
+
size_t len = LIBPTHREAD_NAME_LEN - 1;
|
| 181 |
+
char namebuf[LIBPTHREAD_NAME_LEN];
|
| 182 |
+
static char *libpthread_name = LIBPTHREAD_NAME;
|
| 183 |
+
|
| 184 |
+
if (GC_syms_initialized) return;
|
| 185 |
+
# ifdef RTLD_NEXT
|
| 186 |
+
dl_handle = RTLD_NEXT;
|
| 187 |
+
# else
|
| 188 |
+
dl_handle = dlopen(libpthread_name, RTLD_LAZY);
|
| 189 |
+
if (NULL == dl_handle) {
|
| 190 |
+
while (isdigit(libpthread_name[len-1])) --len;
|
| 191 |
+
if (libpthread_name[len-1] == '.') --len;
|
| 192 |
+
memcpy(namebuf, libpthread_name, len);
|
| 193 |
+
namebuf[len] = '\0';
|
| 194 |
+
dl_handle = dlopen(namebuf, RTLD_LAZY);
|
| 195 |
+
}
|
| 196 |
+
if (NULL == dl_handle) ABORT("Couldn't open libpthread\n");
|
| 197 |
+
# endif
|
| 198 |
+
GC_real_pthread_create = (GC_pthread_create_t)
|
| 199 |
+
dlsym(dl_handle, "pthread_create");
|
| 200 |
+
GC_real_pthread_sigmask = (GC_pthread_sigmask_t)
|
| 201 |
+
dlsym(dl_handle, "pthread_sigmask");
|
| 202 |
+
GC_real_pthread_join = (GC_pthread_join_t)
|
| 203 |
+
dlsym(dl_handle, "pthread_join");
|
| 204 |
+
GC_real_pthread_detach = (GC_pthread_detach_t)
|
| 205 |
+
dlsym(dl_handle, "pthread_detach");
|
| 206 |
+
GC_syms_initialized = TRUE;
|
| 207 |
+
}
|
| 208 |
+
|
| 209 |
+
# define INIT_REAL_SYMS() if (!GC_syms_initialized) GC_init_real_syms();
|
| 210 |
+
#else
|
| 211 |
+
# define INIT_REAL_SYMS()
|
| 212 |
+
#endif
|
| 213 |
+
|
| 214 |
+
void GC_thr_init(void);
|
| 215 |
+
|
| 216 |
+
static GC_bool parallel_initialized = FALSE;
|
| 217 |
+
|
| 218 |
+
GC_bool GC_need_to_lock = FALSE;
|
| 219 |
+
|
| 220 |
+
void GC_init_parallel(void);
|
| 221 |
+
|
| 222 |
+
long GC_nprocs = 1; /* Number of processors. We may not have */
|
| 223 |
+
/* access to all of them, but this is as good */
|
| 224 |
+
/* a guess as any ... */
|
| 225 |
+
|
| 226 |
+
#ifdef THREAD_LOCAL_ALLOC
|
| 227 |
+
/* We must explicitly mark ptrfree and gcj free lists, since the free */
|
| 228 |
+
/* list links wouldn't otherwise be found. We also set them in the */
|
| 229 |
+
/* normal free lists, since that involves touching less memory than if */
|
| 230 |
+
/* we scanned them normally. */
|
| 231 |
+
void GC_mark_thread_local_free_lists(void)
|
| 232 |
+
{
|
| 233 |
+
int i;
|
| 234 |
+
GC_thread p;
|
| 235 |
+
|
| 236 |
+
for (i = 0; i < THREAD_TABLE_SZ; ++i) {
|
| 237 |
+
for (p = GC_threads[i]; 0 != p; p = p -> next) {
|
| 238 |
+
GC_mark_thread_local_fls_for(&(p->tlfs));
|
| 239 |
+
}
|
| 240 |
+
}
|
| 241 |
+
}
|
| 242 |
+
|
| 243 |
+
#if defined(GC_ASSERTIONS)
|
| 244 |
+
/* Check that all thread-local free-lists are completely marked. */
|
| 245 |
+
/* also check that thread-specific-data structures are marked. */
|
| 246 |
+
void GC_check_tls(void) {
|
| 247 |
+
int i;
|
| 248 |
+
GC_thread p;
|
| 249 |
+
|
| 250 |
+
for (i = 0; i < THREAD_TABLE_SZ; ++i) {
|
| 251 |
+
for (p = GC_threads[i]; 0 != p; p = p -> next) {
|
| 252 |
+
GC_check_tls_for(&(p->tlfs));
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
# if defined(USE_CUSTOM_SPECIFIC)
|
| 256 |
+
if (GC_thread_key != 0)
|
| 257 |
+
GC_check_tsd_marks(GC_thread_key);
|
| 258 |
+
# endif
|
| 259 |
+
}
|
| 260 |
+
#endif /* GC_ASSERTIONS */
|
| 261 |
+
|
| 262 |
+
#endif /* Thread_local_alloc */
|
| 263 |
+
|
| 264 |
+
#ifdef PARALLEL_MARK
|
| 265 |
+
|
| 266 |
+
# ifndef MAX_MARKERS
|
| 267 |
+
# define MAX_MARKERS 16
|
| 268 |
+
# endif
|
| 269 |
+
|
| 270 |
+
static ptr_t marker_sp[MAX_MARKERS] = {0};
|
| 271 |
+
#ifdef IA64
|
| 272 |
+
static ptr_t marker_bsp[MAX_MARKERS] = {0};
|
| 273 |
+
#endif
|
| 274 |
+
|
| 275 |
+
void * GC_mark_thread(void * id)
|
| 276 |
+
{
|
| 277 |
+
word my_mark_no = 0;
|
| 278 |
+
|
| 279 |
+
marker_sp[(word)id] = GC_approx_sp();
|
| 280 |
+
# ifdef IA64
|
| 281 |
+
marker_bsp[(word)id] = GC_save_regs_in_stack();
|
| 282 |
+
# endif
|
| 283 |
+
for (;; ++my_mark_no) {
|
| 284 |
+
/* GC_mark_no is passed only to allow GC_help_marker to terminate */
|
| 285 |
+
/* promptly. This is important if it were called from the signal */
|
| 286 |
+
/* handler or from the GC lock acquisition code. Under Linux, it's */
|
| 287 |
+
/* not safe to call it from a signal handler, since it uses mutexes */
|
| 288 |
+
/* and condition variables. Since it is called only here, the */
|
| 289 |
+
/* argument is unnecessary. */
|
| 290 |
+
if (my_mark_no < GC_mark_no || my_mark_no > GC_mark_no + 2) {
|
| 291 |
+
/* resynchronize if we get far off, e.g. because GC_mark_no */
|
| 292 |
+
/* wrapped. */
|
| 293 |
+
my_mark_no = GC_mark_no;
|
| 294 |
+
}
|
| 295 |
+
# ifdef DEBUG_THREADS
|
| 296 |
+
GC_printf("Starting mark helper for mark number %lu\n", my_mark_no);
|
| 297 |
+
# endif
|
| 298 |
+
GC_help_marker(my_mark_no);
|
| 299 |
+
}
|
| 300 |
+
}
|
| 301 |
+
|
| 302 |
+
extern long GC_markers; /* Number of mark threads we would */
|
| 303 |
+
/* like to have. Includes the */
|
| 304 |
+
/* initiating thread. */
|
| 305 |
+
|
| 306 |
+
pthread_t GC_mark_threads[MAX_MARKERS];
|
| 307 |
+
|
| 308 |
+
#define PTHREAD_CREATE REAL_FUNC(pthread_create)
|
| 309 |
+
|
| 310 |
+
static void start_mark_threads(void)
|
| 311 |
+
{
|
| 312 |
+
unsigned i;
|
| 313 |
+
pthread_attr_t attr;
|
| 314 |
+
|
| 315 |
+
if (GC_markers > MAX_MARKERS) {
|
| 316 |
+
WARN("Limiting number of mark threads\n", 0);
|
| 317 |
+
GC_markers = MAX_MARKERS;
|
| 318 |
+
}
|
| 319 |
+
if (0 != pthread_attr_init(&attr)) ABORT("pthread_attr_init failed");
|
| 320 |
+
|
| 321 |
+
if (0 != pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED))
|
| 322 |
+
ABORT("pthread_attr_setdetachstate failed");
|
| 323 |
+
|
| 324 |
+
# if defined(HPUX) || defined(GC_DGUX386_THREADS)
|
| 325 |
+
/* Default stack size is usually too small: fix it. */
|
| 326 |
+
/* Otherwise marker threads or GC may run out of */
|
| 327 |
+
/* space. */
|
| 328 |
+
# define MIN_STACK_SIZE (8*HBLKSIZE*sizeof(word))
|
| 329 |
+
{
|
| 330 |
+
size_t old_size;
|
| 331 |
+
int code;
|
| 332 |
+
|
| 333 |
+
if (pthread_attr_getstacksize(&attr, &old_size) != 0)
|
| 334 |
+
ABORT("pthread_attr_getstacksize failed\n");
|
| 335 |
+
if (old_size < MIN_STACK_SIZE) {
|
| 336 |
+
if (pthread_attr_setstacksize(&attr, MIN_STACK_SIZE) != 0)
|
| 337 |
+
ABORT("pthread_attr_setstacksize failed\n");
|
| 338 |
+
}
|
| 339 |
+
}
|
| 340 |
+
# endif /* HPUX || GC_DGUX386_THREADS */
|
| 341 |
+
if (GC_print_stats) {
|
| 342 |
+
GC_log_printf("Starting %ld marker threads\n", GC_markers - 1);
|
| 343 |
+
}
|
| 344 |
+
for (i = 0; i < GC_markers - 1; ++i) {
|
| 345 |
+
if (0 != PTHREAD_CREATE(GC_mark_threads + i, &attr,
|
| 346 |
+
GC_mark_thread, (void *)(word)i)) {
|
| 347 |
+
WARN("Marker thread creation failed, errno = %ld.\n", errno);
|
| 348 |
+
}
|
| 349 |
+
}
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
#endif /* PARALLEL_MARK */
|
| 353 |
+
|
| 354 |
+
GC_bool GC_thr_initialized = FALSE;
|
| 355 |
+
|
| 356 |
+
volatile GC_thread GC_threads[THREAD_TABLE_SZ];
|
| 357 |
+
|
| 358 |
+
void GC_push_thread_structures(void)
|
| 359 |
+
{
|
| 360 |
+
GC_ASSERT(I_HOLD_LOCK());
|
| 361 |
+
GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
|
| 362 |
+
# if defined(THREAD_LOCAL_ALLOC)
|
| 363 |
+
GC_push_all((ptr_t)(&GC_thread_key),
|
| 364 |
+
(ptr_t)(&GC_thread_key)+sizeof(&GC_thread_key));
|
| 365 |
+
# endif
|
| 366 |
+
}
|
| 367 |
+
|
| 368 |
+
/* It may not be safe to allocate when we register the first thread. */
|
| 369 |
+
static struct GC_Thread_Rep first_thread;
|
| 370 |
+
|
| 371 |
+
/* Add a thread to GC_threads. We assume it wasn't already there. */
|
| 372 |
+
/* Caller holds allocation lock. */
|
| 373 |
+
GC_thread GC_new_thread(pthread_t id)
|
| 374 |
+
{
|
| 375 |
+
int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
|
| 376 |
+
GC_thread result;
|
| 377 |
+
static GC_bool first_thread_used = FALSE;
|
| 378 |
+
|
| 379 |
+
GC_ASSERT(I_HOLD_LOCK());
|
| 380 |
+
if (!first_thread_used) {
|
| 381 |
+
result = &first_thread;
|
| 382 |
+
first_thread_used = TRUE;
|
| 383 |
+
} else {
|
| 384 |
+
result = (struct GC_Thread_Rep *)
|
| 385 |
+
GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
|
| 386 |
+
GC_ASSERT(result -> flags == 0);
|
| 387 |
+
}
|
| 388 |
+
if (result == 0) return(0);
|
| 389 |
+
result -> id = id;
|
| 390 |
+
result -> next = GC_threads[hv];
|
| 391 |
+
GC_threads[hv] = result;
|
| 392 |
+
GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
|
| 393 |
+
return(result);
|
| 394 |
+
}
|
| 395 |
+
|
| 396 |
+
/* Delete a thread from GC_threads. We assume it is there. */
|
| 397 |
+
/* (The code intentionally traps if it wasn't.) */
|
| 398 |
+
void GC_delete_thread(pthread_t id)
|
| 399 |
+
{
|
| 400 |
+
int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
|
| 401 |
+
register GC_thread p = GC_threads[hv];
|
| 402 |
+
register GC_thread prev = 0;
|
| 403 |
+
|
| 404 |
+
GC_ASSERT(I_HOLD_LOCK());
|
| 405 |
+
while (!THREAD_EQUAL(p -> id, id)) {
|
| 406 |
+
prev = p;
|
| 407 |
+
p = p -> next;
|
| 408 |
+
}
|
| 409 |
+
if (prev == 0) {
|
| 410 |
+
GC_threads[hv] = p -> next;
|
| 411 |
+
} else {
|
| 412 |
+
prev -> next = p -> next;
|
| 413 |
+
}
|
| 414 |
+
# ifdef GC_DARWIN_THREADS
|
| 415 |
+
mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
|
| 416 |
+
# endif
|
| 417 |
+
GC_INTERNAL_FREE(p);
|
| 418 |
+
}
|
| 419 |
+
|
| 420 |
+
/* If a thread has been joined, but we have not yet */
|
| 421 |
+
/* been notified, then there may be more than one thread */
|
| 422 |
+
/* in the table with the same pthread id. */
|
| 423 |
+
/* This is OK, but we need a way to delete a specific one. */
|
| 424 |
+
void GC_delete_gc_thread(GC_thread gc_id)
|
| 425 |
+
{
|
| 426 |
+
pthread_t id = gc_id -> id;
|
| 427 |
+
int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
|
| 428 |
+
register GC_thread p = GC_threads[hv];
|
| 429 |
+
register GC_thread prev = 0;
|
| 430 |
+
|
| 431 |
+
GC_ASSERT(I_HOLD_LOCK());
|
| 432 |
+
while (p != gc_id) {
|
| 433 |
+
prev = p;
|
| 434 |
+
p = p -> next;
|
| 435 |
+
}
|
| 436 |
+
if (prev == 0) {
|
| 437 |
+
GC_threads[hv] = p -> next;
|
| 438 |
+
} else {
|
| 439 |
+
prev -> next = p -> next;
|
| 440 |
+
}
|
| 441 |
+
# ifdef GC_DARWIN_THREADS
|
| 442 |
+
mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
|
| 443 |
+
# endif
|
| 444 |
+
GC_INTERNAL_FREE(p);
|
| 445 |
+
}
|
| 446 |
+
|
| 447 |
+
/* Return a GC_thread corresponding to a given pthread_t. */
|
| 448 |
+
/* Returns 0 if it's not there. */
|
| 449 |
+
/* Caller holds allocation lock or otherwise inhibits */
|
| 450 |
+
/* updates. */
|
| 451 |
+
/* If there is more than one thread with the given id we */
|
| 452 |
+
/* return the most recent one. */
|
| 453 |
+
GC_thread GC_lookup_thread(pthread_t id)
|
| 454 |
+
{
|
| 455 |
+
int hv = NUMERIC_THREAD_ID(id) % THREAD_TABLE_SZ;
|
| 456 |
+
register GC_thread p = GC_threads[hv];
|
| 457 |
+
|
| 458 |
+
while (p != 0 && !THREAD_EQUAL(p -> id, id)) p = p -> next;
|
| 459 |
+
return(p);
|
| 460 |
+
}
|
| 461 |
+
|
| 462 |
+
#ifdef HANDLE_FORK
|
| 463 |
+
/* Remove all entries from the GC_threads table, except the */
|
| 464 |
+
/* one for the current thread. We need to do this in the child */
|
| 465 |
+
/* process after a fork(), since only the current thread */
|
| 466 |
+
/* survives in the child. */
|
| 467 |
+
void GC_remove_all_threads_but_me(void)
|
| 468 |
+
{
|
| 469 |
+
pthread_t self = pthread_self();
|
| 470 |
+
int hv;
|
| 471 |
+
GC_thread p, next, me;
|
| 472 |
+
|
| 473 |
+
for (hv = 0; hv < THREAD_TABLE_SZ; ++hv) {
|
| 474 |
+
me = 0;
|
| 475 |
+
for (p = GC_threads[hv]; 0 != p; p = next) {
|
| 476 |
+
next = p -> next;
|
| 477 |
+
if (THREAD_EQUAL(p -> id, self)) {
|
| 478 |
+
me = p;
|
| 479 |
+
p -> next = 0;
|
| 480 |
+
} else {
|
| 481 |
+
# ifdef THREAD_LOCAL_ALLOC
|
| 482 |
+
if (!(p -> flags & FINISHED)) {
|
| 483 |
+
GC_destroy_thread_local(&(p->tlfs));
|
| 484 |
+
}
|
| 485 |
+
# endif /* THREAD_LOCAL_ALLOC */
|
| 486 |
+
if (p != &first_thread) GC_INTERNAL_FREE(p);
|
| 487 |
+
}
|
| 488 |
+
}
|
| 489 |
+
GC_threads[hv] = me;
|
| 490 |
+
}
|
| 491 |
+
}
|
| 492 |
+
#endif /* HANDLE_FORK */
|
| 493 |
+
|
| 494 |
+
#ifdef USE_PROC_FOR_LIBRARIES
|
| 495 |
+
GC_bool GC_segment_is_thread_stack(ptr_t lo, ptr_t hi)
|
| 496 |
+
{
|
| 497 |
+
int i;
|
| 498 |
+
GC_thread p;
|
| 499 |
+
|
| 500 |
+
GC_ASSERT(I_HOLD_LOCK());
|
| 501 |
+
# ifdef PARALLEL_MARK
|
| 502 |
+
for (i = 0; i < GC_markers; ++i) {
|
| 503 |
+
if (marker_sp[i] > lo & marker_sp[i] < hi) return TRUE;
|
| 504 |
+
# ifdef IA64
|
| 505 |
+
if (marker_bsp[i] > lo & marker_bsp[i] < hi) return TRUE;
|
| 506 |
+
# endif
|
| 507 |
+
}
|
| 508 |
+
# endif
|
| 509 |
+
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
| 510 |
+
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
| 511 |
+
if (0 != p -> stack_end) {
|
| 512 |
+
# ifdef STACK_GROWS_UP
|
| 513 |
+
if (p -> stack_end >= lo && p -> stack_end < hi) return TRUE;
|
| 514 |
+
# else /* STACK_GROWS_DOWN */
|
| 515 |
+
if (p -> stack_end > lo && p -> stack_end <= hi) return TRUE;
|
| 516 |
+
# endif
|
| 517 |
+
}
|
| 518 |
+
}
|
| 519 |
+
}
|
| 520 |
+
return FALSE;
|
| 521 |
+
}
|
| 522 |
+
#endif /* USE_PROC_FOR_LIBRARIES */
|
| 523 |
+
|
| 524 |
+
#ifdef IA64
|
| 525 |
+
/* Find the largest stack_base smaller than bound. May be used */
|
| 526 |
+
/* to find the boundary between a register stack and adjacent */
|
| 527 |
+
/* immediately preceding memory stack. */
|
| 528 |
+
ptr_t GC_greatest_stack_base_below(ptr_t bound)
|
| 529 |
+
{
|
| 530 |
+
int i;
|
| 531 |
+
GC_thread p;
|
| 532 |
+
ptr_t result = 0;
|
| 533 |
+
|
| 534 |
+
GC_ASSERT(I_HOLD_LOCK());
|
| 535 |
+
# ifdef PARALLEL_MARK
|
| 536 |
+
for (i = 0; i < GC_markers; ++i) {
|
| 537 |
+
if (marker_sp[i] > result && marker_sp[i] < bound)
|
| 538 |
+
result = marker_sp[i];
|
| 539 |
+
}
|
| 540 |
+
# endif
|
| 541 |
+
for (i = 0; i < THREAD_TABLE_SZ; i++) {
|
| 542 |
+
for (p = GC_threads[i]; p != 0; p = p -> next) {
|
| 543 |
+
if (p -> stack_end > result && p -> stack_end < bound) {
|
| 544 |
+
result = p -> stack_end;
|
| 545 |
+
}
|
| 546 |
+
}
|
| 547 |
+
}
|
| 548 |
+
return result;
|
| 549 |
+
}
|
| 550 |
+
#endif /* IA64 */
|
| 551 |
+
|
| 552 |
+
#ifdef GC_LINUX_THREADS
|
| 553 |
+
/* Return the number of processors, or i<= 0 if it can't be determined. */
|
| 554 |
+
int GC_get_nprocs(void)
|
| 555 |
+
{
|
| 556 |
+
/* Should be "return sysconf(_SC_NPROCESSORS_ONLN);" but that */
|
| 557 |
+
/* appears to be buggy in many cases. */
|
| 558 |
+
/* We look for lines "cpu<n>" in /proc/stat. */
|
| 559 |
+
# define STAT_BUF_SIZE 4096
|
| 560 |
+
# define STAT_READ read
|
| 561 |
+
/* If read is wrapped, this may need to be redefined to call */
|
| 562 |
+
/* the real one. */
|
| 563 |
+
char stat_buf[STAT_BUF_SIZE];
|
| 564 |
+
int f;
|
| 565 |
+
word result = 1;
|
| 566 |
+
/* Some old kernels only have a single "cpu nnnn ..." */
|
| 567 |
+
/* entry in /proc/stat. We identify those as */
|
| 568 |
+
/* uniprocessors. */
|
| 569 |
+
size_t i, len = 0;
|
| 570 |
+
|
| 571 |
+
f = open("/proc/stat", O_RDONLY);
|
| 572 |
+
if (f < 0 || (len = STAT_READ(f, stat_buf, STAT_BUF_SIZE)) < 100) {
|
| 573 |
+
WARN("Couldn't read /proc/stat\n", 0);
|
| 574 |
+
return -1;
|
| 575 |
+
}
|
| 576 |
+
for (i = 0; i < len - 100; ++i) {
|
| 577 |
+
if (stat_buf[i] == '\n' && stat_buf[i+1] == 'c'
|
| 578 |
+
&& stat_buf[i+2] == 'p' && stat_buf[i+3] == 'u') {
|
| 579 |
+
int cpu_no = atoi(stat_buf + i + 4);
|
| 580 |
+
if (cpu_no >= result) result = cpu_no + 1;
|
| 581 |
+
}
|
| 582 |
+
}
|
| 583 |
+
close(f);
|
| 584 |
+
return result;
|
| 585 |
+
}
|
| 586 |
+
#endif /* GC_LINUX_THREADS */
|
| 587 |
+
|
| 588 |
+
/* We hold the GC lock. Wait until an in-progress GC has finished. */
|
| 589 |
+
/* Repeatedly RELEASES GC LOCK in order to wait. */
|
| 590 |
+
/* If wait_for_all is true, then we exit with the GC lock held and no */
|
| 591 |
+
/* collection in progress; otherwise we just wait for the current GC */
|
| 592 |
+
/* to finish. */
|
| 593 |
+
extern GC_bool GC_collection_in_progress(void);
|
| 594 |
+
void GC_wait_for_gc_completion(GC_bool wait_for_all)
|
| 595 |
+
{
|
| 596 |
+
GC_ASSERT(I_HOLD_LOCK());
|
| 597 |
+
if (GC_incremental && GC_collection_in_progress()) {
|
| 598 |
+
int old_gc_no = GC_gc_no;
|
| 599 |
+
|
| 600 |
+
/* Make sure that no part of our stack is still on the mark stack, */
|
| 601 |
+
/* since it's about to be unmapped. */
|
| 602 |
+
while (GC_incremental && GC_collection_in_progress()
|
| 603 |
+
&& (wait_for_all || old_gc_no == GC_gc_no)) {
|
| 604 |
+
ENTER_GC();
|
| 605 |
+
GC_in_thread_creation = TRUE;
|
| 606 |
+
GC_collect_a_little_inner(1);
|
| 607 |
+
GC_in_thread_creation = FALSE;
|
| 608 |
+
EXIT_GC();
|
| 609 |
+
UNLOCK();
|
| 610 |
+
sched_yield();
|
| 611 |
+
LOCK();
|
| 612 |
+
}
|
| 613 |
+
}
|
| 614 |
+
}
|
| 615 |
+
|
| 616 |
+
#ifdef HANDLE_FORK
|
| 617 |
+
/* Procedures called before and after a fork. The goal here is to make */
|
| 618 |
+
/* it safe to call GC_malloc() in a forked child. It's unclear that is */
|
| 619 |
+
/* attainable, since the single UNIX spec seems to imply that one */
|
| 620 |
+
/* should only call async-signal-safe functions, and we probably can't */
|
| 621 |
+
/* quite guarantee that. But we give it our best shot. (That same */
|
| 622 |
+
/* spec also implies that it's not safe to call the system malloc */
|
| 623 |
+
/* between fork() and exec(). Thus we're doing no worse than it. */
|
| 624 |
+
|
| 625 |
+
/* Called before a fork() */
|
| 626 |
+
void GC_fork_prepare_proc(void)
|
| 627 |
+
{
|
| 628 |
+
/* Acquire all relevant locks, so that after releasing the locks */
|
| 629 |
+
/* the child will see a consistent state in which monitor */
|
| 630 |
+
/* invariants hold. Unfortunately, we can't acquire libc locks */
|
| 631 |
+
/* we might need, and there seems to be no guarantee that libc */
|
| 632 |
+
/* must install a suitable fork handler. */
|
| 633 |
+
/* Wait for an ongoing GC to finish, since we can't finish it in */
|
| 634 |
+
/* the (one remaining thread in) the child. */
|
| 635 |
+
LOCK();
|
| 636 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 637 |
+
GC_wait_for_reclaim();
|
| 638 |
+
# endif
|
| 639 |
+
GC_wait_for_gc_completion(TRUE);
|
| 640 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 641 |
+
GC_acquire_mark_lock();
|
| 642 |
+
# endif
|
| 643 |
+
}
|
| 644 |
+
|
| 645 |
+
/* Called in parent after a fork() */
|
| 646 |
+
void GC_fork_parent_proc(void)
|
| 647 |
+
{
|
| 648 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 649 |
+
GC_release_mark_lock();
|
| 650 |
+
# endif
|
| 651 |
+
UNLOCK();
|
| 652 |
+
}
|
| 653 |
+
|
| 654 |
+
/* Called in child after a fork() */
|
| 655 |
+
void GC_fork_child_proc(void)
|
| 656 |
+
{
|
| 657 |
+
/* Clean up the thread table, so that just our thread is left. */
|
| 658 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 659 |
+
GC_release_mark_lock();
|
| 660 |
+
# endif
|
| 661 |
+
GC_remove_all_threads_but_me();
|
| 662 |
+
# ifdef PARALLEL_MARK
|
| 663 |
+
/* Turn off parallel marking in the child, since we are probably */
|
| 664 |
+
/* just going to exec, and we would have to restart mark threads. */
|
| 665 |
+
GC_markers = 1;
|
| 666 |
+
GC_parallel = FALSE;
|
| 667 |
+
# endif /* PARALLEL_MARK */
|
| 668 |
+
UNLOCK();
|
| 669 |
+
}
|
| 670 |
+
#endif /* HANDLE_FORK */
|
| 671 |
+
|
| 672 |
+
#if defined(GC_DGUX386_THREADS)
|
| 673 |
+
/* Return the number of processors, or i<= 0 if it can't be determined. */
|
| 674 |
+
int GC_get_nprocs(void)
|
| 675 |
+
{
|
| 676 |
+
/* <takis@XFree86.Org> */
|
| 677 |
+
int numCpus;
|
| 678 |
+
struct dg_sys_info_pm_info pm_sysinfo;
|
| 679 |
+
int status =0;
|
| 680 |
+
|
| 681 |
+
status = dg_sys_info((long int *) &pm_sysinfo,
|
| 682 |
+
DG_SYS_INFO_PM_INFO_TYPE, DG_SYS_INFO_PM_CURRENT_VERSION);
|
| 683 |
+
if (status < 0)
|
| 684 |
+
/* set -1 for error */
|
| 685 |
+
numCpus = -1;
|
| 686 |
+
else
|
| 687 |
+
/* Active CPUs */
|
| 688 |
+
numCpus = pm_sysinfo.idle_vp_count;
|
| 689 |
+
|
| 690 |
+
# ifdef DEBUG_THREADS
|
| 691 |
+
GC_printf("Number of active CPUs in this system: %d\n", numCpus);
|
| 692 |
+
# endif
|
| 693 |
+
return(numCpus);
|
| 694 |
+
}
|
| 695 |
+
#endif /* GC_DGUX386_THREADS */
|
| 696 |
+
|
| 697 |
+
#if defined(GC_NETBSD_THREADS)
|
| 698 |
+
static int get_ncpu(void)
|
| 699 |
+
{
|
| 700 |
+
int mib[] = {CTL_HW,HW_NCPU};
|
| 701 |
+
int res;
|
| 702 |
+
size_t len = sizeof(res);
|
| 703 |
+
|
| 704 |
+
sysctl(mib, sizeof(mib)/sizeof(int), &res, &len, NULL, 0);
|
| 705 |
+
return res;
|
| 706 |
+
}
|
| 707 |
+
#endif /* GC_NETBSD_THREADS */
|
| 708 |
+
|
| 709 |
+
# if defined(GC_LINUX_THREADS) && defined(INCLUDE_LINUX_THREAD_DESCR)
|
| 710 |
+
__thread int dummy_thread_local;
|
| 711 |
+
# endif
|
| 712 |
+
|
| 713 |
+
/* We hold the allocation lock. */
|
| 714 |
+
void GC_thr_init(void)
|
| 715 |
+
{
|
| 716 |
+
# ifndef GC_DARWIN_THREADS
|
| 717 |
+
int dummy;
|
| 718 |
+
# endif
|
| 719 |
+
GC_thread t;
|
| 720 |
+
|
| 721 |
+
if (GC_thr_initialized) return;
|
| 722 |
+
GC_thr_initialized = TRUE;
|
| 723 |
+
|
| 724 |
+
# ifdef HANDLE_FORK
|
| 725 |
+
/* Prepare for a possible fork. */
|
| 726 |
+
pthread_atfork(GC_fork_prepare_proc, GC_fork_parent_proc,
|
| 727 |
+
GC_fork_child_proc);
|
| 728 |
+
# endif /* HANDLE_FORK */
|
| 729 |
+
# if defined(INCLUDE_LINUX_THREAD_DESCR)
|
| 730 |
+
/* Explicitly register the region including the address */
|
| 731 |
+
/* of a thread local variable. This should included thread */
|
| 732 |
+
/* locals for the main thread, except for those allocated */
|
| 733 |
+
/* in response to dlopen calls. */
|
| 734 |
+
{
|
| 735 |
+
ptr_t thread_local_addr = (ptr_t)(&dummy_thread_local);
|
| 736 |
+
ptr_t main_thread_start, main_thread_end;
|
| 737 |
+
if (!GC_enclosing_mapping(thread_local_addr, &main_thread_start,
|
| 738 |
+
&main_thread_end)) {
|
| 739 |
+
ABORT("Failed to find mapping for main thread thread locals");
|
| 740 |
+
}
|
| 741 |
+
GC_add_roots_inner(main_thread_start, main_thread_end, FALSE);
|
| 742 |
+
}
|
| 743 |
+
# endif
|
| 744 |
+
/* Add the initial thread, so we can stop it. */
|
| 745 |
+
t = GC_new_thread(pthread_self());
|
| 746 |
+
# ifdef GC_DARWIN_THREADS
|
| 747 |
+
t -> stop_info.mach_thread = mach_thread_self();
|
| 748 |
+
# else
|
| 749 |
+
t -> stop_info.stack_ptr = (ptr_t)(&dummy);
|
| 750 |
+
# endif
|
| 751 |
+
t -> flags = DETACHED | MAIN_THREAD;
|
| 752 |
+
|
| 753 |
+
GC_stop_init();
|
| 754 |
+
|
| 755 |
+
/* Set GC_nprocs. */
|
| 756 |
+
{
|
| 757 |
+
char * nprocs_string = GETENV("GC_NPROCS");
|
| 758 |
+
GC_nprocs = -1;
|
| 759 |
+
if (nprocs_string != NULL) GC_nprocs = atoi(nprocs_string);
|
| 760 |
+
}
|
| 761 |
+
if (GC_nprocs <= 0) {
|
| 762 |
+
# if defined(GC_HPUX_THREADS)
|
| 763 |
+
GC_nprocs = pthread_num_processors_np();
|
| 764 |
+
# endif
|
| 765 |
+
# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) \
|
| 766 |
+
|| defined(GC_SOLARIS_THREADS)
|
| 767 |
+
GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN);
|
| 768 |
+
if (GC_nprocs <= 0) GC_nprocs = 1;
|
| 769 |
+
# endif
|
| 770 |
+
# if defined(GC_IRIX_THREADS)
|
| 771 |
+
GC_nprocs = sysconf(_SC_NPROC_ONLN);
|
| 772 |
+
if (GC_nprocs <= 0) GC_nprocs = 1;
|
| 773 |
+
# endif
|
| 774 |
+
# if defined(GC_NETBSD_THREADS)
|
| 775 |
+
GC_nprocs = get_ncpu();
|
| 776 |
+
# endif
|
| 777 |
+
# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
|
| 778 |
+
int ncpus = 1;
|
| 779 |
+
size_t len = sizeof(ncpus);
|
| 780 |
+
sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
|
| 781 |
+
GC_nprocs = ncpus;
|
| 782 |
+
# endif
|
| 783 |
+
# if defined(GC_LINUX_THREADS) || defined(GC_DGUX386_THREADS)
|
| 784 |
+
GC_nprocs = GC_get_nprocs();
|
| 785 |
+
# endif
|
| 786 |
+
# if defined(GC_GNU_THREADS)
|
| 787 |
+
if (GC_nprocs <= 0) GC_nprocs = 1;
|
| 788 |
+
# endif
|
| 789 |
+
}
|
| 790 |
+
if (GC_nprocs <= 0) {
|
| 791 |
+
WARN("GC_get_nprocs() returned %ld\n", GC_nprocs);
|
| 792 |
+
GC_nprocs = 2;
|
| 793 |
+
# ifdef PARALLEL_MARK
|
| 794 |
+
GC_markers = 1;
|
| 795 |
+
# endif
|
| 796 |
+
} else {
|
| 797 |
+
# ifdef PARALLEL_MARK
|
| 798 |
+
{
|
| 799 |
+
char * markers_string = GETENV("GC_MARKERS");
|
| 800 |
+
if (markers_string != NULL) {
|
| 801 |
+
GC_markers = atoi(markers_string);
|
| 802 |
+
} else {
|
| 803 |
+
GC_markers = GC_nprocs;
|
| 804 |
+
}
|
| 805 |
+
}
|
| 806 |
+
# endif
|
| 807 |
+
}
|
| 808 |
+
# ifdef PARALLEL_MARK
|
| 809 |
+
if (GC_print_stats) {
|
| 810 |
+
GC_log_printf("Number of processors = %ld, "
|
| 811 |
+
"number of marker threads = %ld\n", GC_nprocs, GC_markers);
|
| 812 |
+
}
|
| 813 |
+
if (GC_markers == 1) {
|
| 814 |
+
GC_parallel = FALSE;
|
| 815 |
+
if (GC_print_stats) {
|
| 816 |
+
GC_log_printf(
|
| 817 |
+
"Single marker thread, turning off parallel marking\n");
|
| 818 |
+
}
|
| 819 |
+
} else {
|
| 820 |
+
GC_parallel = TRUE;
|
| 821 |
+
/* Disable true incremental collection, but generational is OK. */
|
| 822 |
+
GC_time_limit = GC_TIME_UNLIMITED;
|
| 823 |
+
}
|
| 824 |
+
/* If we are using a parallel marker, actually start helper threads. */
|
| 825 |
+
if (GC_parallel) start_mark_threads();
|
| 826 |
+
# endif
|
| 827 |
+
}
|
| 828 |
+
|
| 829 |
+
|
| 830 |
+
/* Perform all initializations, including those that */
|
| 831 |
+
/* may require allocation. */
|
| 832 |
+
/* Called without allocation lock. */
|
| 833 |
+
/* Must be called before a second thread is created. */
|
| 834 |
+
/* Did we say it's called without the allocation lock? */
|
| 835 |
+
void GC_init_parallel(void)
|
| 836 |
+
{
|
| 837 |
+
if (parallel_initialized) return;
|
| 838 |
+
parallel_initialized = TRUE;
|
| 839 |
+
|
| 840 |
+
/* GC_init() calls us back, so set flag first. */
|
| 841 |
+
if (!GC_is_initialized) GC_init();
|
| 842 |
+
/* Initialize thread local free lists if used. */
|
| 843 |
+
# if defined(THREAD_LOCAL_ALLOC)
|
| 844 |
+
LOCK();
|
| 845 |
+
GC_init_thread_local(&(GC_lookup_thread(pthread_self())->tlfs));
|
| 846 |
+
UNLOCK();
|
| 847 |
+
# endif
|
| 848 |
+
}
|
| 849 |
+
|
| 850 |
+
|
| 851 |
+
#if !defined(GC_DARWIN_THREADS)
|
| 852 |
+
int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
|
| 853 |
+
{
|
| 854 |
+
sigset_t fudged_set;
|
| 855 |
+
|
| 856 |
+
INIT_REAL_SYMS();
|
| 857 |
+
if (set != NULL && (how == SIG_BLOCK || how == SIG_SETMASK)) {
|
| 858 |
+
fudged_set = *set;
|
| 859 |
+
sigdelset(&fudged_set, SIG_SUSPEND);
|
| 860 |
+
set = &fudged_set;
|
| 861 |
+
}
|
| 862 |
+
return(REAL_FUNC(pthread_sigmask)(how, set, oset));
|
| 863 |
+
}
|
| 864 |
+
#endif /* !GC_DARWIN_THREADS */
|
| 865 |
+
|
| 866 |
+
/* Wrapper for functions that are likely to block for an appreciable */
|
| 867 |
+
/* length of time. */
|
| 868 |
+
|
| 869 |
+
struct blocking_data {
|
| 870 |
+
void (*fn)(void *);
|
| 871 |
+
void *arg;
|
| 872 |
+
};
|
| 873 |
+
|
| 874 |
+
static void GC_do_blocking_inner(ptr_t data, void * context) {
|
| 875 |
+
struct blocking_data * d = (struct blocking_data *) data;
|
| 876 |
+
GC_thread me;
|
| 877 |
+
LOCK();
|
| 878 |
+
me = GC_lookup_thread(pthread_self());
|
| 879 |
+
GC_ASSERT(!(me -> thread_blocked));
|
| 880 |
+
# ifdef SPARC
|
| 881 |
+
me -> stop_info.stack_ptr = GC_save_regs_in_stack();
|
| 882 |
+
# elif !defined(GC_DARWIN_THREADS)
|
| 883 |
+
me -> stop_info.stack_ptr = GC_approx_sp();
|
| 884 |
+
# endif
|
| 885 |
+
# ifdef IA64
|
| 886 |
+
me -> backing_store_ptr = GC_save_regs_in_stack();
|
| 887 |
+
# endif
|
| 888 |
+
me -> thread_blocked = TRUE;
|
| 889 |
+
/* Save context here if we want to support precise stack marking */
|
| 890 |
+
UNLOCK();
|
| 891 |
+
(d -> fn)(d -> arg);
|
| 892 |
+
LOCK(); /* This will block if the world is stopped. */
|
| 893 |
+
me -> thread_blocked = FALSE;
|
| 894 |
+
UNLOCK();
|
| 895 |
+
}
|
| 896 |
+
|
| 897 |
+
void GC_do_blocking(void (*fn)(void *), void *arg) {
|
| 898 |
+
struct blocking_data my_data;
|
| 899 |
+
|
| 900 |
+
my_data.fn = fn;
|
| 901 |
+
my_data.arg = arg;
|
| 902 |
+
GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
|
| 903 |
+
}
|
| 904 |
+
|
| 905 |
+
struct start_info {
|
| 906 |
+
void *(*start_routine)(void *);
|
| 907 |
+
void *arg;
|
| 908 |
+
word flags;
|
| 909 |
+
sem_t registered; /* 1 ==> in our thread table, but */
|
| 910 |
+
/* parent hasn't yet noticed. */
|
| 911 |
+
};
|
| 912 |
+
|
| 913 |
+
int GC_unregister_my_thread(void)
|
| 914 |
+
{
|
| 915 |
+
GC_thread me;
|
| 916 |
+
|
| 917 |
+
LOCK();
|
| 918 |
+
/* Wait for any GC that may be marking from our stack to */
|
| 919 |
+
/* complete before we remove this thread. */
|
| 920 |
+
GC_wait_for_gc_completion(FALSE);
|
| 921 |
+
me = GC_lookup_thread(pthread_self());
|
| 922 |
+
# if defined(THREAD_LOCAL_ALLOC)
|
| 923 |
+
GC_destroy_thread_local(&(me->tlfs));
|
| 924 |
+
# endif
|
| 925 |
+
if (me -> flags & DETACHED) {
|
| 926 |
+
GC_delete_thread(pthread_self());
|
| 927 |
+
} else {
|
| 928 |
+
me -> flags |= FINISHED;
|
| 929 |
+
}
|
| 930 |
+
# if defined(THREAD_LOCAL_ALLOC)
|
| 931 |
+
GC_remove_specific(GC_thread_key);
|
| 932 |
+
# endif
|
| 933 |
+
UNLOCK();
|
| 934 |
+
return GC_SUCCESS;
|
| 935 |
+
}
|
| 936 |
+
|
| 937 |
+
/* Called at thread exit. */
|
| 938 |
+
/* Never called for main thread. That's OK, since it */
|
| 939 |
+
/* results in at most a tiny one-time leak. And */
|
| 940 |
+
/* linuxthreads doesn't reclaim the main threads */
|
| 941 |
+
/* resources or id anyway. */
|
| 942 |
+
void GC_thread_exit_proc(void *arg)
|
| 943 |
+
{
|
| 944 |
+
GC_unregister_my_thread();
|
| 945 |
+
}
|
| 946 |
+
|
| 947 |
+
int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
|
| 948 |
+
{
|
| 949 |
+
int result;
|
| 950 |
+
GC_thread thread_gc_id;
|
| 951 |
+
|
| 952 |
+
INIT_REAL_SYMS();
|
| 953 |
+
LOCK();
|
| 954 |
+
thread_gc_id = GC_lookup_thread(thread);
|
| 955 |
+
/* This is guaranteed to be the intended one, since the thread id */
|
| 956 |
+
/* cant have been recycled by pthreads. */
|
| 957 |
+
UNLOCK();
|
| 958 |
+
result = REAL_FUNC(pthread_join)(thread, retval);
|
| 959 |
+
# if defined (GC_FREEBSD_THREADS)
|
| 960 |
+
/* On FreeBSD, the wrapped pthread_join() sometimes returns (what
|
| 961 |
+
appears to be) a spurious EINTR which caused the test and real code
|
| 962 |
+
to gratuitously fail. Having looked at system pthread library source
|
| 963 |
+
code, I see how this return code may be generated. In one path of
|
| 964 |
+
code, pthread_join() just returns the errno setting of the thread
|
| 965 |
+
being joined. This does not match the POSIX specification or the
|
| 966 |
+
local man pages thus I have taken the liberty to catch this one
|
| 967 |
+
spurious return value properly conditionalized on GC_FREEBSD_THREADS. */
|
| 968 |
+
if (result == EINTR) result = 0;
|
| 969 |
+
# endif
|
| 970 |
+
if (result == 0) {
|
| 971 |
+
LOCK();
|
| 972 |
+
/* Here the pthread thread id may have been recycled. */
|
| 973 |
+
GC_delete_gc_thread(thread_gc_id);
|
| 974 |
+
UNLOCK();
|
| 975 |
+
}
|
| 976 |
+
return result;
|
| 977 |
+
}
|
| 978 |
+
|
| 979 |
+
int
|
| 980 |
+
WRAP_FUNC(pthread_detach)(pthread_t thread)
|
| 981 |
+
{
|
| 982 |
+
int result;
|
| 983 |
+
GC_thread thread_gc_id;
|
| 984 |
+
|
| 985 |
+
INIT_REAL_SYMS();
|
| 986 |
+
LOCK();
|
| 987 |
+
thread_gc_id = GC_lookup_thread(thread);
|
| 988 |
+
UNLOCK();
|
| 989 |
+
result = REAL_FUNC(pthread_detach)(thread);
|
| 990 |
+
if (result == 0) {
|
| 991 |
+
LOCK();
|
| 992 |
+
thread_gc_id -> flags |= DETACHED;
|
| 993 |
+
/* Here the pthread thread id may have been recycled. */
|
| 994 |
+
if (thread_gc_id -> flags & FINISHED) {
|
| 995 |
+
GC_delete_gc_thread(thread_gc_id);
|
| 996 |
+
}
|
| 997 |
+
UNLOCK();
|
| 998 |
+
}
|
| 999 |
+
return result;
|
| 1000 |
+
}
|
| 1001 |
+
|
| 1002 |
+
GC_bool GC_in_thread_creation = FALSE; /* Protected by allocation lock. */
|
| 1003 |
+
|
| 1004 |
+
GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb,
|
| 1005 |
+
pthread_t my_pthread)
|
| 1006 |
+
{
|
| 1007 |
+
GC_thread me;
|
| 1008 |
+
|
| 1009 |
+
GC_in_thread_creation = TRUE; /* OK to collect from unknown thread. */
|
| 1010 |
+
me = GC_new_thread(my_pthread);
|
| 1011 |
+
GC_in_thread_creation = FALSE;
|
| 1012 |
+
# ifdef GC_DARWIN_THREADS
|
| 1013 |
+
me -> stop_info.mach_thread = mach_thread_self();
|
| 1014 |
+
# else
|
| 1015 |
+
me -> stop_info.stack_ptr = sb -> mem_base;
|
| 1016 |
+
# endif
|
| 1017 |
+
me -> stack_end = sb -> mem_base;
|
| 1018 |
+
# ifdef IA64
|
| 1019 |
+
me -> backing_store_end = sb -> reg_base;
|
| 1020 |
+
# endif /* IA64 */
|
| 1021 |
+
return me;
|
| 1022 |
+
}
|
| 1023 |
+
|
| 1024 |
+
int GC_register_my_thread(struct GC_stack_base *sb)
|
| 1025 |
+
{
|
| 1026 |
+
pthread_t my_pthread = pthread_self();
|
| 1027 |
+
GC_thread me;
|
| 1028 |
+
|
| 1029 |
+
LOCK();
|
| 1030 |
+
me = GC_lookup_thread(my_pthread);
|
| 1031 |
+
if (0 == me) {
|
| 1032 |
+
me = GC_register_my_thread_inner(sb, my_pthread);
|
| 1033 |
+
me -> flags |= DETACHED;
|
| 1034 |
+
/* Treat as detached, since we do not need to worry about */
|
| 1035 |
+
/* pointer results. */
|
| 1036 |
+
UNLOCK();
|
| 1037 |
+
return GC_SUCCESS;
|
| 1038 |
+
} else {
|
| 1039 |
+
UNLOCK();
|
| 1040 |
+
return GC_DUPLICATE;
|
| 1041 |
+
}
|
| 1042 |
+
}
|
| 1043 |
+
|
| 1044 |
+
void * GC_inner_start_routine(struct GC_stack_base *sb, void * arg)
|
| 1045 |
+
{
|
| 1046 |
+
struct start_info * si = arg;
|
| 1047 |
+
void * result;
|
| 1048 |
+
GC_thread me;
|
| 1049 |
+
pthread_t my_pthread;
|
| 1050 |
+
void *(*start)(void *);
|
| 1051 |
+
void *start_arg;
|
| 1052 |
+
|
| 1053 |
+
my_pthread = pthread_self();
|
| 1054 |
+
# ifdef DEBUG_THREADS
|
| 1055 |
+
GC_printf("Starting thread 0x%x\n", (unsigned)my_pthread);
|
| 1056 |
+
GC_printf("pid = %ld\n", (long) getpid());
|
| 1057 |
+
GC_printf("sp = 0x%lx\n", (long) &arg);
|
| 1058 |
+
# endif
|
| 1059 |
+
LOCK();
|
| 1060 |
+
me = GC_register_my_thread_inner(sb, my_pthread);
|
| 1061 |
+
me -> flags = si -> flags;
|
| 1062 |
+
UNLOCK();
|
| 1063 |
+
start = si -> start_routine;
|
| 1064 |
+
# ifdef DEBUG_THREADS
|
| 1065 |
+
GC_printf("start_routine = %p\n", (void *)start);
|
| 1066 |
+
# endif
|
| 1067 |
+
start_arg = si -> arg;
|
| 1068 |
+
sem_post(&(si -> registered)); /* Last action on si. */
|
| 1069 |
+
/* OK to deallocate. */
|
| 1070 |
+
pthread_cleanup_push(GC_thread_exit_proc, 0);
|
| 1071 |
+
# if defined(THREAD_LOCAL_ALLOC)
|
| 1072 |
+
LOCK();
|
| 1073 |
+
GC_init_thread_local(&(me->tlfs));
|
| 1074 |
+
UNLOCK();
|
| 1075 |
+
# endif
|
| 1076 |
+
result = (*start)(start_arg);
|
| 1077 |
+
# if DEBUG_THREADS
|
| 1078 |
+
GC_printf("Finishing thread 0x%x\n", (unsigned)pthread_self());
|
| 1079 |
+
# endif
|
| 1080 |
+
me -> status = result;
|
| 1081 |
+
pthread_cleanup_pop(1);
|
| 1082 |
+
/* Cleanup acquires lock, ensuring that we can't exit */
|
| 1083 |
+
/* while a collection that thinks we're alive is trying to stop */
|
| 1084 |
+
/* us. */
|
| 1085 |
+
return(result);
|
| 1086 |
+
}
|
| 1087 |
+
|
| 1088 |
+
void * GC_start_routine(void * arg)
|
| 1089 |
+
{
|
| 1090 |
+
# ifdef INCLUDE_LINUX_THREAD_DESCR
|
| 1091 |
+
struct GC_stack_base sb;
|
| 1092 |
+
|
| 1093 |
+
# ifdef REDIRECT_MALLOC
|
| 1094 |
+
/* GC_get_stack_base may call pthread_getattr_np, which can */
|
| 1095 |
+
/* unfortunately call realloc, which may allocate from an */
|
| 1096 |
+
/* unregistered thread. This is unpleasant, since it might */
|
| 1097 |
+
/* force heap growth. */
|
| 1098 |
+
GC_disable();
|
| 1099 |
+
# endif
|
| 1100 |
+
if (GC_get_stack_base(&sb) != GC_SUCCESS)
|
| 1101 |
+
ABORT("Failed to get thread stack base.");
|
| 1102 |
+
# ifdef REDIRECT_MALLOC
|
| 1103 |
+
GC_enable();
|
| 1104 |
+
# endif
|
| 1105 |
+
return GC_inner_start_routine(&sb, arg);
|
| 1106 |
+
# else
|
| 1107 |
+
return GC_call_with_stack_base(GC_inner_start_routine, arg);
|
| 1108 |
+
# endif
|
| 1109 |
+
}
|
| 1110 |
+
|
| 1111 |
+
int
|
| 1112 |
+
WRAP_FUNC(pthread_create)(pthread_t *new_thread,
|
| 1113 |
+
const pthread_attr_t *attr,
|
| 1114 |
+
void *(*start_routine)(void *), void *arg)
|
| 1115 |
+
{
|
| 1116 |
+
int result;
|
| 1117 |
+
int detachstate;
|
| 1118 |
+
word my_flags = 0;
|
| 1119 |
+
struct start_info * si;
|
| 1120 |
+
/* This is otherwise saved only in an area mmapped by the thread */
|
| 1121 |
+
/* library, which isn't visible to the collector. */
|
| 1122 |
+
|
| 1123 |
+
/* We resist the temptation to muck with the stack size here, */
|
| 1124 |
+
/* even if the default is unreasonably small. That's the client's */
|
| 1125 |
+
/* responsibility. */
|
| 1126 |
+
|
| 1127 |
+
INIT_REAL_SYMS();
|
| 1128 |
+
LOCK();
|
| 1129 |
+
si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
|
| 1130 |
+
NORMAL);
|
| 1131 |
+
UNLOCK();
|
| 1132 |
+
if (!parallel_initialized) GC_init_parallel();
|
| 1133 |
+
if (0 == si) return(ENOMEM);
|
| 1134 |
+
sem_init(&(si -> registered), 0, 0);
|
| 1135 |
+
si -> start_routine = start_routine;
|
| 1136 |
+
si -> arg = arg;
|
| 1137 |
+
LOCK();
|
| 1138 |
+
if (!GC_thr_initialized) GC_thr_init();
|
| 1139 |
+
# ifdef GC_ASSERTIONS
|
| 1140 |
+
{
|
| 1141 |
+
size_t stack_size = 0;
|
| 1142 |
+
if (NULL != attr) {
|
| 1143 |
+
pthread_attr_getstacksize(attr, &stack_size);
|
| 1144 |
+
}
|
| 1145 |
+
if (0 == stack_size) {
|
| 1146 |
+
pthread_attr_t my_attr;
|
| 1147 |
+
pthread_attr_init(&my_attr);
|
| 1148 |
+
pthread_attr_getstacksize(&my_attr, &stack_size);
|
| 1149 |
+
}
|
| 1150 |
+
/* On Solaris 10, with default attr initialization, */
|
| 1151 |
+
/* stack_size remains 0. Fudge it. */
|
| 1152 |
+
if (0 == stack_size) {
|
| 1153 |
+
# ifndef SOLARIS
|
| 1154 |
+
WARN("Failed to get stack size for assertion checking\n", 0);
|
| 1155 |
+
# endif
|
| 1156 |
+
stack_size = 1000000;
|
| 1157 |
+
}
|
| 1158 |
+
# ifdef PARALLEL_MARK
|
| 1159 |
+
GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word)));
|
| 1160 |
+
# else
|
| 1161 |
+
/* FreeBSD-5.3/Alpha: default pthread stack is 64K, */
|
| 1162 |
+
/* HBLKSIZE=8192, sizeof(word)=8 */
|
| 1163 |
+
GC_ASSERT(stack_size >= 65536);
|
| 1164 |
+
# endif
|
| 1165 |
+
/* Our threads may need to do some work for the GC. */
|
| 1166 |
+
/* Ridiculously small threads won't work, and they */
|
| 1167 |
+
/* probably wouldn't work anyway. */
|
| 1168 |
+
}
|
| 1169 |
+
# endif
|
| 1170 |
+
if (NULL == attr) {
|
| 1171 |
+
detachstate = PTHREAD_CREATE_JOINABLE;
|
| 1172 |
+
} else {
|
| 1173 |
+
pthread_attr_getdetachstate(attr, &detachstate);
|
| 1174 |
+
}
|
| 1175 |
+
if (PTHREAD_CREATE_DETACHED == detachstate) my_flags |= DETACHED;
|
| 1176 |
+
si -> flags = my_flags;
|
| 1177 |
+
UNLOCK();
|
| 1178 |
+
# ifdef DEBUG_THREADS
|
| 1179 |
+
GC_printf("About to start new thread from thread 0x%x\n",
|
| 1180 |
+
(unsigned)pthread_self());
|
| 1181 |
+
# endif
|
| 1182 |
+
GC_need_to_lock = TRUE;
|
| 1183 |
+
|
| 1184 |
+
result = REAL_FUNC(pthread_create)(new_thread, attr, GC_start_routine, si);
|
| 1185 |
+
|
| 1186 |
+
# ifdef DEBUG_THREADS
|
| 1187 |
+
GC_printf("Started thread 0x%x\n", (unsigned)(*new_thread));
|
| 1188 |
+
# endif
|
| 1189 |
+
/* Wait until child has been added to the thread table. */
|
| 1190 |
+
/* This also ensures that we hold onto si until the child is done */
|
| 1191 |
+
/* with it. Thus it doesn't matter whether it is otherwise */
|
| 1192 |
+
/* visible to the collector. */
|
| 1193 |
+
if (0 == result) {
|
| 1194 |
+
while (0 != sem_wait(&(si -> registered))) {
|
| 1195 |
+
if (EINTR != errno) ABORT("sem_wait failed");
|
| 1196 |
+
}
|
| 1197 |
+
}
|
| 1198 |
+
sem_destroy(&(si -> registered));
|
| 1199 |
+
LOCK();
|
| 1200 |
+
GC_INTERNAL_FREE(si);
|
| 1201 |
+
UNLOCK();
|
| 1202 |
+
|
| 1203 |
+
return(result);
|
| 1204 |
+
}
|
| 1205 |
+
|
| 1206 |
+
/* Spend a few cycles in a way that can't introduce contention with */
|
| 1207 |
+
/* othre threads. */
|
| 1208 |
+
void GC_pause(void)
|
| 1209 |
+
{
|
| 1210 |
+
int i;
|
| 1211 |
+
# if !defined(__GNUC__) || defined(__INTEL_COMPILER)
|
| 1212 |
+
volatile word dummy = 0;
|
| 1213 |
+
# endif
|
| 1214 |
+
|
| 1215 |
+
for (i = 0; i < 10; ++i) {
|
| 1216 |
+
# if defined(__GNUC__) && !defined(__INTEL_COMPILER)
|
| 1217 |
+
__asm__ __volatile__ (" " : : : "memory");
|
| 1218 |
+
# else
|
| 1219 |
+
/* Something that's unlikely to be optimized away. */
|
| 1220 |
+
GC_noop(++dummy);
|
| 1221 |
+
# endif
|
| 1222 |
+
}
|
| 1223 |
+
}
|
| 1224 |
+
|
| 1225 |
+
#define SPIN_MAX 128 /* Maximum number of calls to GC_pause before */
|
| 1226 |
+
/* give up. */
|
| 1227 |
+
|
| 1228 |
+
volatile GC_bool GC_collecting = 0;
|
| 1229 |
+
/* A hint that we're in the collector and */
|
| 1230 |
+
/* holding the allocation lock for an */
|
| 1231 |
+
/* extended period. */
|
| 1232 |
+
|
| 1233 |
+
#if !defined(USE_SPIN_LOCK) || defined(PARALLEL_MARK)
|
| 1234 |
+
/* If we don't want to use the below spinlock implementation, either */
|
| 1235 |
+
/* because we don't have a GC_test_and_set implementation, or because */
|
| 1236 |
+
/* we don't want to risk sleeping, we can still try spinning on */
|
| 1237 |
+
/* pthread_mutex_trylock for a while. This appears to be very */
|
| 1238 |
+
/* beneficial in many cases. */
|
| 1239 |
+
/* I suspect that under high contention this is nearly always better */
|
| 1240 |
+
/* than the spin lock. But it's a bit slower on a uniprocessor. */
|
| 1241 |
+
/* Hence we still default to the spin lock. */
|
| 1242 |
+
/* This is also used to acquire the mark lock for the parallel */
|
| 1243 |
+
/* marker. */
|
| 1244 |
+
|
| 1245 |
+
/* Here we use a strict exponential backoff scheme. I don't know */
|
| 1246 |
+
/* whether that's better or worse than the above. We eventually */
|
| 1247 |
+
/* yield by calling pthread_mutex_lock(); it never makes sense to */
|
| 1248 |
+
/* explicitly sleep. */
|
| 1249 |
+
|
| 1250 |
+
#define LOCK_STATS
|
| 1251 |
+
#ifdef LOCK_STATS
|
| 1252 |
+
unsigned long GC_spin_count = 0;
|
| 1253 |
+
unsigned long GC_block_count = 0;
|
| 1254 |
+
unsigned long GC_unlocked_count = 0;
|
| 1255 |
+
#endif
|
| 1256 |
+
|
| 1257 |
+
void GC_generic_lock(pthread_mutex_t * lock)
|
| 1258 |
+
{
|
| 1259 |
+
#ifndef NO_PTHREAD_TRYLOCK
|
| 1260 |
+
unsigned pause_length = 1;
|
| 1261 |
+
unsigned i;
|
| 1262 |
+
|
| 1263 |
+
if (0 == pthread_mutex_trylock(lock)) {
|
| 1264 |
+
# ifdef LOCK_STATS
|
| 1265 |
+
++GC_unlocked_count;
|
| 1266 |
+
# endif
|
| 1267 |
+
return;
|
| 1268 |
+
}
|
| 1269 |
+
for (; pause_length <= SPIN_MAX; pause_length <<= 1) {
|
| 1270 |
+
for (i = 0; i < pause_length; ++i) {
|
| 1271 |
+
GC_pause();
|
| 1272 |
+
}
|
| 1273 |
+
switch(pthread_mutex_trylock(lock)) {
|
| 1274 |
+
case 0:
|
| 1275 |
+
# ifdef LOCK_STATS
|
| 1276 |
+
++GC_spin_count;
|
| 1277 |
+
# endif
|
| 1278 |
+
return;
|
| 1279 |
+
case EBUSY:
|
| 1280 |
+
break;
|
| 1281 |
+
default:
|
| 1282 |
+
ABORT("Unexpected error from pthread_mutex_trylock");
|
| 1283 |
+
}
|
| 1284 |
+
}
|
| 1285 |
+
#endif /* !NO_PTHREAD_TRYLOCK */
|
| 1286 |
+
# ifdef LOCK_STATS
|
| 1287 |
+
++GC_block_count;
|
| 1288 |
+
# endif
|
| 1289 |
+
pthread_mutex_lock(lock);
|
| 1290 |
+
}
|
| 1291 |
+
|
| 1292 |
+
#endif /* !USE_SPIN_LOCK || PARALLEL_MARK */
|
| 1293 |
+
|
| 1294 |
+
#if defined(USE_SPIN_LOCK)
|
| 1295 |
+
|
| 1296 |
+
/* Reasonably fast spin locks. Basically the same implementation */
|
| 1297 |
+
/* as STL alloc.h. This isn't really the right way to do this. */
|
| 1298 |
+
/* but until the POSIX scheduling mess gets straightened out ... */
|
| 1299 |
+
|
| 1300 |
+
volatile AO_TS_t GC_allocate_lock = 0;
|
| 1301 |
+
|
| 1302 |
+
|
| 1303 |
+
void GC_lock(void)
|
| 1304 |
+
{
|
| 1305 |
+
# define low_spin_max 30 /* spin cycles if we suspect uniprocessor */
|
| 1306 |
+
# define high_spin_max SPIN_MAX /* spin cycles for multiprocessor */
|
| 1307 |
+
static unsigned spin_max = low_spin_max;
|
| 1308 |
+
unsigned my_spin_max;
|
| 1309 |
+
static unsigned last_spins = 0;
|
| 1310 |
+
unsigned my_last_spins;
|
| 1311 |
+
int i;
|
| 1312 |
+
|
| 1313 |
+
if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
|
| 1314 |
+
return;
|
| 1315 |
+
}
|
| 1316 |
+
my_spin_max = spin_max;
|
| 1317 |
+
my_last_spins = last_spins;
|
| 1318 |
+
for (i = 0; i < my_spin_max; i++) {
|
| 1319 |
+
if (GC_collecting || GC_nprocs == 1) goto yield;
|
| 1320 |
+
if (i < my_last_spins/2) {
|
| 1321 |
+
GC_pause();
|
| 1322 |
+
continue;
|
| 1323 |
+
}
|
| 1324 |
+
if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
|
| 1325 |
+
/*
|
| 1326 |
+
* got it!
|
| 1327 |
+
* Spinning worked. Thus we're probably not being scheduled
|
| 1328 |
+
* against the other process with which we were contending.
|
| 1329 |
+
* Thus it makes sense to spin longer the next time.
|
| 1330 |
+
*/
|
| 1331 |
+
last_spins = i;
|
| 1332 |
+
spin_max = high_spin_max;
|
| 1333 |
+
return;
|
| 1334 |
+
}
|
| 1335 |
+
}
|
| 1336 |
+
/* We are probably being scheduled against the other process. Sleep. */
|
| 1337 |
+
spin_max = low_spin_max;
|
| 1338 |
+
yield:
|
| 1339 |
+
for (i = 0;; ++i) {
|
| 1340 |
+
if (AO_test_and_set_acquire(&GC_allocate_lock) == AO_TS_CLEAR) {
|
| 1341 |
+
return;
|
| 1342 |
+
}
|
| 1343 |
+
# define SLEEP_THRESHOLD 12
|
| 1344 |
+
/* Under Linux very short sleeps tend to wait until */
|
| 1345 |
+
/* the current time quantum expires. On old Linux */
|
| 1346 |
+
/* kernels nanosleep(<= 2ms) just spins under Linux. */
|
| 1347 |
+
/* (Under 2.4, this happens only for real-time */
|
| 1348 |
+
/* processes.) We want to minimize both behaviors */
|
| 1349 |
+
/* here. */
|
| 1350 |
+
if (i < SLEEP_THRESHOLD) {
|
| 1351 |
+
sched_yield();
|
| 1352 |
+
} else {
|
| 1353 |
+
struct timespec ts;
|
| 1354 |
+
|
| 1355 |
+
if (i > 24) i = 24;
|
| 1356 |
+
/* Don't wait for more than about 15msecs, even */
|
| 1357 |
+
/* under extreme contention. */
|
| 1358 |
+
ts.tv_sec = 0;
|
| 1359 |
+
ts.tv_nsec = 1 << i;
|
| 1360 |
+
nanosleep(&ts, 0);
|
| 1361 |
+
}
|
| 1362 |
+
}
|
| 1363 |
+
}
|
| 1364 |
+
|
| 1365 |
+
#else /* !USE_SPINLOCK */
|
| 1366 |
+
void GC_lock(void)
|
| 1367 |
+
{
|
| 1368 |
+
#ifndef NO_PTHREAD_TRYLOCK
|
| 1369 |
+
if (1 == GC_nprocs || GC_collecting) {
|
| 1370 |
+
pthread_mutex_lock(&GC_allocate_ml);
|
| 1371 |
+
} else {
|
| 1372 |
+
GC_generic_lock(&GC_allocate_ml);
|
| 1373 |
+
}
|
| 1374 |
+
#else /* !NO_PTHREAD_TRYLOCK */
|
| 1375 |
+
pthread_mutex_lock(&GC_allocate_ml);
|
| 1376 |
+
#endif /* !NO_PTHREAD_TRYLOCK */
|
| 1377 |
+
}
|
| 1378 |
+
|
| 1379 |
+
#endif /* !USE_SPINLOCK */
|
| 1380 |
+
|
| 1381 |
+
#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 1382 |
+
|
| 1383 |
+
#ifdef GC_ASSERTIONS
|
| 1384 |
+
unsigned long GC_mark_lock_holder = NO_THREAD;
|
| 1385 |
+
#endif
|
| 1386 |
+
|
| 1387 |
+
#if 0
|
| 1388 |
+
/* Ugly workaround for a linux threads bug in the final versions */
|
| 1389 |
+
/* of glibc2.1. Pthread_mutex_trylock sets the mutex owner */
|
| 1390 |
+
/* field even when it fails to acquire the mutex. This causes */
|
| 1391 |
+
/* pthread_cond_wait to die. Remove for glibc2.2. */
|
| 1392 |
+
/* According to the man page, we should use */
|
| 1393 |
+
/* PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP, but that isn't actually */
|
| 1394 |
+
/* defined. */
|
| 1395 |
+
static pthread_mutex_t mark_mutex =
|
| 1396 |
+
{0, 0, 0, PTHREAD_MUTEX_ERRORCHECK_NP, {0, 0}};
|
| 1397 |
+
#else
|
| 1398 |
+
static pthread_mutex_t mark_mutex = PTHREAD_MUTEX_INITIALIZER;
|
| 1399 |
+
#endif
|
| 1400 |
+
|
| 1401 |
+
static pthread_cond_t builder_cv = PTHREAD_COND_INITIALIZER;
|
| 1402 |
+
|
| 1403 |
+
void GC_acquire_mark_lock(void)
|
| 1404 |
+
{
|
| 1405 |
+
/*
|
| 1406 |
+
if (pthread_mutex_lock(&mark_mutex) != 0) {
|
| 1407 |
+
ABORT("pthread_mutex_lock failed");
|
| 1408 |
+
}
|
| 1409 |
+
*/
|
| 1410 |
+
GC_generic_lock(&mark_mutex);
|
| 1411 |
+
# ifdef GC_ASSERTIONS
|
| 1412 |
+
GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
|
| 1413 |
+
# endif
|
| 1414 |
+
}
|
| 1415 |
+
|
| 1416 |
+
void GC_release_mark_lock(void)
|
| 1417 |
+
{
|
| 1418 |
+
GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
|
| 1419 |
+
# ifdef GC_ASSERTIONS
|
| 1420 |
+
GC_mark_lock_holder = NO_THREAD;
|
| 1421 |
+
# endif
|
| 1422 |
+
if (pthread_mutex_unlock(&mark_mutex) != 0) {
|
| 1423 |
+
ABORT("pthread_mutex_unlock failed");
|
| 1424 |
+
}
|
| 1425 |
+
}
|
| 1426 |
+
|
| 1427 |
+
/* Collector must wait for a freelist builders for 2 reasons: */
|
| 1428 |
+
/* 1) Mark bits may still be getting examined without lock. */
|
| 1429 |
+
/* 2) Partial free lists referenced only by locals may not be scanned */
|
| 1430 |
+
/* correctly, e.g. if they contain "pointer-free" objects, since the */
|
| 1431 |
+
/* free-list link may be ignored. */
|
| 1432 |
+
void GC_wait_builder(void)
|
| 1433 |
+
{
|
| 1434 |
+
GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
|
| 1435 |
+
# ifdef GC_ASSERTIONS
|
| 1436 |
+
GC_mark_lock_holder = NO_THREAD;
|
| 1437 |
+
# endif
|
| 1438 |
+
if (pthread_cond_wait(&builder_cv, &mark_mutex) != 0) {
|
| 1439 |
+
ABORT("pthread_cond_wait failed");
|
| 1440 |
+
}
|
| 1441 |
+
GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
|
| 1442 |
+
# ifdef GC_ASSERTIONS
|
| 1443 |
+
GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
|
| 1444 |
+
# endif
|
| 1445 |
+
}
|
| 1446 |
+
|
| 1447 |
+
void GC_wait_for_reclaim(void)
|
| 1448 |
+
{
|
| 1449 |
+
GC_acquire_mark_lock();
|
| 1450 |
+
while (GC_fl_builder_count > 0) {
|
| 1451 |
+
GC_wait_builder();
|
| 1452 |
+
}
|
| 1453 |
+
GC_release_mark_lock();
|
| 1454 |
+
}
|
| 1455 |
+
|
| 1456 |
+
void GC_notify_all_builder(void)
|
| 1457 |
+
{
|
| 1458 |
+
GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
|
| 1459 |
+
if (pthread_cond_broadcast(&builder_cv) != 0) {
|
| 1460 |
+
ABORT("pthread_cond_broadcast failed");
|
| 1461 |
+
}
|
| 1462 |
+
}
|
| 1463 |
+
|
| 1464 |
+
#endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
|
| 1465 |
+
|
| 1466 |
+
#ifdef PARALLEL_MARK
|
| 1467 |
+
|
| 1468 |
+
static pthread_cond_t mark_cv = PTHREAD_COND_INITIALIZER;
|
| 1469 |
+
|
| 1470 |
+
void GC_wait_marker(void)
|
| 1471 |
+
{
|
| 1472 |
+
GC_ASSERT(GC_mark_lock_holder == NUMERIC_THREAD_ID(pthread_self()));
|
| 1473 |
+
# ifdef GC_ASSERTIONS
|
| 1474 |
+
GC_mark_lock_holder = NO_THREAD;
|
| 1475 |
+
# endif
|
| 1476 |
+
if (pthread_cond_wait(&mark_cv, &mark_mutex) != 0) {
|
| 1477 |
+
ABORT("pthread_cond_wait failed");
|
| 1478 |
+
}
|
| 1479 |
+
GC_ASSERT(GC_mark_lock_holder == NO_THREAD);
|
| 1480 |
+
# ifdef GC_ASSERTIONS
|
| 1481 |
+
GC_mark_lock_holder = NUMERIC_THREAD_ID(pthread_self());
|
| 1482 |
+
# endif
|
| 1483 |
+
}
|
| 1484 |
+
|
| 1485 |
+
void GC_notify_all_marker(void)
|
| 1486 |
+
{
|
| 1487 |
+
if (pthread_cond_broadcast(&mark_cv) != 0) {
|
| 1488 |
+
ABORT("pthread_cond_broadcast failed");
|
| 1489 |
+
}
|
| 1490 |
+
}
|
| 1491 |
+
|
| 1492 |
+
#endif /* PARALLEL_MARK */
|
| 1493 |
+
|
| 1494 |
+
# endif /* GC_LINUX_THREADS and friends */
|
| 1495 |
+
|
mosesdecoder/jam-files/engine/boehm_gc/reclaim.c
ADDED
|
@@ -0,0 +1,608 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/*
|
| 2 |
+
* Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
|
| 3 |
+
* Copyright (c) 1991-1996 by Xerox Corporation. All rights reserved.
|
| 4 |
+
* Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
|
| 5 |
+
* Copyright (c) 1999-2004 Hewlett-Packard Development Company, L.P.
|
| 6 |
+
*
|
| 7 |
+
* THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
|
| 8 |
+
* OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
|
| 9 |
+
*
|
| 10 |
+
* Permission is hereby granted to use or copy this program
|
| 11 |
+
* for any purpose, provided the above notices are retained on all copies.
|
| 12 |
+
* Permission to modify the code and to distribute modified code is granted,
|
| 13 |
+
* provided the above notices are retained, and a notice that the code was
|
| 14 |
+
* modified is included with the above copyright notice.
|
| 15 |
+
*/
|
| 16 |
+
|
| 17 |
+
#include <stdio.h>
|
| 18 |
+
#include "private/gc_priv.h"
|
| 19 |
+
|
| 20 |
+
signed_word GC_bytes_found = 0;
|
| 21 |
+
/* Number of bytes of memory reclaimed */
|
| 22 |
+
|
| 23 |
+
#if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 24 |
+
word GC_fl_builder_count = 0;
|
| 25 |
+
/* Number of threads currently building free lists without */
|
| 26 |
+
/* holding GC lock. It is not safe to collect if this is */
|
| 27 |
+
/* nonzero. */
|
| 28 |
+
#endif /* PARALLEL_MARK */
|
| 29 |
+
|
| 30 |
+
/* We defer printing of leaked objects until we're done with the GC */
|
| 31 |
+
/* cycle, since the routine for printing objects needs to run outside */
|
| 32 |
+
/* the collector, e.g. without the allocation lock. */
|
| 33 |
+
#define MAX_LEAKED 40
|
| 34 |
+
ptr_t GC_leaked[MAX_LEAKED];
|
| 35 |
+
unsigned GC_n_leaked = 0;
|
| 36 |
+
|
| 37 |
+
GC_bool GC_have_errors = FALSE;
|
| 38 |
+
|
| 39 |
+
void GC_add_leaked(ptr_t leaked)
|
| 40 |
+
{
|
| 41 |
+
if (GC_n_leaked < MAX_LEAKED) {
|
| 42 |
+
GC_have_errors = TRUE;
|
| 43 |
+
GC_leaked[GC_n_leaked++] = leaked;
|
| 44 |
+
/* Make sure it's not reclaimed this cycle */
|
| 45 |
+
GC_set_mark_bit(leaked);
|
| 46 |
+
}
|
| 47 |
+
}
|
| 48 |
+
|
| 49 |
+
static GC_bool printing_errors = FALSE;
|
| 50 |
+
/* Print all objects on the list after printing any smashed objs. */
|
| 51 |
+
/* Clear both lists. */
|
| 52 |
+
void GC_print_all_errors ()
|
| 53 |
+
{
|
| 54 |
+
unsigned i;
|
| 55 |
+
|
| 56 |
+
LOCK();
|
| 57 |
+
if (printing_errors) {
|
| 58 |
+
UNLOCK();
|
| 59 |
+
return;
|
| 60 |
+
}
|
| 61 |
+
printing_errors = TRUE;
|
| 62 |
+
UNLOCK();
|
| 63 |
+
if (GC_debugging_started) GC_print_all_smashed();
|
| 64 |
+
for (i = 0; i < GC_n_leaked; ++i) {
|
| 65 |
+
ptr_t p = GC_leaked[i];
|
| 66 |
+
if (HDR(p) -> hb_obj_kind == PTRFREE) {
|
| 67 |
+
GC_err_printf("Leaked atomic object at ");
|
| 68 |
+
} else {
|
| 69 |
+
GC_err_printf("Leaked composite object at ");
|
| 70 |
+
}
|
| 71 |
+
GC_print_heap_obj(p);
|
| 72 |
+
GC_err_printf("\n");
|
| 73 |
+
GC_free(p);
|
| 74 |
+
GC_leaked[i] = 0;
|
| 75 |
+
}
|
| 76 |
+
GC_n_leaked = 0;
|
| 77 |
+
printing_errors = FALSE;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
/*
|
| 82 |
+
* reclaim phase
|
| 83 |
+
*
|
| 84 |
+
*/
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
/*
|
| 88 |
+
* Test whether a block is completely empty, i.e. contains no marked
|
| 89 |
+
* objects. This does not require the block to be in physical
|
| 90 |
+
* memory.
|
| 91 |
+
*/
|
| 92 |
+
|
| 93 |
+
GC_bool GC_block_empty(hdr *hhdr)
|
| 94 |
+
{
|
| 95 |
+
return (hhdr -> hb_n_marks == 0);
|
| 96 |
+
}
|
| 97 |
+
|
| 98 |
+
GC_bool GC_block_nearly_full(hdr *hhdr)
|
| 99 |
+
{
|
| 100 |
+
return (hhdr -> hb_n_marks > 7 * HBLK_OBJS(hhdr -> hb_sz)/8);
|
| 101 |
+
}
|
| 102 |
+
|
| 103 |
+
/* FIXME: This should perhaps again be specialized for USE_MARK_BYTES */
|
| 104 |
+
/* and USE_MARK_BITS cases. */
|
| 105 |
+
|
| 106 |
+
/*
|
| 107 |
+
* Restore unmarked small objects in h of size sz to the object
|
| 108 |
+
* free list. Returns the new list.
|
| 109 |
+
* Clears unmarked objects. Sz is in bytes.
|
| 110 |
+
*/
|
| 111 |
+
/*ARGSUSED*/
|
| 112 |
+
ptr_t GC_reclaim_clear(struct hblk *hbp, hdr *hhdr, size_t sz,
|
| 113 |
+
ptr_t list, signed_word *count)
|
| 114 |
+
{
|
| 115 |
+
word bit_no = 0;
|
| 116 |
+
word *p, *q, *plim;
|
| 117 |
+
signed_word n_bytes_found = 0;
|
| 118 |
+
|
| 119 |
+
GC_ASSERT(hhdr == GC_find_header((ptr_t)hbp));
|
| 120 |
+
GC_ASSERT(sz == hhdr -> hb_sz);
|
| 121 |
+
GC_ASSERT((sz & (BYTES_PER_WORD-1)) == 0);
|
| 122 |
+
p = (word *)(hbp->hb_body);
|
| 123 |
+
plim = (word *)(hbp->hb_body + HBLKSIZE - sz);
|
| 124 |
+
|
| 125 |
+
/* go through all words in block */
|
| 126 |
+
while( p <= plim ) {
|
| 127 |
+
if( mark_bit_from_hdr(hhdr, bit_no) ) {
|
| 128 |
+
p = (word *)((ptr_t)p + sz);
|
| 129 |
+
} else {
|
| 130 |
+
n_bytes_found += sz;
|
| 131 |
+
/* object is available - put on list */
|
| 132 |
+
obj_link(p) = list;
|
| 133 |
+
list = ((ptr_t)p);
|
| 134 |
+
/* Clear object, advance p to next object in the process */
|
| 135 |
+
q = (word *)((ptr_t)p + sz);
|
| 136 |
+
# ifdef USE_MARK_BYTES
|
| 137 |
+
GC_ASSERT(!(sz & 1)
|
| 138 |
+
&& !((word)p & (2 * sizeof(word) - 1)));
|
| 139 |
+
p[1] = 0;
|
| 140 |
+
p += 2;
|
| 141 |
+
while (p < q) {
|
| 142 |
+
CLEAR_DOUBLE(p);
|
| 143 |
+
p += 2;
|
| 144 |
+
}
|
| 145 |
+
# else
|
| 146 |
+
p++; /* Skip link field */
|
| 147 |
+
while (p < q) {
|
| 148 |
+
*p++ = 0;
|
| 149 |
+
}
|
| 150 |
+
# endif
|
| 151 |
+
}
|
| 152 |
+
bit_no += MARK_BIT_OFFSET(sz);
|
| 153 |
+
}
|
| 154 |
+
*count += n_bytes_found;
|
| 155 |
+
return(list);
|
| 156 |
+
}
|
| 157 |
+
|
| 158 |
+
/* The same thing, but don't clear objects: */
|
| 159 |
+
/*ARGSUSED*/
|
| 160 |
+
ptr_t GC_reclaim_uninit(struct hblk *hbp, hdr *hhdr, size_t sz,
|
| 161 |
+
ptr_t list, signed_word *count)
|
| 162 |
+
{
|
| 163 |
+
word bit_no = 0;
|
| 164 |
+
word *p, *plim;
|
| 165 |
+
signed_word n_bytes_found = 0;
|
| 166 |
+
|
| 167 |
+
GC_ASSERT(sz == hhdr -> hb_sz);
|
| 168 |
+
p = (word *)(hbp->hb_body);
|
| 169 |
+
plim = (word *)((ptr_t)hbp + HBLKSIZE - sz);
|
| 170 |
+
|
| 171 |
+
/* go through all words in block */
|
| 172 |
+
while( p <= plim ) {
|
| 173 |
+
if( !mark_bit_from_hdr(hhdr, bit_no) ) {
|
| 174 |
+
n_bytes_found += sz;
|
| 175 |
+
/* object is available - put on list */
|
| 176 |
+
obj_link(p) = list;
|
| 177 |
+
list = ((ptr_t)p);
|
| 178 |
+
}
|
| 179 |
+
p = (word *)((ptr_t)p + sz);
|
| 180 |
+
bit_no += MARK_BIT_OFFSET(sz);
|
| 181 |
+
}
|
| 182 |
+
*count += n_bytes_found;
|
| 183 |
+
return(list);
|
| 184 |
+
}
|
| 185 |
+
|
| 186 |
+
/* Don't really reclaim objects, just check for unmarked ones: */
|
| 187 |
+
/*ARGSUSED*/
|
| 188 |
+
void GC_reclaim_check(struct hblk *hbp, hdr *hhdr, word sz)
|
| 189 |
+
{
|
| 190 |
+
word bit_no = 0;
|
| 191 |
+
ptr_t p, plim;
|
| 192 |
+
|
| 193 |
+
GC_ASSERT(sz == hhdr -> hb_sz);
|
| 194 |
+
p = hbp->hb_body;
|
| 195 |
+
plim = p + HBLKSIZE - sz;
|
| 196 |
+
|
| 197 |
+
/* go through all words in block */
|
| 198 |
+
while( p <= plim ) {
|
| 199 |
+
if( !mark_bit_from_hdr(hhdr, bit_no) ) {
|
| 200 |
+
GC_add_leaked(p);
|
| 201 |
+
}
|
| 202 |
+
p += sz;
|
| 203 |
+
bit_no += MARK_BIT_OFFSET(sz);
|
| 204 |
+
}
|
| 205 |
+
}
|
| 206 |
+
|
| 207 |
+
|
| 208 |
+
/*
|
| 209 |
+
* Generic procedure to rebuild a free list in hbp.
|
| 210 |
+
* Also called directly from GC_malloc_many.
|
| 211 |
+
* Sz is now in bytes.
|
| 212 |
+
*/
|
| 213 |
+
ptr_t GC_reclaim_generic(struct hblk * hbp, hdr *hhdr, size_t sz,
|
| 214 |
+
GC_bool init, ptr_t list, signed_word *count)
|
| 215 |
+
{
|
| 216 |
+
ptr_t result = list;
|
| 217 |
+
|
| 218 |
+
GC_ASSERT(GC_find_header((ptr_t)hbp) == hhdr);
|
| 219 |
+
GC_remove_protection(hbp, 1, (hhdr)->hb_descr == 0 /* Pointer-free? */);
|
| 220 |
+
if (init) {
|
| 221 |
+
result = GC_reclaim_clear(hbp, hhdr, sz, list, count);
|
| 222 |
+
} else {
|
| 223 |
+
GC_ASSERT((hhdr)->hb_descr == 0 /* Pointer-free block */);
|
| 224 |
+
result = GC_reclaim_uninit(hbp, hhdr, sz, list, count);
|
| 225 |
+
}
|
| 226 |
+
if (IS_UNCOLLECTABLE(hhdr -> hb_obj_kind)) GC_set_hdr_marks(hhdr);
|
| 227 |
+
return result;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
/*
|
| 231 |
+
* Restore unmarked small objects in the block pointed to by hbp
|
| 232 |
+
* to the appropriate object free list.
|
| 233 |
+
* If entirely empty blocks are to be completely deallocated, then
|
| 234 |
+
* caller should perform that check.
|
| 235 |
+
*/
|
| 236 |
+
void GC_reclaim_small_nonempty_block(struct hblk *hbp,
|
| 237 |
+
int report_if_found, signed_word *count)
|
| 238 |
+
{
|
| 239 |
+
hdr *hhdr = HDR(hbp);
|
| 240 |
+
size_t sz = hhdr -> hb_sz;
|
| 241 |
+
int kind = hhdr -> hb_obj_kind;
|
| 242 |
+
struct obj_kind * ok = &GC_obj_kinds[kind];
|
| 243 |
+
void **flh = &(ok -> ok_freelist[BYTES_TO_GRANULES(sz)]);
|
| 244 |
+
|
| 245 |
+
hhdr -> hb_last_reclaimed = (unsigned short) GC_gc_no;
|
| 246 |
+
|
| 247 |
+
if (report_if_found) {
|
| 248 |
+
GC_reclaim_check(hbp, hhdr, sz);
|
| 249 |
+
} else {
|
| 250 |
+
*flh = GC_reclaim_generic(hbp, hhdr, sz,
|
| 251 |
+
(ok -> ok_init || GC_debugging_started),
|
| 252 |
+
*flh, &GC_bytes_found);
|
| 253 |
+
}
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
/*
|
| 257 |
+
* Restore an unmarked large object or an entirely empty blocks of small objects
|
| 258 |
+
* to the heap block free list.
|
| 259 |
+
* Otherwise enqueue the block for later processing
|
| 260 |
+
* by GC_reclaim_small_nonempty_block.
|
| 261 |
+
* If report_if_found is TRUE, then process any block immediately, and
|
| 262 |
+
* simply report free objects; do not actually reclaim them.
|
| 263 |
+
*/
|
| 264 |
+
void GC_reclaim_block(struct hblk *hbp, word report_if_found)
|
| 265 |
+
{
|
| 266 |
+
hdr * hhdr = HDR(hbp);
|
| 267 |
+
size_t sz = hhdr -> hb_sz; /* size of objects in current block */
|
| 268 |
+
struct obj_kind * ok = &GC_obj_kinds[hhdr -> hb_obj_kind];
|
| 269 |
+
struct hblk ** rlh;
|
| 270 |
+
|
| 271 |
+
if( sz > MAXOBJBYTES ) { /* 1 big object */
|
| 272 |
+
if( !mark_bit_from_hdr(hhdr, 0) ) {
|
| 273 |
+
if (report_if_found) {
|
| 274 |
+
GC_add_leaked((ptr_t)hbp);
|
| 275 |
+
} else {
|
| 276 |
+
size_t blocks = OBJ_SZ_TO_BLOCKS(sz);
|
| 277 |
+
if (blocks > 1) {
|
| 278 |
+
GC_large_allocd_bytes -= blocks * HBLKSIZE;
|
| 279 |
+
}
|
| 280 |
+
GC_bytes_found += sz;
|
| 281 |
+
GC_freehblk(hbp);
|
| 282 |
+
}
|
| 283 |
+
} else {
|
| 284 |
+
if (hhdr -> hb_descr != 0) {
|
| 285 |
+
GC_composite_in_use += sz;
|
| 286 |
+
} else {
|
| 287 |
+
GC_atomic_in_use += sz;
|
| 288 |
+
}
|
| 289 |
+
}
|
| 290 |
+
} else {
|
| 291 |
+
GC_bool empty = GC_block_empty(hhdr);
|
| 292 |
+
# ifdef PARALLEL_MARK
|
| 293 |
+
/* Count can be low or one too high because we sometimes */
|
| 294 |
+
/* have to ignore decrements. Objects can also potentially */
|
| 295 |
+
/* be repeatedly marked by each marker. */
|
| 296 |
+
/* Here we assume two markers, but this is extremely */
|
| 297 |
+
/* unlikely to fail spuriously with more. And if it does, it */
|
| 298 |
+
/* should be looked at. */
|
| 299 |
+
GC_ASSERT(hhdr -> hb_n_marks <= 2 * (HBLKSIZE/sz + 1) + 16);
|
| 300 |
+
# else
|
| 301 |
+
GC_ASSERT(sz * hhdr -> hb_n_marks <= HBLKSIZE);
|
| 302 |
+
# endif
|
| 303 |
+
if (hhdr -> hb_descr != 0) {
|
| 304 |
+
GC_composite_in_use += sz * hhdr -> hb_n_marks;
|
| 305 |
+
} else {
|
| 306 |
+
GC_atomic_in_use += sz * hhdr -> hb_n_marks;
|
| 307 |
+
}
|
| 308 |
+
if (report_if_found) {
|
| 309 |
+
GC_reclaim_small_nonempty_block(hbp, (int)report_if_found,
|
| 310 |
+
&GC_bytes_found);
|
| 311 |
+
} else if (empty) {
|
| 312 |
+
GC_bytes_found += HBLKSIZE;
|
| 313 |
+
GC_freehblk(hbp);
|
| 314 |
+
} else if (TRUE != GC_block_nearly_full(hhdr)){
|
| 315 |
+
/* group of smaller objects, enqueue the real work */
|
| 316 |
+
rlh = &(ok -> ok_reclaim_list[BYTES_TO_GRANULES(sz)]);
|
| 317 |
+
hhdr -> hb_next = *rlh;
|
| 318 |
+
*rlh = hbp;
|
| 319 |
+
} /* else not worth salvaging. */
|
| 320 |
+
/* We used to do the nearly_full check later, but we */
|
| 321 |
+
/* already have the right cache context here. Also */
|
| 322 |
+
/* doing it here avoids some silly lock contention in */
|
| 323 |
+
/* GC_malloc_many. */
|
| 324 |
+
}
|
| 325 |
+
}
|
| 326 |
+
|
| 327 |
+
#if !defined(NO_DEBUGGING)
|
| 328 |
+
/* Routines to gather and print heap block info */
|
| 329 |
+
/* intended for debugging. Otherwise should be called */
|
| 330 |
+
/* with lock. */
|
| 331 |
+
|
| 332 |
+
struct Print_stats
|
| 333 |
+
{
|
| 334 |
+
size_t number_of_blocks;
|
| 335 |
+
size_t total_bytes;
|
| 336 |
+
};
|
| 337 |
+
|
| 338 |
+
#ifdef USE_MARK_BYTES
|
| 339 |
+
|
| 340 |
+
/* Return the number of set mark bits in the given header */
|
| 341 |
+
int GC_n_set_marks(hdr *hhdr)
|
| 342 |
+
{
|
| 343 |
+
int result = 0;
|
| 344 |
+
int i;
|
| 345 |
+
size_t sz = hhdr -> hb_sz;
|
| 346 |
+
int offset = MARK_BIT_OFFSET(sz);
|
| 347 |
+
int limit = FINAL_MARK_BIT(sz);
|
| 348 |
+
|
| 349 |
+
for (i = 0; i < limit; i += offset) {
|
| 350 |
+
result += hhdr -> hb_marks[i];
|
| 351 |
+
}
|
| 352 |
+
GC_ASSERT(hhdr -> hb_marks[limit]);
|
| 353 |
+
return(result);
|
| 354 |
+
}
|
| 355 |
+
|
| 356 |
+
#else
|
| 357 |
+
|
| 358 |
+
/* Number of set bits in a word. Not performance critical. */
|
| 359 |
+
static int set_bits(word n)
|
| 360 |
+
{
|
| 361 |
+
word m = n;
|
| 362 |
+
int result = 0;
|
| 363 |
+
|
| 364 |
+
while (m > 0) {
|
| 365 |
+
if (m & 1) result++;
|
| 366 |
+
m >>= 1;
|
| 367 |
+
}
|
| 368 |
+
return(result);
|
| 369 |
+
}
|
| 370 |
+
|
| 371 |
+
/* Return the number of set mark bits in the given header */
|
| 372 |
+
int GC_n_set_marks(hdr *hhdr)
|
| 373 |
+
{
|
| 374 |
+
int result = 0;
|
| 375 |
+
int i;
|
| 376 |
+
int n_mark_words;
|
| 377 |
+
# ifdef MARK_BIT_PER_OBJ
|
| 378 |
+
int n_objs = HBLK_OBJS(hhdr -> hb_sz);
|
| 379 |
+
|
| 380 |
+
if (0 == n_objs) n_objs = 1;
|
| 381 |
+
n_mark_words = divWORDSZ(n_objs + WORDSZ - 1);
|
| 382 |
+
# else /* MARK_BIT_PER_GRANULE */
|
| 383 |
+
n_mark_words = MARK_BITS_SZ;
|
| 384 |
+
# endif
|
| 385 |
+
for (i = 0; i < n_mark_words - 1; i++) {
|
| 386 |
+
result += set_bits(hhdr -> hb_marks[i]);
|
| 387 |
+
}
|
| 388 |
+
# ifdef MARK_BIT_PER_OBJ
|
| 389 |
+
result += set_bits((hhdr -> hb_marks[n_mark_words - 1])
|
| 390 |
+
<< (n_mark_words * WORDSZ - n_objs));
|
| 391 |
+
# else
|
| 392 |
+
result += set_bits(hhdr -> hb_marks[n_mark_words - 1]);
|
| 393 |
+
# endif
|
| 394 |
+
return(result - 1);
|
| 395 |
+
}
|
| 396 |
+
|
| 397 |
+
#endif /* !USE_MARK_BYTES */
|
| 398 |
+
|
| 399 |
+
/*ARGSUSED*/
|
| 400 |
+
void GC_print_block_descr(struct hblk *h, word /* struct PrintStats */ raw_ps)
|
| 401 |
+
{
|
| 402 |
+
hdr * hhdr = HDR(h);
|
| 403 |
+
size_t bytes = hhdr -> hb_sz;
|
| 404 |
+
struct Print_stats *ps;
|
| 405 |
+
unsigned n_marks = GC_n_set_marks(hhdr);
|
| 406 |
+
|
| 407 |
+
if (hhdr -> hb_n_marks != n_marks) {
|
| 408 |
+
GC_printf("(%u:%u,%u!=%u)", hhdr -> hb_obj_kind,
|
| 409 |
+
bytes,
|
| 410 |
+
hhdr -> hb_n_marks, n_marks);
|
| 411 |
+
} else {
|
| 412 |
+
GC_printf("(%u:%u,%u)", hhdr -> hb_obj_kind,
|
| 413 |
+
bytes, n_marks);
|
| 414 |
+
}
|
| 415 |
+
bytes += HBLKSIZE-1;
|
| 416 |
+
bytes &= ~(HBLKSIZE-1);
|
| 417 |
+
|
| 418 |
+
ps = (struct Print_stats *)raw_ps;
|
| 419 |
+
ps->total_bytes += bytes;
|
| 420 |
+
ps->number_of_blocks++;
|
| 421 |
+
}
|
| 422 |
+
|
| 423 |
+
void GC_print_block_list()
|
| 424 |
+
{
|
| 425 |
+
struct Print_stats pstats;
|
| 426 |
+
|
| 427 |
+
GC_printf("(kind(0=ptrfree,1=normal,2=unc.):size_in_bytes, #_marks_set)\n");
|
| 428 |
+
pstats.number_of_blocks = 0;
|
| 429 |
+
pstats.total_bytes = 0;
|
| 430 |
+
GC_apply_to_all_blocks(GC_print_block_descr, (word)&pstats);
|
| 431 |
+
GC_printf("\nblocks = %lu, bytes = %lu\n",
|
| 432 |
+
(unsigned long)pstats.number_of_blocks,
|
| 433 |
+
(unsigned long)pstats.total_bytes);
|
| 434 |
+
}
|
| 435 |
+
|
| 436 |
+
/* Currently for debugger use only: */
|
| 437 |
+
void GC_print_free_list(int kind, size_t sz_in_granules)
|
| 438 |
+
{
|
| 439 |
+
struct obj_kind * ok = &GC_obj_kinds[kind];
|
| 440 |
+
ptr_t flh = ok -> ok_freelist[sz_in_granules];
|
| 441 |
+
struct hblk *lastBlock = 0;
|
| 442 |
+
int n = 0;
|
| 443 |
+
|
| 444 |
+
while (flh){
|
| 445 |
+
struct hblk *block = HBLKPTR(flh);
|
| 446 |
+
if (block != lastBlock){
|
| 447 |
+
GC_printf("\nIn heap block at 0x%x:\n\t", block);
|
| 448 |
+
lastBlock = block;
|
| 449 |
+
}
|
| 450 |
+
GC_printf("%d: 0x%x;", ++n, flh);
|
| 451 |
+
flh = obj_link(flh);
|
| 452 |
+
}
|
| 453 |
+
}
|
| 454 |
+
|
| 455 |
+
#endif /* NO_DEBUGGING */
|
| 456 |
+
|
| 457 |
+
/*
|
| 458 |
+
* Clear all obj_link pointers in the list of free objects *flp.
|
| 459 |
+
* Clear *flp.
|
| 460 |
+
* This must be done before dropping a list of free gcj-style objects,
|
| 461 |
+
* since may otherwise end up with dangling "descriptor" pointers.
|
| 462 |
+
* It may help for other pointer-containing objects.
|
| 463 |
+
*/
|
| 464 |
+
void GC_clear_fl_links(void **flp)
|
| 465 |
+
{
|
| 466 |
+
void *next = *flp;
|
| 467 |
+
|
| 468 |
+
while (0 != next) {
|
| 469 |
+
*flp = 0;
|
| 470 |
+
flp = &(obj_link(next));
|
| 471 |
+
next = *flp;
|
| 472 |
+
}
|
| 473 |
+
}
|
| 474 |
+
|
| 475 |
+
/*
|
| 476 |
+
* Perform GC_reclaim_block on the entire heap, after first clearing
|
| 477 |
+
* small object free lists (if we are not just looking for leaks).
|
| 478 |
+
*/
|
| 479 |
+
void GC_start_reclaim(GC_bool report_if_found)
|
| 480 |
+
{
|
| 481 |
+
unsigned kind;
|
| 482 |
+
|
| 483 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 484 |
+
GC_ASSERT(0 == GC_fl_builder_count);
|
| 485 |
+
# endif
|
| 486 |
+
/* Reset in use counters. GC_reclaim_block recomputes them. */
|
| 487 |
+
GC_composite_in_use = 0;
|
| 488 |
+
GC_atomic_in_use = 0;
|
| 489 |
+
/* Clear reclaim- and free-lists */
|
| 490 |
+
for (kind = 0; kind < GC_n_kinds; kind++) {
|
| 491 |
+
void **fop;
|
| 492 |
+
void **lim;
|
| 493 |
+
struct hblk ** rlp;
|
| 494 |
+
struct hblk ** rlim;
|
| 495 |
+
struct hblk ** rlist = GC_obj_kinds[kind].ok_reclaim_list;
|
| 496 |
+
GC_bool should_clobber = (GC_obj_kinds[kind].ok_descriptor != 0);
|
| 497 |
+
|
| 498 |
+
if (rlist == 0) continue; /* This kind not used. */
|
| 499 |
+
if (!report_if_found) {
|
| 500 |
+
lim = &(GC_obj_kinds[kind].ok_freelist[MAXOBJGRANULES+1]);
|
| 501 |
+
for( fop = GC_obj_kinds[kind].ok_freelist; fop < lim; fop++ ) {
|
| 502 |
+
if (*fop != 0) {
|
| 503 |
+
if (should_clobber) {
|
| 504 |
+
GC_clear_fl_links(fop);
|
| 505 |
+
} else {
|
| 506 |
+
*fop = 0;
|
| 507 |
+
}
|
| 508 |
+
}
|
| 509 |
+
}
|
| 510 |
+
} /* otherwise free list objects are marked, */
|
| 511 |
+
/* and its safe to leave them */
|
| 512 |
+
rlim = rlist + MAXOBJGRANULES+1;
|
| 513 |
+
for( rlp = rlist; rlp < rlim; rlp++ ) {
|
| 514 |
+
*rlp = 0;
|
| 515 |
+
}
|
| 516 |
+
}
|
| 517 |
+
|
| 518 |
+
|
| 519 |
+
/* Go through all heap blocks (in hblklist) and reclaim unmarked objects */
|
| 520 |
+
/* or enqueue the block for later processing. */
|
| 521 |
+
GC_apply_to_all_blocks(GC_reclaim_block, (word)report_if_found);
|
| 522 |
+
|
| 523 |
+
# ifdef EAGER_SWEEP
|
| 524 |
+
/* This is a very stupid thing to do. We make it possible anyway, */
|
| 525 |
+
/* so that you can convince yourself that it really is very stupid. */
|
| 526 |
+
GC_reclaim_all((GC_stop_func)0, FALSE);
|
| 527 |
+
# endif
|
| 528 |
+
# if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
|
| 529 |
+
GC_ASSERT(0 == GC_fl_builder_count);
|
| 530 |
+
# endif
|
| 531 |
+
|
| 532 |
+
}
|
| 533 |
+
|
| 534 |
+
/*
|
| 535 |
+
* Sweep blocks of the indicated object size and kind until either the
|
| 536 |
+
* appropriate free list is nonempty, or there are no more blocks to
|
| 537 |
+
* sweep.
|
| 538 |
+
*/
|
| 539 |
+
void GC_continue_reclaim(size_t sz /* granules */, int kind)
|
| 540 |
+
{
|
| 541 |
+
hdr * hhdr;
|
| 542 |
+
struct hblk * hbp;
|
| 543 |
+
struct obj_kind * ok = &(GC_obj_kinds[kind]);
|
| 544 |
+
struct hblk ** rlh = ok -> ok_reclaim_list;
|
| 545 |
+
void **flh = &(ok -> ok_freelist[sz]);
|
| 546 |
+
|
| 547 |
+
if (rlh == 0) return; /* No blocks of this kind. */
|
| 548 |
+
rlh += sz;
|
| 549 |
+
while ((hbp = *rlh) != 0) {
|
| 550 |
+
hhdr = HDR(hbp);
|
| 551 |
+
*rlh = hhdr -> hb_next;
|
| 552 |
+
GC_reclaim_small_nonempty_block(hbp, FALSE, &GC_bytes_found);
|
| 553 |
+
if (*flh != 0) break;
|
| 554 |
+
}
|
| 555 |
+
}
|
| 556 |
+
|
| 557 |
+
/*
|
| 558 |
+
* Reclaim all small blocks waiting to be reclaimed.
|
| 559 |
+
* Abort and return FALSE when/if (*stop_func)() returns TRUE.
|
| 560 |
+
* If this returns TRUE, then it's safe to restart the world
|
| 561 |
+
* with incorrectly cleared mark bits.
|
| 562 |
+
* If ignore_old is TRUE, then reclaim only blocks that have been
|
| 563 |
+
* recently reclaimed, and discard the rest.
|
| 564 |
+
* Stop_func may be 0.
|
| 565 |
+
*/
|
| 566 |
+
GC_bool GC_reclaim_all(GC_stop_func stop_func, GC_bool ignore_old)
|
| 567 |
+
{
|
| 568 |
+
word sz;
|
| 569 |
+
unsigned kind;
|
| 570 |
+
hdr * hhdr;
|
| 571 |
+
struct hblk * hbp;
|
| 572 |
+
struct obj_kind * ok;
|
| 573 |
+
struct hblk ** rlp;
|
| 574 |
+
struct hblk ** rlh;
|
| 575 |
+
CLOCK_TYPE start_time;
|
| 576 |
+
CLOCK_TYPE done_time;
|
| 577 |
+
|
| 578 |
+
if (GC_print_stats == VERBOSE)
|
| 579 |
+
GET_TIME(start_time);
|
| 580 |
+
|
| 581 |
+
for (kind = 0; kind < GC_n_kinds; kind++) {
|
| 582 |
+
ok = &(GC_obj_kinds[kind]);
|
| 583 |
+
rlp = ok -> ok_reclaim_list;
|
| 584 |
+
if (rlp == 0) continue;
|
| 585 |
+
for (sz = 1; sz <= MAXOBJGRANULES; sz++) {
|
| 586 |
+
rlh = rlp + sz;
|
| 587 |
+
while ((hbp = *rlh) != 0) {
|
| 588 |
+
if (stop_func != (GC_stop_func)0 && (*stop_func)()) {
|
| 589 |
+
return(FALSE);
|
| 590 |
+
}
|
| 591 |
+
hhdr = HDR(hbp);
|
| 592 |
+
*rlh = hhdr -> hb_next;
|
| 593 |
+
if (!ignore_old || hhdr -> hb_last_reclaimed == GC_gc_no - 1) {
|
| 594 |
+
/* It's likely we'll need it this time, too */
|
| 595 |
+
/* It's been touched recently, so this */
|
| 596 |
+
/* shouldn't trigger paging. */
|
| 597 |
+
GC_reclaim_small_nonempty_block(hbp, FALSE, &GC_bytes_found);
|
| 598 |
+
}
|
| 599 |
+
}
|
| 600 |
+
}
|
| 601 |
+
}
|
| 602 |
+
if (GC_print_stats == VERBOSE) {
|
| 603 |
+
GET_TIME(done_time);
|
| 604 |
+
GC_log_printf("Disposing of reclaim lists took %lu msecs\n",
|
| 605 |
+
MS_TIME_DIFF(done_time,start_time));
|
| 606 |
+
}
|
| 607 |
+
return(TRUE);
|
| 608 |
+
}
|
mosesdecoder/jam-files/engine/boehm_gc/sparc_netbsd_mach_dep.s
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
! SPARCompiler 3.0 and later apparently no longer handles
|
| 2 |
+
! asm outside functions. So we need a separate .s file
|
| 3 |
+
! This is only set up for SunOS 4.
|
| 4 |
+
! Assumes this is called before the stack contents are
|
| 5 |
+
! examined.
|
| 6 |
+
|
| 7 |
+
#include "machine/asm.h"
|
| 8 |
+
|
| 9 |
+
.seg "text"
|
| 10 |
+
.globl _C_LABEL(GC_save_regs_in_stack)
|
| 11 |
+
.globl _C_LABEL(GC_push_regs)
|
| 12 |
+
_C_LABEL(GC_save_regs_in_stack):
|
| 13 |
+
_C_LABEL(GC_push_regs):
|
| 14 |
+
ta 0x3 ! ST_FLUSH_WINDOWS
|
| 15 |
+
mov %sp,%o0
|
| 16 |
+
retl
|
| 17 |
+
nop
|
| 18 |
+
|
| 19 |
+
.globl _C_LABEL(GC_clear_stack_inner)
|
| 20 |
+
_C_LABEL(GC_clear_stack_inner):
|
| 21 |
+
mov %sp,%o2 ! Save sp
|
| 22 |
+
add %sp,-8,%o3 ! p = sp-8
|
| 23 |
+
clr %g1 ! [g0,g1] = 0
|
| 24 |
+
add %o1,-0x60,%sp ! Move sp out of the way,
|
| 25 |
+
! so that traps still work.
|
| 26 |
+
! Includes some extra words
|
| 27 |
+
! so we can be sloppy below.
|
| 28 |
+
loop:
|
| 29 |
+
std %g0,[%o3] ! *(long long *)p = 0
|
| 30 |
+
cmp %o3,%o1
|
| 31 |
+
bgu loop ! if (p > limit) goto loop
|
| 32 |
+
add %o3,-8,%o3 ! p -= 8 (delay slot)
|
| 33 |
+
retl
|
| 34 |
+
mov %o2,%sp ! Restore sp., delay slot
|
mosesdecoder/jam-files/engine/boehm_gc/version.h
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
/* The version here should match that in configure/configure.ac */
|
| 2 |
+
/* Eventually this one may become unnecessary. For now we need */
|
| 3 |
+
/* it to keep the old-style build process working. */
|
| 4 |
+
#define GC_TMP_VERSION_MAJOR 7
|
| 5 |
+
#define GC_TMP_VERSION_MINOR 0
|
| 6 |
+
#define GC_TMP_ALPHA_VERSION GC_NOT_ALPHA
|
| 7 |
+
|
| 8 |
+
#ifndef GC_NOT_ALPHA
|
| 9 |
+
# define GC_NOT_ALPHA 0xff
|
| 10 |
+
#endif
|
| 11 |
+
|
| 12 |
+
#if defined(GC_VERSION_MAJOR)
|
| 13 |
+
# if GC_TMP_VERSION_MAJOR != GC_VERSION_MAJOR || \
|
| 14 |
+
GC_TMP_VERSION_MINOR != GC_VERSION_MINOR || \
|
| 15 |
+
defined(GC_ALPHA_VERSION) != (GC_TMP_ALPHA_VERSION != GC_NOT_ALPHA) || \
|
| 16 |
+
defined(GC_ALPHA_VERSION) && GC_TMP_ALPHA_VERSION != GC_ALPHA_VERSION
|
| 17 |
+
# error Inconsistent version info. Check README, version.h, and configure.ac.
|
| 18 |
+
# endif
|
| 19 |
+
#else
|
| 20 |
+
# define GC_VERSION_MAJOR GC_TMP_VERSION_MAJOR
|
| 21 |
+
# define GC_VERSION_MINOR GC_TMP_VERSION_MINOR
|
| 22 |
+
# define GC_ALPHA_VERSION GC_TMP_ALPHA_VERSION
|
| 23 |
+
#endif
|
| 24 |
+
|
| 25 |
+
|
| 26 |
+
#ifndef GC_NO_VERSION_VAR
|
| 27 |
+
|
| 28 |
+
unsigned GC_version = ((GC_VERSION_MAJOR << 16) | (GC_VERSION_MINOR << 8) | GC_TMP_ALPHA_VERSION);
|
| 29 |
+
|
| 30 |
+
#endif /* GC_NO_VERSION_VAR */
|
mosesdecoder/lm/common/compare.hh
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef LM_COMMON_COMPARE_H
|
| 2 |
+
#define LM_COMMON_COMPARE_H
|
| 3 |
+
|
| 4 |
+
#include "lm/word_index.hh"
|
| 5 |
+
|
| 6 |
+
#include <functional>
|
| 7 |
+
#include <string>
|
| 8 |
+
|
| 9 |
+
namespace lm {
|
| 10 |
+
|
| 11 |
+
/**
|
| 12 |
+
* Abstract parent class for defining custom n-gram comparators.
|
| 13 |
+
*/
|
| 14 |
+
template <class Child> class Comparator : public std::binary_function<const void *, const void *, bool> {
|
| 15 |
+
public:
|
| 16 |
+
|
| 17 |
+
/**
|
| 18 |
+
* Constructs a comparator capable of comparing two n-grams.
|
| 19 |
+
*
|
| 20 |
+
* @param order Number of words in each n-gram
|
| 21 |
+
*/
|
| 22 |
+
explicit Comparator(std::size_t order) : order_(order) {}
|
| 23 |
+
|
| 24 |
+
/**
|
| 25 |
+
* Applies the comparator using the Compare method that must be defined in any class that inherits from this class.
|
| 26 |
+
*
|
| 27 |
+
* @param lhs A pointer to the n-gram on the left-hand side of the comparison
|
| 28 |
+
* @param rhs A pointer to the n-gram on the right-hand side of the comparison
|
| 29 |
+
*
|
| 30 |
+
* @see ContextOrder::Compare
|
| 31 |
+
* @see PrefixOrder::Compare
|
| 32 |
+
* @see SuffixOrder::Compare
|
| 33 |
+
*/
|
| 34 |
+
inline bool operator()(const void *lhs, const void *rhs) const {
|
| 35 |
+
return static_cast<const Child*>(this)->Compare(static_cast<const WordIndex*>(lhs), static_cast<const WordIndex*>(rhs));
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
/** Gets the n-gram order defined for this comparator. */
|
| 39 |
+
std::size_t Order() const { return order_; }
|
| 40 |
+
|
| 41 |
+
protected:
|
| 42 |
+
std::size_t order_;
|
| 43 |
+
};
|
| 44 |
+
|
| 45 |
+
/**
|
| 46 |
+
* N-gram comparator that compares n-grams according to their reverse (suffix) order.
|
| 47 |
+
*
|
| 48 |
+
* This comparator compares n-grams lexicographically, one word at a time,
|
| 49 |
+
* beginning with the last word of each n-gram and ending with the first word of each n-gram.
|
| 50 |
+
*
|
| 51 |
+
* Some examples of n-gram comparisons as defined by this comparator:
|
| 52 |
+
* - a b c == a b c
|
| 53 |
+
* - a b c < a b d
|
| 54 |
+
* - a b c > a d b
|
| 55 |
+
* - a b c > a b b
|
| 56 |
+
* - a b c > x a c
|
| 57 |
+
* - a b c < x y z
|
| 58 |
+
*/
|
| 59 |
+
class SuffixOrder : public Comparator<SuffixOrder> {
|
| 60 |
+
public:
|
| 61 |
+
|
| 62 |
+
/**
|
| 63 |
+
* Constructs a comparator capable of comparing two n-grams.
|
| 64 |
+
*
|
| 65 |
+
* @param order Number of words in each n-gram
|
| 66 |
+
*/
|
| 67 |
+
explicit SuffixOrder(std::size_t order) : Comparator<SuffixOrder>(order) {}
|
| 68 |
+
|
| 69 |
+
/**
|
| 70 |
+
* Compares two n-grams lexicographically, one word at a time,
|
| 71 |
+
* beginning with the last word of each n-gram and ending with the first word of each n-gram.
|
| 72 |
+
*
|
| 73 |
+
* @param lhs A pointer to the n-gram on the left-hand side of the comparison
|
| 74 |
+
* @param rhs A pointer to the n-gram on the right-hand side of the comparison
|
| 75 |
+
*/
|
| 76 |
+
inline bool Compare(const WordIndex *lhs, const WordIndex *rhs) const {
|
| 77 |
+
for (std::size_t i = order_ - 1; i != 0; --i) {
|
| 78 |
+
if (lhs[i] != rhs[i])
|
| 79 |
+
return lhs[i] < rhs[i];
|
| 80 |
+
}
|
| 81 |
+
return lhs[0] < rhs[0];
|
| 82 |
+
}
|
| 83 |
+
|
| 84 |
+
static const unsigned kMatchOffset = 1;
|
| 85 |
+
};
|
| 86 |
+
|
| 87 |
+
|
| 88 |
+
/**
|
| 89 |
+
* N-gram comparator that compares n-grams according to the reverse (suffix) order of the n-gram context.
|
| 90 |
+
*
|
| 91 |
+
* This comparator compares n-grams lexicographically, one word at a time,
|
| 92 |
+
* beginning with the penultimate word of each n-gram and ending with the first word of each n-gram;
|
| 93 |
+
* finally, this comparator compares the last word of each n-gram.
|
| 94 |
+
*
|
| 95 |
+
* Some examples of n-gram comparisons as defined by this comparator:
|
| 96 |
+
* - a b c == a b c
|
| 97 |
+
* - a b c < a b d
|
| 98 |
+
* - a b c < a d b
|
| 99 |
+
* - a b c > a b b
|
| 100 |
+
* - a b c > x a c
|
| 101 |
+
* - a b c < x y z
|
| 102 |
+
*/
|
| 103 |
+
class ContextOrder : public Comparator<ContextOrder> {
|
| 104 |
+
public:
|
| 105 |
+
|
| 106 |
+
/**
|
| 107 |
+
* Constructs a comparator capable of comparing two n-grams.
|
| 108 |
+
*
|
| 109 |
+
* @param order Number of words in each n-gram
|
| 110 |
+
*/
|
| 111 |
+
explicit ContextOrder(std::size_t order) : Comparator<ContextOrder>(order) {}
|
| 112 |
+
|
| 113 |
+
/**
|
| 114 |
+
* Compares two n-grams lexicographically, one word at a time,
|
| 115 |
+
* beginning with the penultimate word of each n-gram and ending with the first word of each n-gram;
|
| 116 |
+
* finally, this comparator compares the last word of each n-gram.
|
| 117 |
+
*
|
| 118 |
+
* @param lhs A pointer to the n-gram on the left-hand side of the comparison
|
| 119 |
+
* @param rhs A pointer to the n-gram on the right-hand side of the comparison
|
| 120 |
+
*/
|
| 121 |
+
inline bool Compare(const WordIndex *lhs, const WordIndex *rhs) const {
|
| 122 |
+
for (int i = order_ - 2; i >= 0; --i) {
|
| 123 |
+
if (lhs[i] != rhs[i])
|
| 124 |
+
return lhs[i] < rhs[i];
|
| 125 |
+
}
|
| 126 |
+
return lhs[order_ - 1] < rhs[order_ - 1];
|
| 127 |
+
}
|
| 128 |
+
};
|
| 129 |
+
|
| 130 |
+
/**
|
| 131 |
+
* N-gram comparator that compares n-grams according to their natural (prefix) order.
|
| 132 |
+
*
|
| 133 |
+
* This comparator compares n-grams lexicographically, one word at a time,
|
| 134 |
+
* beginning with the first word of each n-gram and ending with the last word of each n-gram.
|
| 135 |
+
*
|
| 136 |
+
* Some examples of n-gram comparisons as defined by this comparator:
|
| 137 |
+
* - a b c == a b c
|
| 138 |
+
* - a b c < a b d
|
| 139 |
+
* - a b c < a d b
|
| 140 |
+
* - a b c > a b b
|
| 141 |
+
* - a b c < x a c
|
| 142 |
+
* - a b c < x y z
|
| 143 |
+
*/
|
| 144 |
+
class PrefixOrder : public Comparator<PrefixOrder> {
|
| 145 |
+
public:
|
| 146 |
+
|
| 147 |
+
/**
|
| 148 |
+
* Constructs a comparator capable of comparing two n-grams.
|
| 149 |
+
*
|
| 150 |
+
* @param order Number of words in each n-gram
|
| 151 |
+
*/
|
| 152 |
+
explicit PrefixOrder(std::size_t order) : Comparator<PrefixOrder>(order) {}
|
| 153 |
+
|
| 154 |
+
/**
|
| 155 |
+
* Compares two n-grams lexicographically, one word at a time,
|
| 156 |
+
* beginning with the first word of each n-gram and ending with the last word of each n-gram.
|
| 157 |
+
*
|
| 158 |
+
* @param lhs A pointer to the n-gram on the left-hand side of the comparison
|
| 159 |
+
* @param rhs A pointer to the n-gram on the right-hand side of the comparison
|
| 160 |
+
*/
|
| 161 |
+
inline bool Compare(const WordIndex *lhs, const WordIndex *rhs) const {
|
| 162 |
+
for (std::size_t i = 0; i < order_; ++i) {
|
| 163 |
+
if (lhs[i] != rhs[i])
|
| 164 |
+
return lhs[i] < rhs[i];
|
| 165 |
+
}
|
| 166 |
+
return false;
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
static const unsigned kMatchOffset = 0;
|
| 170 |
+
};
|
| 171 |
+
|
| 172 |
+
} // namespace lm
|
| 173 |
+
|
| 174 |
+
#endif // LM_COMMON_COMPARE_H
|
mosesdecoder/lm/common/model_buffer.cc
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "lm/common/model_buffer.hh"
|
| 2 |
+
#include "util/exception.hh"
|
| 3 |
+
#include "util/file_stream.hh"
|
| 4 |
+
#include "util/file.hh"
|
| 5 |
+
#include "util/file_piece.hh"
|
| 6 |
+
#include "util/stream/io.hh"
|
| 7 |
+
#include "util/stream/multi_stream.hh"
|
| 8 |
+
|
| 9 |
+
#include <boost/lexical_cast.hpp>
|
| 10 |
+
|
| 11 |
+
namespace lm {
|
| 12 |
+
|
| 13 |
+
namespace {
|
| 14 |
+
const char kMetadataHeader[] = "KenLM intermediate binary file";
|
| 15 |
+
} // namespace
|
| 16 |
+
|
| 17 |
+
ModelBuffer::ModelBuffer(StringPiece file_base, bool keep_buffer, bool output_q)
|
| 18 |
+
: file_base_(file_base.data(), file_base.size()), keep_buffer_(keep_buffer), output_q_(output_q),
|
| 19 |
+
vocab_file_(keep_buffer ? util::CreateOrThrow((file_base_ + ".vocab").c_str()) : util::MakeTemp(file_base_)) {}
|
| 20 |
+
|
| 21 |
+
ModelBuffer::ModelBuffer(StringPiece file_base)
|
| 22 |
+
: file_base_(file_base.data(), file_base.size()), keep_buffer_(false) {
|
| 23 |
+
const std::string full_name = file_base_ + ".kenlm_intermediate";
|
| 24 |
+
util::FilePiece in(full_name.c_str());
|
| 25 |
+
StringPiece token = in.ReadLine();
|
| 26 |
+
UTIL_THROW_IF2(token != kMetadataHeader, "File " << full_name << " begins with \"" << token << "\" not " << kMetadataHeader);
|
| 27 |
+
|
| 28 |
+
token = in.ReadDelimited();
|
| 29 |
+
UTIL_THROW_IF2(token != "Counts", "Expected Counts, got \"" << token << "\" in " << full_name);
|
| 30 |
+
char got;
|
| 31 |
+
while ((got = in.get()) == ' ') {
|
| 32 |
+
counts_.push_back(in.ReadULong());
|
| 33 |
+
}
|
| 34 |
+
UTIL_THROW_IF2(got != '\n', "Expected newline at end of counts.");
|
| 35 |
+
|
| 36 |
+
token = in.ReadDelimited();
|
| 37 |
+
UTIL_THROW_IF2(token != "Payload", "Expected Payload, got \"" << token << "\" in " << full_name);
|
| 38 |
+
token = in.ReadDelimited();
|
| 39 |
+
if (token == "q") {
|
| 40 |
+
output_q_ = true;
|
| 41 |
+
} else if (token == "pb") {
|
| 42 |
+
output_q_ = false;
|
| 43 |
+
} else {
|
| 44 |
+
UTIL_THROW(util::Exception, "Unknown payload " << token);
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
vocab_file_.reset(util::OpenReadOrThrow((file_base_ + ".vocab").c_str()));
|
| 48 |
+
|
| 49 |
+
files_.Init(counts_.size());
|
| 50 |
+
for (unsigned long i = 0; i < counts_.size(); ++i) {
|
| 51 |
+
files_.push_back(util::OpenReadOrThrow((file_base_ + '.' + boost::lexical_cast<std::string>(i + 1)).c_str()));
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
void ModelBuffer::Sink(util::stream::Chains &chains, const std::vector<uint64_t> &counts) {
|
| 56 |
+
counts_ = counts;
|
| 57 |
+
// Open files.
|
| 58 |
+
files_.Init(chains.size());
|
| 59 |
+
for (std::size_t i = 0; i < chains.size(); ++i) {
|
| 60 |
+
if (keep_buffer_) {
|
| 61 |
+
files_.push_back(util::CreateOrThrow(
|
| 62 |
+
(file_base_ + '.' + boost::lexical_cast<std::string>(i + 1)).c_str()
|
| 63 |
+
));
|
| 64 |
+
} else {
|
| 65 |
+
files_.push_back(util::MakeTemp(file_base_));
|
| 66 |
+
}
|
| 67 |
+
chains[i] >> util::stream::Write(files_.back().get());
|
| 68 |
+
}
|
| 69 |
+
if (keep_buffer_) {
|
| 70 |
+
util::scoped_fd metadata(util::CreateOrThrow((file_base_ + ".kenlm_intermediate").c_str()));
|
| 71 |
+
util::FileStream meta(metadata.get(), 200);
|
| 72 |
+
meta << kMetadataHeader << "\nCounts";
|
| 73 |
+
for (std::vector<uint64_t>::const_iterator i = counts_.begin(); i != counts_.end(); ++i) {
|
| 74 |
+
meta << ' ' << *i;
|
| 75 |
+
}
|
| 76 |
+
meta << "\nPayload " << (output_q_ ? "q" : "pb") << '\n';
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
void ModelBuffer::Source(util::stream::Chains &chains) {
|
| 81 |
+
assert(chains.size() <= files_.size());
|
| 82 |
+
for (unsigned int i = 0; i < chains.size(); ++i) {
|
| 83 |
+
chains[i] >> util::stream::PRead(files_[i].get());
|
| 84 |
+
}
|
| 85 |
+
}
|
| 86 |
+
|
| 87 |
+
void ModelBuffer::Source(std::size_t order_minus_1, util::stream::Chain &chain) {
|
| 88 |
+
chain >> util::stream::PRead(files_[order_minus_1].get());
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
} // namespace
|
mosesdecoder/lm/common/model_buffer.hh
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef LM_COMMON_MODEL_BUFFER_H
|
| 2 |
+
#define LM_COMMON_MODEL_BUFFER_H
|
| 3 |
+
|
| 4 |
+
/* Format with separate files in suffix order. Each file contains
|
| 5 |
+
* n-grams of the same order.
|
| 6 |
+
*/
|
| 7 |
+
|
| 8 |
+
#include "util/file.hh"
|
| 9 |
+
#include "util/fixed_array.hh"
|
| 10 |
+
|
| 11 |
+
#include <string>
|
| 12 |
+
#include <vector>
|
| 13 |
+
|
| 14 |
+
namespace util { namespace stream {
|
| 15 |
+
class Chains;
|
| 16 |
+
class Chain;
|
| 17 |
+
}} // namespaces
|
| 18 |
+
|
| 19 |
+
namespace lm {
|
| 20 |
+
|
| 21 |
+
class ModelBuffer {
|
| 22 |
+
public:
|
| 23 |
+
// Construct for writing. Must call VocabFile() and fill it with null-delimited vocab words.
|
| 24 |
+
ModelBuffer(StringPiece file_base, bool keep_buffer, bool output_q);
|
| 25 |
+
|
| 26 |
+
// Load from file.
|
| 27 |
+
explicit ModelBuffer(StringPiece file_base);
|
| 28 |
+
|
| 29 |
+
// Must call VocabFile and populate before calling this function.
|
| 30 |
+
void Sink(util::stream::Chains &chains, const std::vector<uint64_t> &counts);
|
| 31 |
+
|
| 32 |
+
// Read files and write to the given chains. If fewer chains are provided,
|
| 33 |
+
// only do the lower orders.
|
| 34 |
+
void Source(util::stream::Chains &chains);
|
| 35 |
+
|
| 36 |
+
void Source(std::size_t order_minus_1, util::stream::Chain &chain);
|
| 37 |
+
|
| 38 |
+
// The order of the n-gram model that is associated with the model buffer.
|
| 39 |
+
std::size_t Order() const { return counts_.size(); }
|
| 40 |
+
// Requires Sink or load from file.
|
| 41 |
+
const std::vector<uint64_t> &Counts() const {
|
| 42 |
+
assert(!counts_.empty());
|
| 43 |
+
return counts_;
|
| 44 |
+
}
|
| 45 |
+
|
| 46 |
+
int VocabFile() const { return vocab_file_.get(); }
|
| 47 |
+
int StealVocabFile() { return vocab_file_.release(); }
|
| 48 |
+
|
| 49 |
+
bool Keep() const { return keep_buffer_; }
|
| 50 |
+
|
| 51 |
+
private:
|
| 52 |
+
const std::string file_base_;
|
| 53 |
+
const bool keep_buffer_;
|
| 54 |
+
bool output_q_;
|
| 55 |
+
std::vector<uint64_t> counts_;
|
| 56 |
+
|
| 57 |
+
util::scoped_fd vocab_file_;
|
| 58 |
+
util::FixedArray<util::scoped_fd> files_;
|
| 59 |
+
};
|
| 60 |
+
|
| 61 |
+
} // namespace lm
|
| 62 |
+
|
| 63 |
+
#endif // LM_COMMON_MODEL_BUFFER_H
|
mosesdecoder/lm/common/ngram_stream.hh
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef LM_BUILDER_NGRAM_STREAM_H
|
| 2 |
+
#define LM_BUILDER_NGRAM_STREAM_H
|
| 3 |
+
|
| 4 |
+
#include "lm/common/ngram.hh"
|
| 5 |
+
#include "util/stream/chain.hh"
|
| 6 |
+
#include "util/stream/multi_stream.hh"
|
| 7 |
+
#include "util/stream/stream.hh"
|
| 8 |
+
|
| 9 |
+
#include <cstddef>
|
| 10 |
+
|
| 11 |
+
namespace lm {
|
| 12 |
+
|
| 13 |
+
template <class Proxy> class ProxyStream {
|
| 14 |
+
public:
|
| 15 |
+
// Make an invalid stream.
|
| 16 |
+
ProxyStream() {}
|
| 17 |
+
|
| 18 |
+
explicit ProxyStream(const util::stream::ChainPosition &position, const Proxy &proxy = Proxy())
|
| 19 |
+
: proxy_(proxy), stream_(position) {
|
| 20 |
+
proxy_.ReBase(stream_.Get());
|
| 21 |
+
}
|
| 22 |
+
|
| 23 |
+
Proxy &operator*() { return proxy_; }
|
| 24 |
+
const Proxy &operator*() const { return proxy_; }
|
| 25 |
+
|
| 26 |
+
Proxy *operator->() { return &proxy_; }
|
| 27 |
+
const Proxy *operator->() const { return &proxy_; }
|
| 28 |
+
|
| 29 |
+
void *Get() { return stream_.Get(); }
|
| 30 |
+
const void *Get() const { return stream_.Get(); }
|
| 31 |
+
|
| 32 |
+
operator bool() const { return stream_; }
|
| 33 |
+
bool operator!() const { return !stream_; }
|
| 34 |
+
void Poison() { stream_.Poison(); }
|
| 35 |
+
|
| 36 |
+
ProxyStream<Proxy> &operator++() {
|
| 37 |
+
++stream_;
|
| 38 |
+
proxy_.ReBase(stream_.Get());
|
| 39 |
+
return *this;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
private:
|
| 43 |
+
Proxy proxy_;
|
| 44 |
+
util::stream::Stream stream_;
|
| 45 |
+
};
|
| 46 |
+
|
| 47 |
+
template <class Payload> class NGramStream : public ProxyStream<NGram<Payload> > {
|
| 48 |
+
public:
|
| 49 |
+
// Make an invalid stream.
|
| 50 |
+
NGramStream() {}
|
| 51 |
+
|
| 52 |
+
explicit NGramStream(const util::stream::ChainPosition &position) :
|
| 53 |
+
ProxyStream<NGram<Payload> >(position, NGram<Payload>(NULL, NGram<Payload>::OrderFromSize(position.GetChain().EntrySize()))) {}
|
| 54 |
+
};
|
| 55 |
+
|
| 56 |
+
template <class Payload> class NGramStreams : public util::stream::GenericStreams<NGramStream<Payload> > {
|
| 57 |
+
private:
|
| 58 |
+
typedef util::stream::GenericStreams<NGramStream<Payload> > P;
|
| 59 |
+
public:
|
| 60 |
+
NGramStreams() : P() {}
|
| 61 |
+
NGramStreams(const util::stream::ChainPositions &positions) : P(positions) {}
|
| 62 |
+
};
|
| 63 |
+
|
| 64 |
+
} // namespace
|
| 65 |
+
#endif // LM_BUILDER_NGRAM_STREAM_H
|
mosesdecoder/lm/common/print.hh
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef LM_COMMON_PRINT_H
|
| 2 |
+
#define LM_COMMON_PRINT_H
|
| 3 |
+
|
| 4 |
+
#include "lm/word_index.hh"
|
| 5 |
+
#include "util/mmap.hh"
|
| 6 |
+
#include "util/string_piece.hh"
|
| 7 |
+
|
| 8 |
+
#include <cassert>
|
| 9 |
+
#include <vector>
|
| 10 |
+
|
| 11 |
+
namespace util { namespace stream { class ChainPositions; }}
|
| 12 |
+
|
| 13 |
+
// Warning: PrintARPA routines read all unigrams before all bigrams before all
|
| 14 |
+
// trigrams etc. So if other parts of the chain move jointly, you'll have to
|
| 15 |
+
// buffer.
|
| 16 |
+
|
| 17 |
+
namespace lm {
|
| 18 |
+
|
| 19 |
+
class VocabReconstitute {
|
| 20 |
+
public:
|
| 21 |
+
// fd must be alive for life of this object; does not take ownership.
|
| 22 |
+
explicit VocabReconstitute(int fd);
|
| 23 |
+
|
| 24 |
+
const char *Lookup(WordIndex index) const {
|
| 25 |
+
assert(index < map_.size() - 1);
|
| 26 |
+
return map_[index];
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
StringPiece LookupPiece(WordIndex index) const {
|
| 30 |
+
return StringPiece(map_[index], map_[index + 1] - 1 - map_[index]);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
std::size_t Size() const {
|
| 34 |
+
// There's an extra entry to support StringPiece lengths.
|
| 35 |
+
return map_.size() - 1;
|
| 36 |
+
}
|
| 37 |
+
|
| 38 |
+
private:
|
| 39 |
+
util::scoped_memory memory_;
|
| 40 |
+
std::vector<const char*> map_;
|
| 41 |
+
};
|
| 42 |
+
|
| 43 |
+
class PrintARPA {
|
| 44 |
+
public:
|
| 45 |
+
// Does not take ownership of vocab_fd or out_fd.
|
| 46 |
+
explicit PrintARPA(int vocab_fd, int out_fd, const std::vector<uint64_t> &counts)
|
| 47 |
+
: vocab_fd_(vocab_fd), out_fd_(out_fd), counts_(counts) {}
|
| 48 |
+
|
| 49 |
+
void Run(const util::stream::ChainPositions &positions);
|
| 50 |
+
|
| 51 |
+
private:
|
| 52 |
+
int vocab_fd_;
|
| 53 |
+
int out_fd_;
|
| 54 |
+
std::vector<uint64_t> counts_;
|
| 55 |
+
};
|
| 56 |
+
|
| 57 |
+
} // namespace lm
|
| 58 |
+
#endif // LM_COMMON_PRINT_H
|
mosesdecoder/lm/common/size_option.cc
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <boost/program_options.hpp>
|
| 2 |
+
#include "util/usage.hh"
|
| 3 |
+
|
| 4 |
+
namespace lm {
|
| 5 |
+
|
| 6 |
+
namespace {
|
| 7 |
+
class SizeNotify {
|
| 8 |
+
public:
|
| 9 |
+
explicit SizeNotify(std::size_t &out) : behind_(out) {}
|
| 10 |
+
|
| 11 |
+
void operator()(const std::string &from) {
|
| 12 |
+
behind_ = util::ParseSize(from);
|
| 13 |
+
}
|
| 14 |
+
|
| 15 |
+
private:
|
| 16 |
+
std::size_t &behind_;
|
| 17 |
+
};
|
| 18 |
+
}
|
| 19 |
+
|
| 20 |
+
boost::program_options::typed_value<std::string> *SizeOption(std::size_t &to, const char *default_value) {
|
| 21 |
+
return boost::program_options::value<std::string>()->notifier(SizeNotify(to))->default_value(default_value);
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
} // namespace lm
|
mosesdecoder/lm/common/size_option.hh
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include <boost/program_options.hpp>
|
| 2 |
+
|
| 3 |
+
#include <cstddef>
|
| 4 |
+
#include <string>
|
| 5 |
+
|
| 6 |
+
namespace lm {
|
| 7 |
+
|
| 8 |
+
// Create a boost program option for data sizes. This parses sizes like 1T and 10k.
|
| 9 |
+
boost::program_options::typed_value<std::string> *SizeOption(std::size_t &to, const char *default_value);
|
| 10 |
+
|
| 11 |
+
} // namespace lm
|
mosesdecoder/lm/common/special.hh
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#ifndef LM_COMMON_SPECIAL_H
|
| 2 |
+
#define LM_COMMON_SPECIAL_H
|
| 3 |
+
|
| 4 |
+
#include "lm/word_index.hh"
|
| 5 |
+
|
| 6 |
+
namespace lm {
|
| 7 |
+
|
| 8 |
+
class SpecialVocab {
|
| 9 |
+
public:
|
| 10 |
+
SpecialVocab(WordIndex bos, WordIndex eos) : bos_(bos), eos_(eos) {}
|
| 11 |
+
|
| 12 |
+
bool IsSpecial(WordIndex word) const {
|
| 13 |
+
return word == kUNK || word == bos_ || word == eos_;
|
| 14 |
+
}
|
| 15 |
+
|
| 16 |
+
WordIndex UNK() const { return kUNK; }
|
| 17 |
+
WordIndex BOS() const { return bos_; }
|
| 18 |
+
WordIndex EOS() const { return eos_; }
|
| 19 |
+
|
| 20 |
+
private:
|
| 21 |
+
WordIndex bos_;
|
| 22 |
+
WordIndex eos_;
|
| 23 |
+
};
|
| 24 |
+
|
| 25 |
+
} // namespace lm
|
| 26 |
+
|
| 27 |
+
#endif // LM_COMMON_SPECIAL_H
|
mosesdecoder/lm/config.cc
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#include "lm/config.hh"
|
| 2 |
+
|
| 3 |
+
#include <iostream>
|
| 4 |
+
|
| 5 |
+
namespace lm {
|
| 6 |
+
namespace ngram {
|
| 7 |
+
|
| 8 |
+
Config::Config() :
|
| 9 |
+
show_progress(true),
|
| 10 |
+
messages(&std::cerr),
|
| 11 |
+
enumerate_vocab(NULL),
|
| 12 |
+
unknown_missing(COMPLAIN),
|
| 13 |
+
sentence_marker_missing(THROW_UP),
|
| 14 |
+
positive_log_probability(THROW_UP),
|
| 15 |
+
unknown_missing_logprob(-100.0),
|
| 16 |
+
probing_multiplier(1.5),
|
| 17 |
+
building_memory(1073741824ULL), // 1 GB
|
| 18 |
+
temporary_directory_prefix(""),
|
| 19 |
+
arpa_complain(ALL),
|
| 20 |
+
write_mmap(NULL),
|
| 21 |
+
write_method(WRITE_AFTER),
|
| 22 |
+
include_vocab(true),
|
| 23 |
+
rest_function(REST_MAX),
|
| 24 |
+
prob_bits(8),
|
| 25 |
+
backoff_bits(8),
|
| 26 |
+
pointer_bhiksha_bits(22),
|
| 27 |
+
load_method(util::POPULATE_OR_READ) {}
|
| 28 |
+
|
| 29 |
+
} // namespace ngram
|
| 30 |
+
} // namespace lm
|