Compare commits

..

2 Commits

Author SHA1 Message Date
fur%netscape.com
1c43d4984f This is a copy of regalloc_code2_BRANCH from Netscape's private repository,
as it existed in January of 1998.


git-svn-id: svn://10.0.0.236/branches/regalloc_code2_BRANCH@22571 18797224-902f-48f8-a5cc-f745e15eee43
1999-03-02 16:12:08 +00:00
(no author)
cfe021ff88 This commit was manufactured by cvs2svn to create branch
'regalloc_code2_BRANCH'.

git-svn-id: svn://10.0.0.236/branches/regalloc_code2_BRANCH@22567 18797224-902f-48f8-a5cc-f745e15eee43
1999-03-02 15:57:58 +00:00
77 changed files with 5324 additions and 15813 deletions

View File

@@ -1,68 +0,0 @@
#############################################################################
# $Id: ACL.pm,v 1.1.2.1 1999-09-09 18:25:37 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s): Michelle Wyner <mwyner@perldap.org>
#
# DESCRIPTION
# This is an object class to parse, manage and generate ACL
# definitions for an LDAP server. Currently we only support Netscape
# and Sun/Alliance LDAP servers.
#
#############################################################################
package Mozilla::LDAP::ACL;
use Mozilla::LDAP::Utils 2.0 qw(normalizeDN);
use Tie::Hash;
use strict;
use vars qw($VERSION @ISA);
use overload
'""' => \&getLDIFString;
@ISA = ('Tie::StdHash');
$VERSION = "1.0";
#############################################################################
# Constructor.
#
sub new
{
my ($class) = shift;
my (%entry, $obj);
tie %entry, $class;
$obj = bless \%entry, $class;
return $obj;
}
#############################################################################
# Creator, make a new tie hash instance, which will keep track of all
# changes made to the hash array. This is needed so we only update modified
# attributes.
#
sub TIEHASH
{
my ($class, $self) = (shift, {});
return bless $self, $class;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,50 +0,0 @@
This is a short list of people that have contributed to the success of
this project.
* Leif Hedstrom <leif@perldap.org>
- Project lead, v1.0 and v2.0.
- Wrote some of the API code, and most of OO layers (Conn.pm,
Entry.pm, Utils.pm, ACL.pm etc.)
- Unix portability tests, and releases.
- Port to Windows/NT and ActivePerl.
* Kevin McCarthy <kmccarth@perldap.org>
- New maintainer of API.xs and API.pm
- Bug fixes, tons of contribution, particularly to the API.xs file.
* Michelle Wyner <mwyner@perldap.org>
- Testing, bug fixes, and documentation, as well as working on new
modules for PerLDAP v2.0.
* John Kristian <kristian@netscape.com>
- Rewrote the entire LDIF.pm module, which is a standalone LDIF
module, which also integrates tightly with PerLDAP if desired.
* Clayton Donley
- Wrote a lot of the initial API code (API.xs and API.pm).
* Netscape Netcenter team (Kevin Burns, Max Block, Mark Takacs etc.)
- Tons of ideas and requests for features.
- Discovering bugs daily (great, thanks... ;-).
* Bob Ferguson <rferguso@netscape.com>
- Primary guinea pig for all my NT builds.
* Everyone else that I've forgot to mention:
- Thanks for testing and debugging this package!

View File

@@ -1,735 +0,0 @@
2000-10-05 Leif Hedstrom <leif@perldap.org>
* Released v1.4.1, finally...
* Makefile.PL: Remove the POLLUTE hack, v2.0 of PerLDAP will
support this properly, and require Perl v5.6.
2000-09-19 Leif Hedstrom <leif@perldap.org>
* Conn.pm (update): Bug fix to allow us to delete() an attribute,
call update(), and then add new values (or the same values...) to
the entry again.
2000-09-19 Leif Hedstrom <leif@perldap.org>
* Entry.pm (DESTROY): Bug fix from daniel.hams@db.com (Daniel
Hams) to avoid warnings from Apache and mod_perl.
2000-09-13 Leif Hedstrom <leif@perldap.org>
* Utils.pm (askPassword): Oops, stupid typo here, should be
"unless $prompt" of course...
2000-09-13 Leif Hedstrom <leif@perldap.org>
* Entry.pm (isDeleted): Removed a test which made this function
not working at all... :)
2000-09-13 Leif Hedstrom <leif@perldap.org>
* Removed an if defined() to avoid warnings with Perl v5.6.
2000-06-24 Wolfram Schmidt <wschmidt@decefix.iao.fhg.de>
* Entry.pm (FIRSTKEY): Fix bug for deleting all attributes and calling
keys.
2000-05-30 Kevin McCarthy <kevin@perldap.org>
* Makefile.PL: Added fix so API.xs compiles under Perl 5.6
(POLLUTE=>1)
2000-05-30 Leif Hedstrom <leif@perldap.org>
* Lots of small fixes...
1999-09-08 Leif Hedstrom <leif@perldap.org>
* Conn.pm, Entry.pm: Changed \* to be \& when creating function
aliases.
1999-09-09 Kevin McCarthy <kevin@perldap.org>
* Conn.pm (update): Fixed potential bug with scalar(@add) and @remove
comparison.
1999-09-08 Kevin McCarthy <kevin@perldap.org>
* API.xs: Misc. - function reordering, prototypes, comments.
(berptr2svpv): Added to handle struct berval * typemap.
(sv2ldapcontrolptrptr): Added to handle LDAPControl ** typemap.
(ldapcontrolptrptr2avref): Ditto.
(sv2ldapvirtuallistptr): Added to handle LDAPVirtualList * typemap.
(ldap_abandon_ext): Added CLEANUP for LDAPControl **.
(ldap_add_ext): Ditto.
(ldap_add_ext_s): Ditto.
(ldap_compare_ext): Ditto.
(ldap_compare_ext_s): Ditto.
(ldap_controls_count): Ditto.
(ldap_delete_ext): Ditto.
(ldap_delete_ext_s): Ditto.
(ldap_extended_operation): Ditto.
(ldap_modify_ext): Ditto.
(ldap_modify_ext_s): Ditto.
(ldap_parse_virtuallist_control): Ditto.
(ldap_rename): Ditto.
(ldap_rename_s): Ditto.
(ldap_sasl_bind): Ditto.
(ldap_search_ext): Ditto.
(ldap_search_ext_s): Ditto.
(ldap_create_persistentsearch_control): Fixed parameter ctrlp.
(ldap_create_sort_control): Ditto.
(ldap_create_virtuallist_control): Fixed parameter ctrlp,
LDAPVirtualList cleanup.
(ldap_extended_operation): Fixed parameter retdatap, added CLEANUP.
(ldap_free_friendlymap): Fixed parameter map.
(ldap_friendly_name): Ditto.
(ldap_memcache_get): Fixed parameter cachep.
(ldap_memcache_init): Ditto.
(ldap_multisort_entries): Fixed parameter chain.
(ldap_sort_entries): Ditto.
(ldap_next_attribute): Removed ber as output parameter.
(ldap_parse_entrychange_control): Added CLEANUP.
(ldap_parse_result): Ditto.
(ldap_parse_sort_control): Ditto.
(ldap_parse_extended_result): Fixed parameter retdatap, added CLEANUP.
(ldap_parse_sasl_bind_result): Fixed parameter servercredp.
(ldap_parse_sasl_bind_s): Fixed parameter servercredp, added CLEANUP.
* typemap: Added typemaps FriendlyMap, LDAPVirtualList *,
struct berval *, LDAPControl **
Removed typemaps LDAPMessage **, FriendlyMap *,
struct berval **, LDAPMemCache **
Added comments about the typemaps.
1999-09-07 Leif Hedstrom <leif@perldap.org>
* API.xs (avref2charptrptr): Fixed potential core dump, if the
argument passed wasn't a proper array.
(avref2berptrptr): Ditto.
1999-09-07 Leif Hedstrom <leif@perldap.org>
* API.xs (avref2charptrptr): Merged in changes from v1.4.1, fixes
a potential core dump.
(avref2berptrptr): Ditto.
1999-09-06 Leif Hedstrom <leif@perldap.org>
* Conn.pm (search): Cleaned out warnings, from @_ and undefined
variables ($self->{ldres}).
(searchURL): Ditto.
(browse): Ditto.
(compare): Ditto.
1999-09-06 Leif Hedstrom <leif@perldap.org>
* Conn.pm (searchURL): We now return undef if we don't find
anything, instead of an empty string
(search): Ditto.
(search): Added code for handling the new options, including the
verbose argument (for debugging information).
(search): Fixed bug with empty list of attributes. This might be
considered a bug in API.xs::avref2charptrptr().
(browse): Support new options, bug fixes when calling with empty
list of attributes.
(compare): Support new options syntax, and verbose.
1999-09-06 Leif Hedstrom <leif@perldap.org>
* Conn.pm (search): Removed $res and $resv, set the internal data
element directly.
(searchURL): Ditto.
1999-09-05 Leif Hedstrom <leif@perldap.org>
* Entry.pm (values): Changed $#<xxx> syntax to use scalar.
(values): Cleaned up @vals, it's no longer needed.
* Conn.pm (_initialize): Renamed from init().
(new): Added support for the new "standard" way of handling
arguments (both the old syntax and the new "hash" array method are
supported).
(new): Added support for a verbose option. This is only supported
with the new argument syntax.
(update): Changed $#<xxx> to use scalar(@<xxx>) instead. This is
slightly faster...
* Entry.pm (new): Call _initialize() method of there are any extra
arguments passed.
(_initialize): New private method, to initialize the entry with
attribute-value pairs (used by ::new).
* Conn.pm (newEntry): Now we support initializing new Entry
objects with a list of attribute-value pairs.
1999-08-25 John Kristian <kristian@netscape.com>
* Entry.pm (printLDIF): Bug fix.
* LDIF.pm: Cleaned out memory leaks.
1999-08-24 Leif Hedstrom <leif@netscape.com>
* Merged v1.3.x into trunk, tagged it as v1.4, and released it!
1999-08-19 Leif Hedstrom <leif@netscape.com>
* Changed internal version numbering again, just called this plain
v1.4.
* Entry.pm (FIRSTKEY): Bug fix, we'd crap out if there are no
attributes in the returned entry.
(NEXTKEY): Ditto.
1999-08-18 Leif Hedstrom <leif@netscape.com>
* Set version number to v1.4! Woohoo! Also tagged it as v1.3.4,
last "development" release.
1999-08-17 Leif Hedstrom <leif@netscape.com>
* Makefile.PL: Fixes for Windows/NT, cleaned out some code etc.
(MY::postamble): Support for "make html".
* MANIFEST: Updated with all new files etc.
* test.pl: Renamed to oldtest.pl, to avoid "make test" to fail.
1999-08-16 Kevin McCarthy <kmccarth@perldap.org> and Leif Hedstrom
* API.xs: Cleaned most all the memory allocation changes, we are
changing it to use the LDAP_OPT_MEMALLOC_FN_PTRS option in the
C-SDK instead (much cleaner!).
(perldap_init): New function, set up the memory management
handlers. This is called when the API module is loaded.
(perldap_malloc): New function, our memory management method(s).
(perldap_calloc): Ditto.
(perldap_realloc): Ditto.
(perldap_free): Ditto.
1999-08-16 Kevin McCarthy <kmccarth@perldap.org>
* API.xs: Cleaned up prototypes, changed strdup() to use a
Perl'ified version, change a number of free()'s to use Safefree.
(ldap_value_free_perl): New function, similar to
ldap_mods_free_perl(), to avoid memory problems (on NT and
ActivePerl primarily).
(StrDup): New function, to handle strdup() calls in a safe way.
(ber_bvfree_perl): Ditto.
(ber_bvecfree_perl): Ditto.
1999-08-15 Leif Hedstrom <leif@netscape.com>
* API.xs (ldap_mods_free_perl): Modified version of
ldap_mods_free(), which uses Perl native free method instead of
the things from the LDAP SDK. This fixes some nasty issues with
Windows/NT and ActiveState Perl. Woohoo!!!
1999-08-14 Leif Hedstrom <leif@netscape.com> and Kevin McCarthy
* Entry.pm (setValues): Implemented bug fix for bug id 7131, where
the "_save_" structures weren't set properly when using setValues().
1999-08-14 Kevin McCarthy <kmccarth@perldap.org>
* Conn.pm (update): Rewrote to optimize add/remove vs replace
operations. Basically, we'll try to do whatever seems to be the
smallest amount of work for the LDAP server now.
1999-08-13 Leif Hedstrom <leif@netscape.com>
* Makefile.PL: Cleaned up code, and added support for linking in
the missing libraries need for some missing symbols.
1999-08-13 Michelle Wyner <mwyner@netscape.com>
* Entry.pm: Updated documentation, and cleaned it up.
* Conn.pm: Ditto.
1999-08-12 Leif Hedstrom <leif@netscape.com>
* Entry.pm (move): Changed name, was rename(), is now move().
1999-08-10 Leif Hedstrom <leif@netscape.com>
* Entry.pm (setValues): Renamed, used to be setValue(), which is
now an alias to setValues().
(getValues): New method, to get the array of values.
(STORE): Fixed tests around DN handling, making sure it's not
treated as an array. I also optimized a couple of tests, since we
now filter out "DN" earlier in the funtion(s).
(attrModified): Ditto.
(attrClean): Ditto.
(unRemove): Ditto.
(removeValue): Ditto.
(addValue): Ditto.
1999-08-08 Leif Hedstrom <leif@netscape.com> and Kevin McCarthy
* Entry.pm (setValue): Remove _delete_ flag, if set.
* Conn.pm (close): Fixed memory leak, moved code from the DESTROY
method over here.
(DESTROY): Call the close() method.
(getErrorCode): We now return LDAP_SUCCESS if there is no LDAP
connection handle.
(getErrorString): Ditto.
* Entry.pm (STORE): Bug fix for large attribute sets.
(attrModified): Ditto.
(removeValue): Ditto.
(addValue): Ditto.
(EXISTS): Fix for bug 4368, cleaning up the code, and avoid the
double calls.
1999-08-06 Leif Hedstrom <leif@netscape.com> and Kevin McCarthy
* API.xs: Added some more tests around free() statements. These
are most likely never triggered, but better safe than sorrow (and
the overhead of testing this is insignificant).
* Conn.pm (browse): Added this function, to make it easy to browse
an entry.
(compare): Compare an attribute value against a DN/entry, without
having to do the search.
* Entry.pm (removeValue): Fixed loop bug.
(addValue): Ditto.
(hasValue): Ditto.
(matchValue): Fixed loop bug, and also missing normalization in
half of the case statement.
(rename): Added this new method, to rename attributes.
(copy): Added, to copy attributes.
* Merged v1.2.3 with v1.3 branch.
1999-08-06 Kevin McCarthy <kmccarth@perldap.org>
* Entry.pm (addDNValue): Bug fix, index for norm was wrong.
* Entry.pm (size): Optimzied for performance.
1999-07-25 Kevin McCarthy <kmccarth@perldap.org>
* API.xs: Fixed memory allocation problems in parsing and
generating the LDAPMods structure.
1999-06-22 Leif Hedstrom <leif@netscape.com>
* Conn.pm (add): Fixed bug 3342, thanks to Kevin McCarthy for
debugging this, and providing a patch. This fixes the problem with
adding new entries that has binary data.
1999-05-30 Kevin McCarthy <kevin@perldap.org>
* typemap, API.xs: Updated Perl internal variables. na=>PL_na,
sv_undef=>PL_sv_undef.
NOTE: This means we can only compile with Perl 5.004_05 and later now.
1999-05-30 Kevin McCarthy <kevin@perldap.org>
* typemap: Translate undef to NULL, so we can pass NULL to API calls.
1999-03-23 Leif Hedstrom <leif@netscape.com>
* Changed versioning numbers for all .pm files.
1999-03-22 Leif Hedstrom <leif@netscape.com>
* Entry.pm: Removed all _self_obj_ stuff...
* Conn.pm: Ditto.
* Conn.pm: Cleanup in use statements, and "use strict".
(search): Avoid warnings of uninitialized variables.
(searchURL): Ditto.
(modifyRDN): Bugfix, we did not update the appropriate DN in the
self object (very minor...).
* Entry.pm: Cleanup in use statements, and "use strict".
(BEGIN): Added this initializer, to use the new LDIF module.
(STORE): Fixed bug where we would not ignore the internal instance
variables properly.
* Utils.pm: Cleanup in all use statements, and "use strict". Also
enforces the VERSION control feature.
* Merged v1.2.1 to devel-branch-1_3, and tagged v1.3.1.
1999-03-21 Leif Hedstrom <leif@netscape.com>
* Checked in v1.2.1(beta).
1999-03-19 Leif Hedstrom <leif@netscape.com>
* Conn.pm (add): Fixed the code so that it will handle hash array,
as the documentation indicates. (Pointed out by Kevin Burns).
(add): Code cleanup in the add() method.
1999-03-18 Leif Hedstrom <leif@netscape.com>
* Entry.pm: Changed back some of the "my" definitions, to make
sure arrays are properly reset.
(setValue): Added the _modified_ flag, from Stephen P. Schaefer
<stephen@networks.com>.
(addValue): Bug fix, when calling delete, and then
addValue(). From Stephen P. Schaefer as well.
* Conn.pm: Ditto. This fixes the bug where qsearch/printLDIF()
would print multiple values.
1999-03-12 Leif Hedstrom <leif@netscape.com>
* Conn.pm: Changed docs for modifyRDN(), it was wrong...
1999-03-11 Leif Hedstrom <leif@netscape.com>
* Entry.pm (new): Added this method, so that "new ...::Entry" will
work as expected.
1999-03-09 Leif Hedstrom <leif@netscape.com>
* Entry.pm: Tons of changes to handling the save/modified/deleted
attribute values.
(DESTROY): Added this destructor again, this time it does seem to
help quite a lot! Whoohoo...
* Conn.pm (update): Bug fix for bug #2530, keeping sort order for
attribute values.
1999-03-08 Leif Hedstrom <leif@netscape.com>
* Entry.pm (unRemove): Bug fix, this was terribly horked, please
let's try it to make sure it works...
* Conn.pm (newEntry): Bug fix, forgot to give it the self_obj
member value... Sigh.
1999-03-05 Leif Hedstrom <leif@netscape.com>
* Entry.pm (DELETE): We now handle the event that someone tries to
delete an internal attribute.
* Conn.pm (update): Bug: We forgot to test for existance of
"_save_" before trying to loop over it.
* Entry.pm (attrClean): Added this method, to make it easier to
reset the internal state of en Entry. This is used primarily by
the Conn.pm package.
(unRemove): Bug Fix: $selfl changed to $self...
1999-02-28 Leif Hedstrom <leif@netscape.com>
* Entry.pm (matchValue): Added support for the normalization,
which should have been done before... Bug #2854.
* Conn.pm (printError): Changed to use ldap_err2string instead of
ldap_perror.
* Utils.pm (ldapArgs): Changed "root" to "base" in the LD
structure.
(userCredentials): Ditto.
* Conn.pm: Changed documentation to reflect the "base/root"
change.
1999-01-06 Leif Hedstrom <leif@netscape.com>
* Conn.pm (nextEntry): Fixed (tried to fix...) the bug with
missing attributes. I hope this will work, at a minimum I'm sure
it won't hurt. The idea is to keep the case on the attribute type
when requesting the values_len().
1999-01-11 Leif Hedstrom <leif@netscape.com>
* API.xs: Added IF statements around all ldap_value_free() calls.
1999-01-05 Leif Hedstrom <leif@netscape.com>
* Conn.pm (getRes): Ooops, didn't return the appropriate
value... :(
(init): Changed test for LDAP_SUCCESS, to always return 0 or 1.
(close): Ditto.
(delete): Ditto.
(add): Ditto.
(modifyRDN): Ditto.
(update): Ditto.
(simpleAuth): Ditto.
* Entry.pm (NEXTKEY): Don't return the last $key if it's one that
should be hidden.
* Conn.pm (newEntry): New method, to create an empty LDAP::Entry
object. It is properly "tied" into the appropriate object.
1999-01-04 Leif Hedstrom <leif@netscape.com>
* Entry.pm (setDN): Added third optional argument, to enfoce DN
normalization.
(getDN): Ditto.
(hasDNValue): Ditto.
(matchDNValue): Ditto.
* Entry.pm (removeValue): Added support for DN normalization
(optional argument).
(addValue): Ditto
(getDN): Ditto.
1998-12-31 Leif Hedstrom <leif@netscape.com>
* Entry.pm (DESTROY): Added this method, don't know if it actually
makes any sense at all... :(
* Conn.pm (add): Use _oc_order_ to find a list of attributes, to
avoide calling the TIEHASH methods.
(update): Ditto.
(ALL): Clean out some "my" definitions.
* Entry.pm (unRemove): New function, to undo remove opertaions on
an attribute.
(DELETE): Bug-fix, don't undef the attribute, it would prevent us
from updating it properly in the Conn::update() method.
(remove): Ditto.
* Conn.pm (nextEntry): Return $obj instead of blessing the %entry
(again).
1998-12-25 Leif Hedstrom <leif@netscape.com>
* Conn.pm (POD): Changed examples from $conn -> $entry.
1998-12-17 Leif Hedstrom <leif@netscape.com>
* Conn.pm (DESTROY): undef the Perl data after doing a
ldap_msgfree(), bug #1964.
(search): Ditto.
(searchURL): Ditto.
(nextEntry): Changed the order of setting numattr, to make sure
it's zero if we don't find anything.
1998-12-16 Leif Hedstrom <leif@netscape.com>
* Entry.pm (FIRSTKEY): Modified to honor the oc_order.
(NEXTKEY): Ditto.
(markModified): Made as an alias for attrModified().
* Conn.pm (nextEntry): Added code to handle internal counters for
number of attributes in oc_order. This is used/needed for the
FIRSTKEY and NEXTKEY methods in the Entry/Tie::Hash object.
* Entry.pm (isAttr): New method, to make sure an attribute name
really is a valid LDAP attribute.
(FIRSTKEY): Now we'll handle each() and keys() properly, whooohoo!
(NEXTKEY): Ditto.
1998-12-15 Leif Hedstrom <leif@netscape.com>
* Entry.pm (isDeleted): Added new method, almost identical to isModified().
(EXISTS): New method, to implement the EXISTS functionality.
* API.xs (RET_CPP): Test for NULL pointers, bug #1387.
(RET_BVPP): Ditto.
* Utils.pm (ldapArgs): Fixed bug where "-s 0" would not be honored
(I'm an idiot, OK?).
1998-12-14 Leif Hedstrom <leif@netscape.com>
* Conn.pm (getRes): New method, to return the internal result message.
(getLD): Use defined() around test for existence.
1998-12-11 Leif Hedstrom <leif@netscape.com>
* Conn.pm (new): Make sure binddn and bindpasswd are set to the
empty string unless specified.
(init): Make sure certdb is defined before trying to use it.
(setDefaultRebindProc): Added default auth method, unless
explicitly specified.
* Utils.pm (askPassword): Added support for Term::ReadKey.
(askPassword): Moved the eval "use ..." here.
(userCredentials): Removed verbose print statement.
(askPassword): Added an optional argument to print a prompt;
* Conn.pm (setDefaultRebindProc): Added a default "auth" value, if
not provided in the call.
1998-12-04 Leif Hedstrom <leif@netscape.com>
* Makefile.PL: Modified so that "silent" install will actually
echo what options it's setting.
It will now croak() if the SDK dir specified doesn't exist.
* INSTALL: Updated to reflect new v1.1 stuff. Added links to the
FAQ.
* README: Ditto. Also changed some of the binary install
information, which might not be useful anyways...
* Makefile.PL: Added "filters" to remove .dll and .sl from shared
libraries when creating link options. I also replaced the code to
put the valid library extensions into a variable (bug #1344).
* Makefile.PL: Fixed some crap with the config parsing, and ENV
handling (for silent installs).
1998-12-03 Leif Hedstrom <leif@netscape.com>
* Conn.pm (update): Bug fix, now we empty the hash array before
examining changed attributes (bug #1385).
* Makefile.PL: Added the "-nolinenumbers" XSUBS options (bug #1329).
1998-09-26 Leif Hedstrom <leif@netscape.com>
* Conn.pm (init): Cleaned out _perror() calls.
(delete): Added support for calling delete() with an Entry::
object as paramter.
(new): Cleaned out some dead code for $ref.
* Entry.pm (setValue): New method, to avoid having to use Perl
assignment statements to set an entire attribute value.
1998-09-18 Leif Hedstrom <leif@netscape.com>
* Conn.pm (init): Changed call to ldapssl_client_init() to pass a
0 value as the handle pointer. This avoids a Perl compiler warning.
1998-09-12 Leif Hedstrom <leif@netscape.com>
* LDIF.pm (readEntries): Changed tests for empty arguments, to use
defined().
* Utils.pm (ldapArgs): Bug fix, we used the wrong option for the
certificate (-P) when checking to set the LDAP port.
(normalizeDN): Chagned tests for empty arguments, to use use defined().
* Entry.pm (STORE): Changed tests for empty arguments, to use
defined().
(DELETE): Ditto.
(attrModified): Ditto.
(isModified): Ditto.
(remove): Ditto.
(removeValue): Ditto.
(addValue): Ditto.
(hasValue): Ditto.
(matchValue): Ditto.
(setDN): Ditto.
(size): Ditto.
(exists): Ditto.
* Conn.pm (printError): Changed test for $str to see if it's defined.
(delete): Cleaned up code around $dn.
(modifyRDN): Cleaned up testes around $dn and $del.
1998-09-11 Leif Hedstrom <leif@netscape.com>
* Conn.pm (modifyRDN): We now preserve the case of the DN/RDN, but
still treat RDNs as CIS when comparing strings.
1998-09-08 Leif Hedstrom <leif@netscape.com>
* Conn.pm (setDefaultRebindProc): Bug fix, it had the Ldapc:: crap
stil in there... :-(.
(simpleAuth): New method, to do simple authentication rebind.
1998-09-07 Leif Hedstrom <leif@netscape.com>
* Makefile.PL: Changed all <> to <STDIN>, to support command line
arguments for MakeMaker.
1998-09-03 Leif Hedstrom <leif@netscape.com>
* Conn.pm (nextEntry): Fixed bug with case sensitivity.
1998-08-18 Leif Hedstrom <leif@netscape.com>
* Conn.pm (setDefaultRebindProc): It's back!
Officially released PerLDAP v1.0.
1998-08-13 Leif Hedstrom <leif@netscape.com>
* Makefile.PL: Fixed so that automated installs works.
* Conn.pm (update): Fixed narly bug with ldap_modify()...
* All: Cleaned up some hash indexes, to make sure they are
properly quoted, and there are no conflicts to resolve.
* Entry.pm (STORE): Fixed a bug with attribute names not being
properly added to _oc_order_.
(addValue): Ditto, added the same code as for STORE.
1998-08-06 Leif Hedstrom <leif@netscape.com>
* Entry.pm (printLDIF): Copied/modified from the Utils.pm library.
(isModified): Added this function, thought it might be useful.
1998-08-03 Leif Hedstrom <leif@netscape.com>
* Conn.pm (modifyRDN): Fixed! It also has an option to take an
"external" DN as an argument, if supplied.
1998-08-02 Leif Hedstrom <leif@netscape.com>
* Conn.pm (getErrorCode): Now takes two optional arguments, to
return the match string, and extra error string. Note that these
two arguments are pointers to strings!
* API.xs(ldap_get_lderrno): Fixed this function, at least it seems
to work now...
* Conn.pm (getLD): Added this function, convenient way to get the
LD from the OO layer.
1998-07-30 Leif Hedstrom <leif@netscape.com>
* Conn.pm (modifyRDN): New method, to rename the RDN of the entry.
* Utils.pm (answer): New function, from LdapUtils.pm.
* Conn.pm (delete): Fixed references to normalizeDN.
* Utils.pm (userCredentials): Added this function, to make it easy
to get credentials when binding as a user.
(normalizeDN): Fixed bugs, because of calling convention...
* Conn.pm (getError): Fixed bug with passing read-only argument.
1998-07-29 Leif Hedstrom <leif@netscape.com>
* Utils.pm (unixCrypt): Moved from my LdapUtils.pm module.
Added askPassword to the export tag.
* Conn.pm (new): Added support for passing a hash array of all the
parameters, as returned by the ldapArgs() function.
* Utils.pm (str2Scope): New function, for converting strings
(subtree) to a numerical scope value (2).
(askPassword): Ditto, ask for a password, interactively.
(ldapArgs): Ditto, handle common LDAP command line arguments.
* Makefile.PL: Minor change, to do regex match on OS version for
MSWin.
* Entry.pm: Changed all _XXX hash values to also end with a _,
hence making it easier to isolate them (/^_.*_$/).
* Conn.pm (nextEntry): Changed to accept that the attributes are
now arrays, not pointers to arrays. We still consider them as
pointers internally though, it's cleaner API.
* API.pm: Changed to use the native Exporter function to export
tags into EXPORT_OK.
1998-07-22 Leif Hedstrom <leif@netscape.com>
* LDIF.pm (readEntry): Moved from my LdapUtils.pm package.
* Utils.pm (printEntry): Moved from the ::Connection class, and
marked it as "obsolete".
(encodeBase64): Moved from my LdapUtils.pm package.
(decodeBase64): Ditto.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,98 +0,0 @@
PerLDAP installation instructions
==================================
Building this package is fairly straight forward, but requires some
knowledge about using compilers and compiler tools on your system. If you
are uncomfortable using these tools, we recommend you get one of the
prebuilt binary distributions instead.
Prerequisites
=============
In order to build the module, you'll need
- Perl, version 5.003 or later. We definitely recommend you to use
v5.004 or later.
- An ANSI-C compiler, e.g. gcc-2.x, or Visual C++ 5.0.
- The LDAP client libraries and include files, e.g. the SDK from
Netscape Communications. See the README file for information on
retrieving binaries.
You can download (or CVS checkout) the Directory SDK source, see further
information available on
http://www.mozilla.org/directory/
and the FAQ at
http://www.mozilla.org/directory/faq/perldap-faq.html
Building
========
This package uses the normal Perl5 MakeMaker installation system. To
generate a Makefile appropriate for your platform, run perl on the
provided Makefile.PL script, e.g.
% perl Makefile.PL
You might have to use the command `perl5' or `perl-5.004', depending on
how you installed Perl-5. The script will now ask you a few questions to
find the necessary library and include files. A typical configuration
session is
data 195% perl5 Makefile.PL
PerLDAP - Perl 5 Module for LDAP
================================
Directory containing 'include' and 'lib' directory of the Netscape
LDAP Software Developer Kit (default: /usr): /opt/ldapsdk3
Using LDAPv3 Developer Kit (default: yes)?
Include SSL Support (default: yes)?
Libraries to link with (default: -L/opt/pkg/ldapsdk3/lib -lldapssl30):
Checking if your kit is complete...
Looks good
Writing Makefile for Mozilla::LDAP::API
The important question is where your LDAP SDK is installed, in the example
above the base directory is /opt/ldapsdk3. This directory should have two
subdirectories, named "lib" and "include". If you installed the SDK in the
standard /usr hierarchy, use the default value as provided by the install
script.
Assuming you get no errors or warning, proceed with the build and install:
% make
% make install
That should be it!
Automated Configuration and Installs
====================================
The Makefile.PL script also honors a set of environment variables to make
it possible to do configuration and installs non-interactively. The
variables are
LDAPSDKDIR - Full path to the C SDK base directory
LDAPV3ON - Set to "N" to diable LDAP v3 (on by default)
LDAPSDKSSL - Set to "N" to disable SSL (SSL is default)
With these variables set, you will not be asked any of the questions above
(but it will echo the paramaters). Just run the Makefile.PL script, and
finish the build, e.g.
% perl5 Makefile.PL
% make
% make install

File diff suppressed because it is too large Load Diff

View File

@@ -1,39 +0,0 @@
ChangeLog
API.pm
API.xs
MANIFEST
Makefile.PL
constant.h
typemap
Entry.pm
Conn.pm
LDIF.pm
Utils.pm
README
INSTALL
CREDITS
RELEASE
MPL-1.1.txt
test_api/search.pl
test_api/write.pl
test_api/api.pl
t/conn.pl
t/entry.pl
t/ChangeLog
t/api.t
t/conn.t
t/entry.t
t/ldif.t
t/utils.t
examples/ChangeLog
examples/lfinger.pl
examples/qsearch.pl
examples/monitor.pl
examples/ldappasswd.pl
examples/rmentry.pl
examples/tabdump.pl
examples/modattr.pl
examples/rename.pl
examples/psoftsync.pl
examples/changes2ldif.pl
examples/rand_mods.pl

View File

@@ -1,567 +0,0 @@
MOZILLA PUBLIC LICENSE
Version 1.1
---------------
1. Definitions.
1.0.1. "Commercial Use" means distribution or otherwise making the
Covered Code available to a third party.
1.1. "Contributor" means each entity that creates or contributes to
the creation of Modifications.
1.2. "Contributor Version" means the combination of the Original
Code, prior Modifications used by a Contributor, and the Modifications
made by that particular Contributor.
1.3. "Covered Code" means the Original Code or Modifications or the
combination of the Original Code and Modifications, in each case
including portions thereof.
1.4. "Electronic Distribution Mechanism" means a mechanism generally
accepted in the software development community for the electronic
transfer of data.
1.5. "Executable" means Covered Code in any form other than Source
Code.
1.6. "Initial Developer" means the individual or entity identified
as the Initial Developer in the Source Code notice required by Exhibit
A.
1.7. "Larger Work" means a work which combines Covered Code or
portions thereof with code not governed by the terms of this License.
1.8. "License" means this document.
1.8.1. "Licensable" means having the right to grant, to the maximum
extent possible, whether at the time of the initial grant or
subsequently acquired, any and all of the rights conveyed herein.
1.9. "Modifications" means any addition to or deletion from the
substance or structure of either the Original Code or any previous
Modifications. When Covered Code is released as a series of files, a
Modification is:
A. Any addition to or deletion from the contents of a file
containing Original Code or previous Modifications.
B. Any new file that contains any part of the Original Code or
previous Modifications.
1.10. "Original Code" means Source Code of computer software code
which is described in the Source Code notice required by Exhibit A as
Original Code, and which, at the time of its release under this
License is not already Covered Code governed by this License.
1.10.1. "Patent Claims" means any patent claim(s), now owned or
hereafter acquired, including without limitation, method, process,
and apparatus claims, in any patent Licensable by grantor.
1.11. "Source Code" means the preferred form of the Covered Code for
making modifications to it, including all modules it contains, plus
any associated interface definition files, scripts used to control
compilation and installation of an Executable, or source code
differential comparisons against either the Original Code or another
well known, available Covered Code of the Contributor's choice. The
Source Code can be in a compressed or archival form, provided the
appropriate decompression or de-archiving software is widely available
for no charge.
1.12. "You" (or "Your") means an individual or a legal entity
exercising rights under, and complying with all of the terms of, this
License or a future version of this License issued under Section 6.1.
For legal entities, "You" includes any entity which controls, is
controlled by, or is under common control with You. For purposes of
this definition, "control" means (a) the power, direct or indirect,
to cause the direction or management of such entity, whether by
contract or otherwise, or (b) ownership of more than fifty percent
(50%) of the outstanding shares or beneficial ownership of such
entity.
2. Source Code License.
2.1. The Initial Developer Grant.
The Initial Developer hereby grants You a world-wide, royalty-free,
non-exclusive license, subject to third party intellectual property
claims:
(a) under intellectual property rights (other than patent or
trademark) Licensable by Initial Developer to use, reproduce,
modify, display, perform, sublicense and distribute the Original
Code (or portions thereof) with or without Modifications, and/or
as part of a Larger Work; and
(b) under Patents Claims infringed by the making, using or
selling of Original Code, to make, have made, use, practice,
sell, and offer for sale, and/or otherwise dispose of the
Original Code (or portions thereof).
(c) the licenses granted in this Section 2.1(a) and (b) are
effective on the date Initial Developer first distributes
Original Code under the terms of this License.
(d) Notwithstanding Section 2.1(b) above, no patent license is
granted: 1) for code that You delete from the Original Code; 2)
separate from the Original Code; or 3) for infringements caused
by: i) the modification of the Original Code or ii) the
combination of the Original Code with other software or devices.
2.2. Contributor Grant.
Subject to third party intellectual property claims, each Contributor
hereby grants You a world-wide, royalty-free, non-exclusive license
(a) under intellectual property rights (other than patent or
trademark) Licensable by Contributor, to use, reproduce, modify,
display, perform, sublicense and distribute the Modifications
created by such Contributor (or portions thereof) either on an
unmodified basis, with other Modifications, as Covered Code
and/or as part of a Larger Work; and
(b) under Patent Claims infringed by the making, using, or
selling of Modifications made by that Contributor either alone
and/or in combination with its Contributor Version (or portions
of such combination), to make, use, sell, offer for sale, have
made, and/or otherwise dispose of: 1) Modifications made by that
Contributor (or portions thereof); and 2) the combination of
Modifications made by that Contributor with its Contributor
Version (or portions of such combination).
(c) the licenses granted in Sections 2.2(a) and 2.2(b) are
effective on the date Contributor first makes Commercial Use of
the Covered Code.
(d) Notwithstanding Section 2.2(b) above, no patent license is
granted: 1) for any code that Contributor has deleted from the
Contributor Version; 2) separate from the Contributor Version;
3) for infringements caused by: i) third party modifications of
Contributor Version or ii) the combination of Modifications made
by that Contributor with other software (except as part of the
Contributor Version) or other devices; or 4) under Patent Claims
infringed by Covered Code in the absence of Modifications made by
that Contributor.
3. Distribution Obligations.
3.1. Application of License.
The Modifications which You create or to which You contribute are
governed by the terms of this License, including without limitation
Section 2.2. The Source Code version of Covered Code may be
distributed only under the terms of this License or a future version
of this License released under Section 6.1, and You must include a
copy of this License with every copy of the Source Code You
distribute. You may not offer or impose any terms on any Source Code
version that alters or restricts the applicable version of this
License or the recipients' rights hereunder. However, You may include
an additional document offering the additional rights described in
Section 3.5.
3.2. Availability of Source Code.
Any Modification which You create or to which You contribute must be
made available in Source Code form under the terms of this License
either on the same media as an Executable version or via an accepted
Electronic Distribution Mechanism to anyone to whom you made an
Executable version available; and if made available via Electronic
Distribution Mechanism, must remain available for at least twelve (12)
months after the date it initially became available, or at least six
(6) months after a subsequent version of that particular Modification
has been made available to such recipients. You are responsible for
ensuring that the Source Code version remains available even if the
Electronic Distribution Mechanism is maintained by a third party.
3.3. Description of Modifications.
You must cause all Covered Code to which You contribute to contain a
file documenting the changes You made to create that Covered Code and
the date of any change. You must include a prominent statement that
the Modification is derived, directly or indirectly, from Original
Code provided by the Initial Developer and including the name of the
Initial Developer in (a) the Source Code, and (b) in any notice in an
Executable version or related documentation in which You describe the
origin or ownership of the Covered Code.
3.4. Intellectual Property Matters
(a) Third Party Claims.
If Contributor has knowledge that a license under a third party's
intellectual property rights is required to exercise the rights
granted by such Contributor under Sections 2.1 or 2.2,
Contributor must include a text file with the Source Code
distribution titled "LEGAL" which describes the claim and the
party making the claim in sufficient detail that a recipient will
know whom to contact. If Contributor obtains such knowledge after
the Modification is made available as described in Section 3.2,
Contributor shall promptly modify the LEGAL file in all copies
Contributor makes available thereafter and shall take other steps
(such as notifying appropriate mailing lists or newsgroups)
reasonably calculated to inform those who received the Covered
Code that new knowledge has been obtained.
(b) Contributor APIs.
If Contributor's Modifications include an application programming
interface and Contributor has knowledge of patent licenses which
are reasonably necessary to implement that API, Contributor must
also include this information in the LEGAL file.
(c) Representations.
Contributor represents that, except as disclosed pursuant to
Section 3.4(a) above, Contributor believes that Contributor's
Modifications are Contributor's original creation(s) and/or
Contributor has sufficient rights to grant the rights conveyed by
this License.
3.5. Required Notices.
You must duplicate the notice in Exhibit A in each file of the Source
Code. If it is not possible to put such notice in a particular Source
Code file due to its structure, then You must include such notice in a
location (such as a relevant directory) where a user would be likely
to look for such a notice. If You created one or more Modification(s)
You may add your name as a Contributor to the notice described in
Exhibit A. You must also duplicate this License in any documentation
for the Source Code where You describe recipients' rights or ownership
rights relating to Covered Code. You may choose to offer, and to
charge a fee for, warranty, support, indemnity or liability
obligations to one or more recipients of Covered Code. However, You
may do so only on Your own behalf, and not on behalf of the Initial
Developer or any Contributor. You must make it absolutely clear than
any such warranty, support, indemnity or liability obligation is
offered by You alone, and You hereby agree to indemnify the Initial
Developer and every Contributor for any liability incurred by the
Initial Developer or such Contributor as a result of warranty,
support, indemnity or liability terms You offer.
3.6. Distribution of Executable Versions.
You may distribute Covered Code in Executable form only if the
requirements of Section 3.1-3.5 have been met for that Covered Code,
and if You include a notice stating that the Source Code version of
the Covered Code is available under the terms of this License,
including a description of how and where You have fulfilled the
obligations of Section 3.2. The notice must be conspicuously included
in any notice in an Executable version, related documentation or
collateral in which You describe recipients' rights relating to the
Covered Code. You may distribute the Executable version of Covered
Code or ownership rights under a license of Your choice, which may
contain terms different from this License, provided that You are in
compliance with the terms of this License and that the license for the
Executable version does not attempt to limit or alter the recipient's
rights in the Source Code version from the rights set forth in this
License. If You distribute the Executable version under a different
license You must make it absolutely clear that any terms which differ
from this License are offered by You alone, not by the Initial
Developer or any Contributor. You hereby agree to indemnify the
Initial Developer and every Contributor for any liability incurred by
the Initial Developer or such Contributor as a result of any such
terms You offer.
3.7. Larger Works.
You may create a Larger Work by combining Covered Code with other code
not governed by the terms of this License and distribute the Larger
Work as a single product. In such a case, You must make sure the
requirements of this License are fulfilled for the Covered Code.
4. Inability to Comply Due to Statute or Regulation.
If it is impossible for You to comply with any of the terms of this
License with respect to some or all of the Covered Code due to
statute, judicial order, or regulation then You must: (a) comply with
the terms of this License to the maximum extent possible; and (b)
describe the limitations and the code they affect. Such description
must be included in the LEGAL file described in Section 3.4 and must
be included with all distributions of the Source Code. Except to the
extent prohibited by statute or regulation, such description must be
sufficiently detailed for a recipient of ordinary skill to be able to
understand it.
5. Application of this License.
This License applies to code to which the Initial Developer has
attached the notice in Exhibit A and to related Covered Code.
6. Versions of the License.
6.1. New Versions.
Netscape Communications Corporation ("Netscape") may publish revised
and/or new versions of the License from time to time. Each version
will be given a distinguishing version number.
6.2. Effect of New Versions.
Once Covered Code has been published under a particular version of the
License, You may always continue to use it under the terms of that
version. You may also choose to use such Covered Code under the terms
of any subsequent version of the License published by Netscape. No one
other than Netscape has the right to modify the terms applicable to
Covered Code created under this License.
6.3. Derivative Works.
If You create or use a modified version of this License (which you may
only do in order to apply it to code which is not already Covered Code
governed by this License), You must (a) rename Your license so that
the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
"MPL", "NPL" or any confusingly similar phrase do not appear in your
license (except to note that your license differs from this License)
and (b) otherwise make it clear that Your version of the license
contains terms which differ from the Mozilla Public License and
Netscape Public License. (Filling in the name of the Initial
Developer, Original Code or Contributor in the notice described in
Exhibit A shall not of themselves be deemed to be modifications of
this License.)
7. DISCLAIMER OF WARRANTY.
COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
8. TERMINATION.
8.1. This License and the rights granted hereunder will terminate
automatically if You fail to comply with terms herein and fail to cure
such breach within 30 days of becoming aware of the breach. All
sublicenses to the Covered Code which are properly granted shall
survive any termination of this License. Provisions which, by their
nature, must remain in effect beyond the termination of this License
shall survive.
8.2. If You initiate litigation by asserting a patent infringement
claim (excluding declatory judgment actions) against Initial Developer
or a Contributor (the Initial Developer or Contributor against whom
You file such action is referred to as "Participant") alleging that:
(a) such Participant's Contributor Version directly or indirectly
infringes any patent, then any and all rights granted by such
Participant to You under Sections 2.1 and/or 2.2 of this License
shall, upon 60 days notice from Participant terminate prospectively,
unless if within 60 days after receipt of notice You either: (i)
agree in writing to pay Participant a mutually agreeable reasonable
royalty for Your past and future use of Modifications made by such
Participant, or (ii) withdraw Your litigation claim with respect to
the Contributor Version against such Participant. If within 60 days
of notice, a reasonable royalty and payment arrangement are not
mutually agreed upon in writing by the parties or the litigation claim
is not withdrawn, the rights granted by Participant to You under
Sections 2.1 and/or 2.2 automatically terminate at the expiration of
the 60 day notice period specified above.
(b) any software, hardware, or device, other than such Participant's
Contributor Version, directly or indirectly infringes any patent, then
any rights granted to You by such Participant under Sections 2.1(b)
and 2.2(b) are revoked effective as of the date You first made, used,
sold, distributed, or had made, Modifications made by that
Participant.
8.3. If You assert a patent infringement claim against Participant
alleging that such Participant's Contributor Version directly or
indirectly infringes any patent where such claim is resolved (such as
by license or settlement) prior to the initiation of patent
infringement litigation, then the reasonable value of the licenses
granted by such Participant under Sections 2.1 or 2.2 shall be taken
into account in determining the amount or value of any payment or
license.
8.4. In the event of termination under Sections 8.1 or 8.2 above,
all end user license agreements (excluding distributors and resellers)
which have been validly granted by You or any distributor hereunder
prior to termination shall survive termination.
9. LIMITATION OF LIABILITY.
UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
(INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
10. U.S. GOVERNMENT END USERS.
The Covered Code is a "commercial item," as that term is defined in
48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
software" and "commercial computer software documentation," as such
terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
all U.S. Government End Users acquire Covered Code with only those
rights set forth herein.
11. MISCELLANEOUS.
This License represents the complete agreement concerning subject
matter hereof. If any provision of this License is held to be
unenforceable, such provision shall be reformed only to the extent
necessary to make it enforceable. This License shall be governed by
California law provisions (except to the extent applicable law, if
any, provides otherwise), excluding its conflict-of-law provisions.
With respect to disputes in which at least one party is a citizen of,
or an entity chartered or registered to do business in the United
States of America, any litigation relating to this License shall be
subject to the jurisdiction of the Federal Courts of the Northern
District of California, with venue lying in Santa Clara County,
California, with the losing party responsible for costs, including
without limitation, court costs and reasonable attorneys' fees and
expenses. The application of the United Nations Convention on
Contracts for the International Sale of Goods is expressly excluded.
Any law or regulation which provides that the language of a contract
shall be construed against the drafter shall not apply to this
License.
12. RESPONSIBILITY FOR CLAIMS.
As between Initial Developer and the Contributors, each party is
responsible for claims and damages arising, directly or indirectly,
out of its utilization of rights under this License and You agree to
work with Initial Developer and Contributors to distribute such
responsibility on an equitable basis. Nothing herein is intended or
shall be deemed to constitute any admission of liability.
13. MULTIPLE-LICENSED CODE.
Initial Developer may designate portions of the Covered Code as
"Multiple-Licensed". "Multiple-Licensed" means that the Initial
Developer permits you to utilize portions of the Covered Code under
Your choice of the NPL or the alternative licenses, if any, specified
by the Initial Developer in the file described in Exhibit A.
EXHIBIT A -Mozilla Public License.
``The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in
compliance with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/
Software distributed under the License is distributed on an "AS IS"
basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
License for the specific language governing rights and limitations
under the License.
The Original Code is ______________________________________.
The Initial Developer of the Original Code is ________________________.
Portions created by ______________________ are Copyright (C) ______
_______________________. All Rights Reserved.
Contributor(s): ______________________________________.
Alternatively, the contents of this file may be used under the terms
of the _____ license (the "[___] License"), in which case the
provisions of [______] License are applicable instead of those
above. If you wish to allow use of your version of this file only
under the terms of the [____] License and not to allow others to use
your version of this file under the MPL, indicate your decision by
deleting the provisions above and replace them with the notice and
other provisions required by the [___] License. If you do not delete
the provisions above, a recipient may use your version of this file
under either the MPL or the [___] License."
[NOTE: The text of this Exhibit A may differ slightly from the text of
the notices in the Source Code files of the Original Code. You should
use the text of this Exhibit A rather than the text found in the
Original Code Source Code for Your Modifications.]
----------------------------------------------------------------------
AMENDMENTS
The Netscape Public License Version 1.1 ("NPL") consists of the
Mozilla Public License Version 1.1 with the following Amendments,
including Exhibit A-Netscape Public License. Files identified with
"Exhibit A-Netscape Public License" are governed by the Netscape
Public License Version 1.1.
Additional Terms applicable to the Netscape Public License.
I. Effect.
These additional terms described in this Netscape Public
License -- Amendments shall apply to the Mozilla Communicator
client code and to all Covered Code under this License.
II. "Netscape's Branded Code" means Covered Code that Netscape
distributes and/or permits others to distribute under one or more
trademark(s) which are controlled by Netscape but which are not
licensed for use under this License.
III. Netscape and logo.
This License does not grant any rights to use the trademarks
"Netscape", the "Netscape N and horizon" logo or the "Netscape
lighthouse" logo, "Netcenter", "Gecko", "Java" or "JavaScript",
"Smart Browsing" even if such marks are included in the Original
Code or Modifications.
IV. Inability to Comply Due to Contractual Obligation.
Prior to licensing the Original Code under this License, Netscape
has licensed third party code for use in Netscape's Branded Code.
To the extent that Netscape is limited contractually from making
such third party code available under this License, Netscape may
choose to reintegrate such code into Covered Code without being
required to distribute such code in Source Code form, even if
such code would otherwise be considered "Modifications" under
this License.
V. Use of Modifications and Covered Code by Initial Developer.
V.1. In General.
The obligations of Section 3 apply to Netscape, except to
the extent specified in this Amendment, Section V.2 and V.3.
V.2. Other Products.
Netscape may include Covered Code in products other than the
Netscape's Branded Code which are released by Netscape
during the two (2) years following the release date of the
Original Code, without such additional products becoming
subject to the terms of this License, and may license such
additional products on different terms from those contained
in this License.
V.3. Alternative Licensing.
Netscape may license the Source Code of Netscape's Branded
Code, including Modifications incorporated therein, without
such Netscape Branded Code becoming subject to the terms of
this License, and may license such Netscape Branded Code on
different terms from those contained in this License.
VI. Litigation.
Notwithstanding the limitations of Section 11 above, the
provisions regarding litigation in Section 11(a), (b) and (c) of
the License shall apply to all disputes relating to this License.
EXHIBIT A-Netscape Public License.
"The contents of this file are subject to the Netscape Public
License Version 1.1 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of
the License at http://www.mozilla.org/NPL/
Software distributed under the License is distributed on an "AS
IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
implied. See the License for the specific language governing
rights and limitations under the License.
The Original Code is Mozilla Communicator client code, released
March 31, 1998.
The Initial Developer of the Original Code is Netscape
Communications Corporation. Portions created by Netscape are
Copyright (C) 1998-1999 Netscape Communications Corporation. All
Rights Reserved.
Contributor(s): ______________________________________.
Alternatively, the contents of this file may be used under the
terms of the _____ license (the "[___] License"), in which case
the provisions of [______] License are applicable instead of
those above. If you wish to allow use of your version of this
file only under the terms of the [____] License and not to allow
others to use your version of this file under the NPL, indicate
your decision by deleting the provisions above and replace them
with the notice and other provisions required by the [___]
License. If you do not delete the provisions above, a recipient
may use your version of this file under either the NPL or the
[___] License."

View File

@@ -1,195 +0,0 @@
#############################################################################
# $Id: Makefile.PL,v 1.15.2.2 2000-10-05 22:20:46 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Netscape Communications Corp. and Clayton Donley. Portions
# created by Netscape are Copyright (C) Netscape Communications
# Corp., portions created by Clayton Donley are Copyright (C) Clayton
# Donley. All Rights Reserved.
#
# Contributor(s): Leif Hedstrom <leif@perldap.org>
#
# DESCRIPTION
# The Makefile "source", this is mostly rewritten by Leif.
#
#############################################################################
use ExtUtils::MakeMaker;
use Config;
use Carp;
$perlpath = $Config{'perlpath'};
$osname = $Config{'osname'};
$ldapsdk_loc = $ENV{"LDAPSDKDIR"}; # Full Path to C SDK Top-Level
$ldapsdk_ssl = $ENV{"LDAPSDKSSL"}; # N to exclude SSL
$ldapsdk_ver = $ENV{"LDAPV3ON"}; # N to exclude LDAP v3 features
$libexts = "so|sl|a|lib";
print "\nPerLDAP - Perl 5 Module for LDAP\n";
print "================================\n";
$silent = 1;
print "Directory containing 'include' and 'lib' directory of the Netscape\n";
print "LDAP Software Developer Kit (default: /usr): ";
if (!$ldapsdk_loc)
{
$silent = 0;
chomp ($ldapsdk_loc = <STDIN>);
$ldapsdk_loc = "/usr" unless $ldapsdk_loc =~ /\S/;
} else {
print "$ldapsdk_loc\n";
}
croak("Directory $ldapsdk_loc does not exist!") unless -d $ldapsdk_loc;
if ($osname =~ /mswin/i)
{
$dir_sep = "\\";
} else {
$dir_sep = "/";
}
$include_ldap = $ldapsdk_loc . $dir_sep . "include";
$lib_ldap = $ldapsdk_loc . $dir_sep . "lib";
print "Using LDAPv3 Developer Kit (default: yes)? ";
if (!$ldapsdk_ver)
{
$silent = 0;
chomp ($ldapsdk_ver = <STDIN>);
} else {
print "YES\n";
}
$v3_def = "-DLDAPV3" unless ($ldapsdk_ver =~ /^n/i);
print "Include SSL Support (default: yes)? ";
if (!$ldapsdk_ssl)
{
$silent = 0;
chomp ($ldapsdk_ssl = <STDIN>);
} else {
print "YES\n";
}
$ssl_def = "-DUSE_SSL" unless ($ldapsdk_ssl =~ /^n/i);
opendir(DIR,$lib_ldap);
@files = grep{/ldap|lber/} readdir(DIR);
closedir(DIR);
if (!((@ldaplib = grep{/ldapssl.*\.($libexts)$/} @files) && $ssl_def))
{
@ldaplib = grep{/ldap.*\.($libexts)$/} @files;
@lberlib = grep{/lber.*\.($libexts)$/} @files;
}
if ($#ldaplib < 0)
{
die "No LDAP libraries found.";
}
if ($#ldaplib > 0)
{
print "Located multiple libraries:\n";
foreach $alib (@ldaplib)
{
print " - $alib\n";
}
}
$lline_ldap = $ldaplib[0];
$lline_ldap =~ s/^lib//;
$lline_ldap =~ s/\.($libexts)$//;
$lline = "-L$lib_ldap -l$lline_ldap";
if ($#lberlib >= 0 && $lline =~ /ldap$/)
{
$lline_lber = $lberlib[0];
$lline_lber =~ s/^lib//;
$lline_lber =~ s/\.($libexts)$//;
$lline .= " -l$lline_lber";
}
print "Libraries to link with (default: $lline): ";
if (!$silent)
{
chomp ($lib_line = <STDIN>);
$lib_line = $lline unless $lib_line =~ /\S/;
} else {
$lib_line = $lline;
print "\n";
}
# Include directories etc.
$my_includes = "";
$my_includes .= " -I$include_ldap" unless ($include_ldap eq "/usr/include");
# Add system dependant stuff here...
@extras = ();
if ($osname =~ /mswin/i)
{
$my_extlib = "$lib_ldap\\$ldaplib[0]";
$my_extlib .= " $lib_ldap\\$lberlib[0]" if $lber_lib;
push(@extras, 'dynamic_lib' => {
'OTHERLDFLAGS' => "kernel32.lib oldnames.lib" });
} else {
$my_extlib = "";
}
push(@extras,
CAPI => 'TRUE')
if ($] >= 5.005 and $^O eq 'MSWin32'
and $Config{archname} =~ /-object\b/i);
push(@extras,
ABSTRACT => 'Perl methods for LDAP C API calls, and OO layers',
AUTHOR => 'Netscape Communications Corp., Inc. and Leif Hedstrom')
if ($] >= 5.005);
#
# Ok, let's do it!
#
WriteMakefile(
'NAME' => 'Mozilla::LDAP::API',
'DISTNAME' => 'PerLDAP',
'VERSION_FROM' => 'API.pm',
'INC' => $my_includes,
'LIBS' => [$lib_line],
'MYEXTLIB' => $my_extlib,
'DEFINE' => "$v3_def $ssl_def",
'XSOPT' => "-nolinenumbers",
@extras
);
#
# Generate a "make HTML" target
#
sub MY::postamble
{
'
.SUFFIXES: .pm .html
.PHONY: html
.pm.html:
pod2html --netscape $< > $@
html: Entry.html Conn.html Utils.html API.html LDIF.html $(FIRST_MAKEFILE)
@rm -f pod2html-itemcache pod2html-dircache
'
}

View File

@@ -1,129 +0,0 @@
#############################################################################
# #
# PerLDAP v1.4 - A Perl Developers' Kit for LDAP #
# #
#############################################################################
What is PerLDAP?
================
PerLDAP is a set of modules written in Perl and C that allow developers to
leverage their existing Perl knowledge to easily access and manage LDAP-
enabled directories. PerLDAP makes it very easy to search, add, delete,
and modify directory entries. For example, Perl developers can easily
build web applications to access information stored in a directory or
create directory sync tools between directories and other services.
PerLDAP is an open source development project, the result of a joint effort
between Netscape and Clayton Donley, an open source developer. PerLDAP
currently provides the basic functions to allow Perl users to access and
manipulate directories easily. Based on developer feedback and
involvement, PerLDAP will continue to evolve to include additional
functionality in future releases.
Compiling the PerLDAP Sources
=============================
The source to PerLDAP is available on the Mozilla site at:
http://www.mozilla.org/directory/
You can either retrieve the .tar/zip file with the source distribution, or
use CVS to checkout the module directly. The name of the CVS module is
PerLDAP, and it checks out the directory
mozilla/directory/perldap
Further instructions for using CVS and Mozilla is available at
http://www.mozilla.org/cvs.html
and an FAQ for PerLDAP is at
http://www.mozilla.org/directory/faq/perldap-faq.html
Instructions for building the source can be found in the INSTALL file
in the source distribution. The latest stable release of PerLDAP is
v1.4, the next version is planned to be v2.0 (development continues on the
v1.9 development branch).
Getting Started
===============
Documentation for this module is in standard Perl 'pod' format. HTML
versions of this documentation can also be found on the Netscape DevEdge
site at: http://developer.netscape.com/tech/directory/.
Additionally, many good examples can be found in the 'examples' directory.
Modules and Examples Included
=============================
Mozilla::LDAP::API - Low level interface between Perl and the LDAP C API
Mozilla::LDAP::Entry - Perl methods for manipulating entry objects
Mozilla::LDAP::Conn - Perl methods for performing LDAP operations
Mozilla::LDAP::LDIF - Perl methods for utilizing LDIF
Mozilla::LDAP::Utils - Some convenient LDAP related utilities
test_api/search.pl - Tests low level API search calls
test_api/write.pl - Tests low level API write calls
test_api/api.pl - Tests ALL low level LDAPv2 calls
examples/lfinger.pl - LDAP version of the regular Unix finger command.
examples/qsearch.pl - Simple ldapsearch replacement.
examples/monitor.pl - Retrieve status information from an LDAP server.
examples/ldappasswd.pl - Change the LDAP password for a user.
examples/rmentry.pl - Remove an entire entry from the database.
examples/rename.pl - Rename (modRDN) an entry.
examples/tabdump.pl - Dump LDAP information into a tab separated file.
examples/psoftsync.pl - Synchronize LDAP with a PeopleSoft "dump" file.
All examples support the "standard" LDAP command line options, which are
-h hostname LDAP server name
-p port # LDAP port, default is 389 (or 636 for SSL)
-b base DN LDAP Base-DN
-D bind DN LDAP bind DN (connect to server as this "user")
-w bind pswd Password to bind to the server
-P certfile Use SSL, with the publick keys from this file
Note that the examples currently only support Simple Authentication
(passwords), the Client Authentication features (using certificates) will
be used in the next release. All examples also honors the environment
variable LDAP_BASEDN, set it to your systems base DN, e.g.
% setenv LDAP_BASEDN 'dc=netscape,dc=com'
or for Bourne shell
# LDAP_BASEDN='dc=netscape,dc=com'; export LDAP_BASEDN
Reporting problems and bugs
===========================
Address all bug reports and comments to the Mozilla newsgroups at:
news://news.mozilla.org/netscape.public.mozilla.directory
License/Copyright
=================
Portions by Netscape (c) Copyright 1998 Netscape Communications Corp, Inc.
Portions by Clayton Donley (c) Copyright 1998 Clayton Donley.
Portions by Leif Hedstrom (c) Copyright 1998 Leif Hedstrom.
Please read the MPL-1.1.txt file included for information on the Mozilla
Public License, which covers all files in this distribution.
Known Bugs
==========
- The Rebind operation on NT does NOT work properly when set to a Perl
function. This is being investigated.

View File

@@ -1,79 +0,0 @@
#############################################################################
# #
# PerLDAP Release Notes #
# #
#############################################################################
VERSION 1.4 - AUGUST 18, 1999
=============================
This is primarily a bug fix release, however there are 5 new methods
introduced as well. Brief descriptions follow in this document. To get
full examples and a larger summary, see the PerLDAP Programmer's Guide.
New Methods Added
-----------------
Entry.pm:
* getValues() - returns the array of values.
* move() - move one attribute to another, and delete the original.
* copy() - copy one attribute to another.
Conn.pm:
* browse() - makes it easy to browse an entry.
* compare() - compare an attribute value against a DN/entry
without having to do the search.
Bug Fixes and other changes
---------------------------
Entry.pm:
* addDNValue() - fixed wrong index for norm.
* matchValue() - fixed missing normalization in half of case statement.
* setValue() - remove _delete_ flag if set, fix for saving state.
* STORE - fixed not ignoring the internal instance variables properly.
* Fixed numerous bugs for large attribute sets.
* Fixed bug 4368 ("exists vs. EXISTS").
* Fixed several loop bugs.
* Removed all _self_obj_ references, it's obsolete in this
version.
* We support each() and keys() now on the Entry object, to loop
through all attribute names (types).
Conn.pm:
* close() - fixed memory leak.
* modifyRDN() - fixed problem where we weren't updating the
appropriate DN in the self object.
* Fixed bug 3342 (problems adding entries with binary data).
* getErrorCode()/getErrorString() - return LDAP_SUCCESS if no
LDAP connection handle.
* add() - fixed code to handle hash array as docs indicate.
* update() - optimization for "replace" vs "add/delete", we try to
use whatever LDAPMod is most efficient.
LDIF.pm:
* Complete rewrite, by John Kristian <kristian@netscape.com>.
API.xs:
* Fixed memory allocation problems, replacing all memory management
routines. This solves all known issues with ActiveState Perl.
* More safety checks around calls to *_free().
Miscellaneous
-------------
* Various other optimizations on tests and such.
* Fixed most (all?) known memory leaks.
* Fixed a lot of problems with Makefile.PL, adding some new targets
(like "make html"). Add a skeleton to "make test".
* Fixed numerous small bugs, as reported to Mozilla.
* We produce less warnings now, and try to "use strict" when
appropriate.
* We have a new versioning scheme, conforming to standard
Perl. We'll change this again when Perl's new versioning system
is in place (allowing versions like 1.2.3).

View File

@@ -1,770 +0,0 @@
#############################################################################
# $Id: Schema.pm,v 1.1.2.13 2000-06-25 07:46:42 mwyner%ogre.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.0 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s): Michelle Wyner <mwyner@perldap.org>
#
# DESCRIPTION
#
#############################################################################
package Mozilla::LDAP::Schema;
use Mozilla::LDAP::Utils 2.0 qw(normalizeDN);
use strict;
use vars qw($VERSION);
use overload
'""' => \&getLDIFString;
$VERSION = "2.0";
sub new
{
# do the search for everything
my ($self) = shift;
my $conn = shift;
my $base = "cn=schema";
my (%schema, $obj, $attr, $objectclass);
my $initialReturn = $conn->search($base, "base", "objectclass=*");
my @attributeArray = $initialReturn->getValues("attributetypes");
my @objectarray = $initialReturn->getValues("objectclasses");
foreach (@attributeArray) {
$attr = new Mozilla::LDAP::Schema::Attribute($_);
$schema{"attributes"}{$attr->name()} = $attr;
}
$schema{"searchvalue"} = $initialReturn;
$schema{"connection"} = $conn;
foreach (@objectarray) {
$objectclass = new Mozilla::LDAP::Schema::ObjectClass($_);
$schema{"objectclass"}{$objectclass->name()} = $objectclass;
}
$obj = bless \%schema;
return $obj;
}
sub add
{
my ($self, $attr) = @_;
my ($schema) = $self->{"searchvalue"};
my ($conn) = $self->{"connection"};
my $finalString;
my $ref = ref($attr);
if ($ref eq 'Mozilla::LDAP::Schema::Attribute') {
$finalString = $attr->formatValue();
$schema->addValue("attributetypes",$finalString);
return $schema;
}
}
sub update
{
my ($self) = shift;
my ($conn) = $self->{"connection"};
my ($attributes) = $self->{"searchvalue"};
return $conn->update($attributes);
}
sub attributes
{
my ($self, $attr) = (shift, lc shift);
return 0 unless (defined($attr) && ($attr ne ""));
return $self->{"attributes"}{$attr};
}
sub objectclass
{
my ($self, $attr) = (shift, lc shift);
return 0 unless (defined($attr) && ($attr ne ""));
return $self->{"objectclass"}{$attr};
}
1;
package Mozilla::LDAP::Schema::Attribute;
use Text::ParseWords;
my %fields = (
oid => undef,
name => undef,
desc => undef,
syntax => undef,
);
sub _initialize
{
my ($self, $attrString) = @_;
my @temparr = quotewords(" ", 0, $attrString);
my $i = 2;
if (ref($attrString) eq "HASH") {
my @somearray = ("NAME","OID","DESC","SYNTAX");
my($name,$oid,$desc,$syntax) = $self->rearrange(\@somearray, $attrString);
$self->{"name"} = $name;
$self->{"oid"} = $oid;
$self->{"desc"} = $desc;
$self->{"syntax"} = $syntax;
}
else {
# The OID is always going to be the first thing, and it will not have
# a label on it.
# We start from 1 because 0 will be a parentheses.
$self->{"oid"} = $temparr[1];
while ($i<(scalar(@temparr)-1)) # the last character is a ")"
{
$self->{lc $temparr[$i]} = lc $temparr[$i+1];
$i += 2;
}
}
}
sub rearrange
{
my ($self, $order, @param) = @_;
my ($i, %pos); $i = 0;
@param = %{$param[0]};
foreach (@$order) {
foreach (ref($_) eq 'ARRAY' ? @$_ : $_) {
$pos{$_} = $i;
}
$i++;
}
my (@result,%leftover);
$#result = $#$order;
while (@param) {
my $key = uc(shift(@param));
$key =~ s/^\-//;
if (exists $pos{$key}) {
$result[$pos{$key}] = shift(@param);
} else {
$leftover{$key} = shift(@param);
}
}
push (@result,$self->make_attributes(\%leftover)) if %leftover;
@result;
}
sub make_attributes {
my($self,$attr) = @_;
return () unless $attr && ref($attr) && ref($attr) eq 'HASH';
my(@att);
foreach (keys %{$attr}) {
my($key) = $_;
$key=~s/^\-//; # get rid of initial - if present
$key=~tr/a-z_/A-Z-/; # parameters are upper case, use dashes
push(@att,defined($attr->{$_}) ? qq/$key="$attr->{$_}"/ : qq/$key/);
}
return @att;
}
sub formatValue
{
my $self = shift;
my $finalString = "( ";
$finalString .= $self->oid()." NAME \'".$self->name()."\' DESC \'".$self->desc."\' SYNTAX \'".$self->syntax."\' )";
print $finalString;
return $finalString;
}
sub new
{
my $tmp = shift;
my $self = {%fields};
bless $self;
$self->_initialize(@_) if (scalar(@_) > $[);
return $self;
}
sub oid
{
my $self = shift;
if(@_) {
$self->{'oid'} = shift;
}
$self->{'oid'};
}
sub name
{
my $self = shift;
if(@_) {
$self->{'name'} = lc shift;
}
$self->{'name'};
}
sub desc
{
my $self = shift;
if(@_) {
$self->{'desc'} = shift;
}
$self->{'desc'};
}
sub syntax
{
my $self = shift;
if(@_) {
$self->{'syntax'} = shift;
}
$self->{'syntax'};
}
1;
package Mozilla::LDAP::Schema::ObjectClass;
use Text::ParseWords;
my %objfields = (
oid => undef,
name => undef,
desc => undef,
sup => undef,
must => undef,
may => undef
);
sub _initialize
{
my ($self, $attrString) = @_;
my @temparr = quotewords(" ", 0, $attrString);
my ($i,$j) = 2;
my @objarr;
my $count=0;
# The OID is always going to be the first thing, and it will not have
# a label on it.
# We start from 1 because 0 will be a parentheses.
$self->{"oid"} = $temparr[1];
while ($i<(scalar(@temparr)-1)) # the last character is a ")"
{
#since the objectclass can have stuff nested, we need to check
#for parentheses in the $i+1 phase.
#check for spaces in the objectclass!!
if ($temparr[$i] eq "") {
$i+=1;
}
if ($temparr[$i+1] ne "(") {
# print $temparr[$i],"\n";
$self->{lc $temparr[$i]} = lc $temparr[$i+1];
$i+=2;
}
else {
$j = $i+2;
my $k = 0;
while ($temparr[$j] ne ")")
{
if ($temparr[$j] eq "\$") {
$j+=1;
}
$objarr[$k] = lc $temparr[$j];
$k+=1;
$j+=1;
}
@{$self->{lc $temparr[$i]}} = @objarr;
$i=$j+1;
}
}
}
sub new
{
my $tmp = shift;
my $self = {%objfields};
bless $self;
$self->_initialize(@_);
return $self;
}
sub oid
{
my $self = shift;
if(@_) {
$self->{'oid'} = shift;
}
$self->{'oid'};
}
sub name
{
my $self = shift;
if(@_) {
$self->{'name'} = lc shift;
}
$self->{'name'};
}
sub desc
{
my $self = shift;
if(@_) {
$self->{'desc'} = lc shift;
}
$self->{'desc'};
}
sub sup
{
my $self = shift;
if(@_) {
$self->{'sup'} = lc shift;
}
$self->{'sup'};
}
sub must
{
my $self = shift;
if(@_) {
$self->{'must'} = lc shift;
}
@{$self->{'must'}};
}
sub may
{
my $self = shift;
if(@_) {
$self->{'may'} = lc shift;
}
@{$self->{'may'}};
}
#############################################################################
# Mandatory TRUE return value.
#
1;
#############################################################################
# POD documentation...
#
__END__
=head1 NAME
Mozilla::LDAP::Entry.pm - Object class to hold one LDAP entry.
=head1 SYNOPSIS
use Mozilla::LDAP::Conn;
use Mozilla::LDAP::Entry;
=head1 ABSTRACT
The LDAP::Conn object is used to perform LDAP searches, updates, adds and
deletes. All such functions works on LDAP::Entry objects only. All
modifications and additions you'll do to an LDAP entry, will be done
through this object class.
=head1 DESCRIPTION
The LDAP::Entry object class is built on top of the Tie::Hash standard
object class. This gives us several powerful features, the main one being
to keep track of what is changing in the LDAP entry. This makes it very
easy to write LDAP clients that needs to update/modify entries, since
you'll just do the changes, and this object class will take care of the
rest.
We define local functions for STORE, FETCH, DELETE, EXISTS, FIRSTKEY and
NEXTKEY in this object class, and inherit the rest from the super
class. Overloading these specific functions is how we can keep track of
what is changing in the entry, which turns out to be very convenient. We
can also easily "loop" over the attribute types, ignoring internal data,
or deleted attributes.
Most of the methods here either return the requested LDAP value, or a
status code. The status code (either 0 or 1) indicates the failure or
success of a certain operation. 0 (False) meaning the operation failed,
and a return code of 1 (True) means complete success.
One thing to remember is that in LDAP, attribute names are case
insensitive. All methods in this class are aware of this, and will convert
all attribute name arguments to lower case before performing any
operations. This does not mean that the values are case insensitive. On
the contrary, all values are considered case sensitive by this module,
even if the LDAP server itself treats it as a CIS attribute.
=head1 OBJECT CLASS METHODS
The LDAP::Entry class implements many methods you can use to access and
modify LDAP entries. It is strongly recommended that you use this API as
much as possible, and avoid using the internals of the class
directly. Failing to do so may actually break the functionality.
=head2 Creating a new entry
To create a completely new entry, use the B<new> method, for instance
$entry = new Mozilla::LDAP::Entry()
$entry->setDN("uid=leif,ou=people,dc=netscape,dc=com");
$entry->{objectclass} = [ "top", "person", "inetOrgPerson" ];
$entry->addValue("cn", "Leif Hedstrom");
$entry->addValue("sn", "Hedstrom");
$entry->addValue("givenName", "Leif");
$entry->addValue("mail", "leif@netscape.com);
$conn->add($entry);
This is the minimum requirements for an LDAP entry. It must have a DN, and
it must have at least one objectclass. As it turns out, by adding the
I<person> and I<inetOrgPerson> classes, we also must provide some more
attributes, like I<CN> and I<SN>. This is because the object classes have
these attributes marked as "required", and we'd get a schema violation
without those values.
In the example above we use both native API methods to add values, and
setting an attribute entire value set directly. Note that the value set is
a pointer to an array, and not the array itself. In the example above, the
object classes are set using an anonymous array, which the API handles
properly. It's important to be aware that the attribute value list is
indeed a pointer.
Finally, as you can see there's only only one way to add new LDAP entries,
and it's called add(). It normally takes an LDAP::Entry object instance as
argument, but it can also be called with a regular hash array if so
desired.
=head2 Adding and removing attributes and values
This is the main functionality of this module. Use these methods to do any
modifications and updates to your LDAP entries.
=over 13
=item B<addDNValue>
Just like B<addValue>, except this method assume the value is a DN
attribute. For instance
$dn = "uid=Leif, dc=Netscape, dc=COM";
$entry->addDNValue("uniqueMember", $dn);
will only add the DN for "uid=leif" if it does not exist as a DN in the
uniqueMember attribute.
=item B<addValue>
Add a value to an attribute. If the attribute value already exists, or we
couldn't add the value for any other reason, we'll return FALSE (0),
otherwise we return TRUE (1). The first two arguments are the attribute
name, and the value to add.
The optional third argument is a flag, indicating that we want to add the
attribute without checking for duplicates. This is useful if you know the
values are unique already, or if you perhaps want to allow duplicates for
a particular attribute. To add a CN to an existing entry/attribute, do:
$entry->addValue("cn", "Leif Hedstrom");
=item B<attrModified>
This is an internal function, that can be used to force the API to
consider an attribute (value) to have been modified. The only argument is
the name of the attribute. In almost all situation, you never, ever,
should call this. If you do, please contact the developers, and as us to
fix the API. Example
$entry->attrModified("cn");
=item B<copy>
Copy the value of one attribute to another. Requires at least two
arguments. The first argument is the name of the attribute to copy, and
the second argument is the name of the new attribute to copy to. The new
attribute can not currently exist in the entry, else the copy will fail.
There is an optional third argument (a boolean flag), which, when set to
1, will force an
override and copy to the new attribute even if it already exists. Returns TRUE if the copy
was successful.
$entry->copy("cn", "description");
=item B<exists>
Return TRUE if the specified attribute is defined in the LDAP entry. This
is useful to know if an entry has a particular attribute, regardless of
the value. For instance:
if ($entry->exists("jpegphoto")) { # do something special }
=item B<getDN>
Return the DN for the entry. For instance
print "The DN is: ", $entry->getDN(), "\n";
Just like B<setDN>, this method also has an optional argument, which
indicates we should normalize the DN before returning it to the caller.
=item B<getValues>
Returns an entire array of values for the attribute specified. Note that
this returns an array, and not a pointer to an array. This method is
deprecated, use B<values> instead.
=item B<hasValue>
Return TRUE or FALSE if the attribute has the specified value. A typical
usage is to see if an entry is of a certain object class, e.g.
if ($entry->hasValue("objectclass", "person", 1)) { # do something }
The (optional) third argument indicates if the string comparison should be
case insensitive or not, and the (optional) fourth argument indicats
wheter we should normalize the string as if it was a DN. The first two
arguments are the name and value of the attribute, respectively.
=item B<hasDNValue>
Exactly like B<hasValue>, except we assume the attribute values are DN
attributes.
=item B<isAttr>
This method can be used to decide if an attribute name really is a valid
LDAP attribute in the current entry. Use of this method is fairly limited,
but could potentially be useful. Usage is like previous examples, like
if ($entry->isAttr("cn")) { # do something }
The code section will only be executed if these criterias are true:
1. The name of the attribute is a non-empty string.
2. The name of the attribute does not begin, and end, with an
underscore character (_).
2. The attribute has one or more values in the entry.
=item B<isDeleted>
This is almost identical to B<isModified>, except it tests if an attribute
has been deleted. You use it the same way as above, like
if (! $entry->isDeleted("cn")) { # do something }
=item B<isModified>
This is a somewhat more useful method, which will return the internal
modification status of a particular attribute. The argument is the name of
the attribute, and the return value is True or False. If the attribute has
been modified, in any way, we return True (1), otherwise we return False
(0). For example:
if ($entry->isModified("cn")) { # do something }
=item B<matchValue>
This is very similar to B<hasValue>, except it does a regular expression
match instead of a full string match. It takes the same arguments,
including the optional third argument to specify case insensitive
matching. The usage is identical to the example for hasValue, e.g.
if ($entry->matchValue("objectclass", "pers", 1)) { # do something }
=item B<matchDNValue>
Like B<matchValue>, except the attribute values are considered being DNs.
=item B<move>
Identical to the copy method, except the original attribute is
deleted once the move to the new attribute is complete.
$entry->move("cn", "sn");
=item B<printLDIF>
Print the entry in a format called LDIF (LDAP Data Interchange
Format, RFC xxxx). An example of an LDIF entry is:
dn: uid=leif,ou=people,dc=netscape,dc=com
objectclass: top
objectclass: person
objectclass: inetOrgPerson
uid: leif
cn: Leif Hedstrom
mail: leif@netscape.com
The above would be the result of
$entry->printLDIF();
If you need to write to a file, open and then select() it.
For more useful LDIF functionality, check out the
Mozilla::LDAP::LDIF.pm module.
=item B<remove>
This will remove the entire attribute, including all it's values, from the
entry. The only argument is the name of the attribute to remove. Let's say
you want to nuke all I<mailAlternateAddress> values (i.e. the entire
attribute should be removed from the entry):
$entry->remove("mailAlternateAddress");
=item B<removeValue>
Remove a value from an attribute, if it exists. Of course, if the
attribute has no such value, we won't try to remove it, and instead return
a False (0) status code. The arguments are the name of the attribute, and
the particular value to remove. Note that values are considered case
sensitive, so make sure you preserve case properly. An example is:
$entry->removeValue("objectclass", "nscpPerson");
=item B<removeDNValue>
This is almost identical to B<removeValue>, except it will normalize the
attribute values before trying to remove them. This is useful if you know
that the attribute is a DN value, but perhaps the values are not cosistent
in all LDAP entries. For example
$dn = "uid=Leif, dc=Netscape, dc=COM";
$entry->removeDNValue("owner", $dn);
will remove the owner "uid=leif,dc=netscape,dc=com", no matter how it's
capitalized and formatted in the entry.
=item B<setDN>
Set the DN to the specified value. Only do this on new entries, it will
not work well if you try to do this on an existing entry. If you wish to
rename an entry, use the Mozilla::Conn::modifyRDN method instead.
Eventually we'll provide a complete "rename" method. To set the DN for a
newly created entry, we can do
$entry->setDN("uid=leif,ou=people,dc=netscape,dc=com");
There is an optional third argument, a boolean flag, indicating that we
should normalize the DN before setting it. This will assure a consistent
format of your DNs.
=item B<setValues>
Set the specified attribute to the new value (or values), overwriting
whatever old values it had before. This is a little dangerous, since you
can lose attribute values you didn't intend to remove. Therefore, it's
usually recommended to use B<removeValue()> and B<setValues()>. This
method is deprecated, use B<values> instead.
=item B<size>
Return the number of values for a particular attribute. For instance
$entry->{cn} = [ "Leif Hedstrom", "The Swede" ];
$numVals = $entry->size("cn");
This will set C<$numVals> to two (2). The only argument is the name of the
attribute, and the return value is the size of the value array.
=item B<values>
This is the get/set method for manipulating an entire set of values for a
particular attribute. The first argument is the attribute you wish to set
or get, and the optional second (and so forth) arguments is the list of
attribute values to set.
To get the values from the I<CN> attribute, just do
@vals = $entry->values("CN");
To set some attributes entire set of values, you can do
$entry->values("cn", "Leif Hedstrom", "The Swede");
$entry->values("mail", @mailAddresses);
or if it's a single value attribute,
$entry->values("uidNumber", "12345");
The only important thing to remember is that the optional value arguments
must be array elements (or an array), not a pointer to an array (or an
anonymous array).
=back
=head2 Deleting entries
To delete an LDAP entry from the LDAP server, you have to use the
B<delete> method from the Mozilla::LDAP::Conn module. It will actually
delete any entry, if you provide an legitimate DN.
=head2 Renaming entries
Again, there's no functionality in this object class to rename the entry
(i.e. changing it's DN). For now, there is a way to modify the RDN
component of a DN through the Mozilla::LDAP::Conn module, with
B<modifyRDN>. Eventually we hope to have a complete B<rename> method,
which should be capable of renaming any entry, in any way, including
moving it to a different part of the DIT (Directory Information Tree).
=head1 EXAMPLES
There are plenty of examples to look at, in the examples directory. We are
adding more examples every day (almost).
=head1 INSTALLATION
Installing this package is part of the Makefile supplied in the
package. See the installation procedures which are part of this package.
=head1 AVAILABILITY
This package can be retrieved from a number of places, including:
http://www.mozilla.org/directory/
Your local CPAN server
=head1 CREDITS
Most of this code was developed by Leif Hedstrom, Netscape Communications
Corporation.
=head1 BUGS
None. :)
=head1 SEE ALSO
L<Mozilla::LDAP::Conn>, L<Mozilla::LDAP::API>, and of course L<Perl>.
=cut

View File

@@ -1,387 +0,0 @@
#############################################################################
# $Id: Utils.pm,v 1.13.2.3 2000-10-05 22:42:05 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s): Leif Hedstrom
# Michelle Wyner
#
# DESCRIPTION
# Lots of Useful Little Utilities, for LDAP related operations.
#
#############################################################################
package Mozilla::LDAP::Utils;
use Mozilla::LDAP::API 2.0 qw(:constant);
use Mozilla::LDAP::Conn;
use Exporter;
use strict;
use vars qw($VERSION @ISA %EXPORT_TAGS);
@ISA = qw(Exporter);
$VERSION = "2.0";
%EXPORT_TAGS = (
all => [qw(normalizeDN
isUrl
printEntry
printentry
encodeBase64
decodeBase64
str2Scope
askPassword
ldapArgs
unixCrypt
userCredentials
answer)]
);
# Add Everything in %EXPORT_TAGS to @EXPORT_OK
Exporter::export_ok_tags('all');
#############################################################################
# Normalize the DN string (first argument), and return the new, normalized,
# string (DN). This is useful to make sure that two syntactically
# identical DNs compare (eq) as the same string.
#
sub normalizeDN
{
my ($dn) = @_;
my (@vals);
return "" unless (defined($dn) && ($dn ne ""));
@vals = Mozilla::LDAP::API::ldap_explode_dn(lc $dn, 0);
return join(",", @vals);
}
#############################################################################
# Checks if a string is a properly formed LDAP URL.
#
sub isURL
{
return ldap_is_ldap_url($_[0]);
}
#############################################################################
# Print an entry, in LDIF format. This is sort of obsolete, we encourage
# you to use the :;LDAP::LDIF class instead.
#
sub printEntry
{
my $entry = $_[0];
my ($attr);
local $_;
print "dn: ", $entry->{"dn"},"\n";
foreach $attr (@{$entry->{"_oc_order_"}})
{
next if ($attr =~ /^_.+_$/);
next if $entry->{"_${attr}_deleted_"};
foreach (@{$entry->{$attr}})
{
print "$attr: $_\n";
}
}
print "\n";
}
*printentry = \*printEntry;
#############################################################################
# Perform Base64 encoding, this is based on MIME::Base64.pm, written
# by Gisle Aas <gisle@aas.no>. If possible, use the MIME:: package instead.
#
sub encodeBase64
{
my ($res) = "";
my ($eol) = "$_[1]";
my ($padding);
pos($_[0]) = 0; # ensure start at the beginning
while ($_[0] =~ /(.{1,45})/gs) {
$res .= substr(pack('u', $1), 1);
chop($res);
}
$res =~ tr|` -_|AA-Za-z0-9+/|; # `# help emacs
$padding = (3 - length($_[0]) % 3) % 3;
$res =~ s/.{$padding}$/'=' x $padding/e if $padding;
if (length $eol) {
$res =~ s/(.{1,76})/$1$eol/g;
}
return $res;
}
#############################################################################
# Perform Base64 decoding, this is based on MIME::Base64.pm, written
# by Gisle Aas <gisle@aas.no>. If possible, use the MIME:: package instead.
#
sub decodeBase64
{
my ($str) = shift;
my ($res) = "";
my ($len);
$str =~ tr|A-Za-z0-9+=/||cd;
Carp::croak("Base64 decoder requires string length to be a multiple of 4")
if length($str) % 4;
$str =~ s/=+$//; # remove padding
$str =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format
while ($str =~ /(.{1,60})/gs)
{
$len = chr(32 + length($1)*3/4);
$res .= unpack("u", $len . $1 ); # uudecode
}
return $res;
}
#############################################################################
# Convert a "human" readable string to an LDAP scope value
#
sub str2Scope
{
my ($str) = $_[0];
return $str if ($str =~ /^[0-9]+$/);
if ($str =~ /^sub/i)
{
return LDAP_SCOPE_SUBTREE;
}
elsif ($str =~ /^base/i)
{
return LDAP_SCOPE_BASE;
}
elsif ($str =~ /^one/i)
{
return LDAP_SCOPE_ONELEVEL;
}
# Default...
return LDAP_SCOPE_SUBTREE;
}
#############################################################################
# Ask for a password, without displaying it on the TTY.
#
sub askPassword
{
my ($prompt) = shift;
my ($hasReadKey) = 0;
eval "use Term::ReadKey";
$hasReadKey=1 unless ($@);
print "LDAP password: " if $prompt;
if ($hasReadKey)
{
ReadMode(2);
chop($_ = ReadLine(0));
ReadMode(0);
}
else
{
system('/bin/stty -echo');
chop($_ = <STDIN>);
system('/bin/stty echo');
}
print "\n";
return $_;
}
#############################################################################
# Handle some standard LDAP options, and construct a nice little structure
# that we can use later on. We really should have some appropriate defaults,
# perhaps from an Mozilla::LDAP::Config module.
#
sub ldapArgs
{
my ($bind, $base) = @_;
my (%ld);
$main::opt_v = $main::opt_n if defined($main::opt_n);
$main::opt_p = LDAPS_PORT if (!defined($main::opt_p) &&
defined($main::opt_P) &&
($main::opt_P ne ""));
$ld{"host"} = $main::opt_h || "ldap";
$ld{"port"} = $main::opt_p || LDAP_PORT;
$ld{"base"} = $main::opt_b || $base || $ENV{'LDAP_BASEDN'};
$ld{"root"} = $ld{"base"};
$ld{"bind"} = $main::opt_D || $bind || "";
$ld{"pswd"} = $main::opt_w || "";
$ld{"cert"} = $main::opt_P || "";
$ld{"scope"} = (defined($main::opt_s) ? $main::opt_s : LDAP_SCOPE_SUBTREE);
if (($ld{"bind"} ne "") && ($ld{"pswd"} eq ""))
{
$ld{pswd} = askPassword(1);
}
return %ld;
}
#############################################################################
# Create a Unix-type password, using the "crypt" function. A random salt
# is always generated, perhaps it should be an optional argument?
#
sub unixCrypt
{
my ($ascii) =
"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
my ($salt) = substr($ascii, rand(62), 1) . substr($ascii, rand(62), 1);
srand(time ^ $$);
crypt($_[0], $salt);
}
#############################################################################
# Try to find a user to bind as, and possibly ask for the password. Pass
# a pointer to the hash array with LDAP parameters to this function.
#
sub userCredentials
{
my ($ld) = @_;
my ($conn, $entry, $pswd, $search);
if ($ld->{"bind"} eq "")
{
my ($base) = $ld->{"base"} || $ld->{"root"};
$conn = new Mozilla::LDAP::Conn($ld);
die "Could't connect to LDAP server " . $ld->{"host"} unless $conn;
$search = "(&(objectclass=inetOrgPerson)(uid=$ENV{USER}))";
$entry = $conn->search($base, "subtree", $search, 0, ("uid"));
return 0 if (!$entry || $conn->nextEntry());
$conn->close();
$ld->{"bind"} = $entry->getDN();
}
if ($ld->{"pswd"} eq "")
{
$ld->{"pswd"} = Mozilla::LDAP::Utils::askPassword(1);
}
}
#############################################################################
# Ask a Y/N question, return "Y" or "N".
#
sub answer
{
die "Default string must be Y or N."
unless (($_[0] eq "Y") || ($_[0] eq "N"));
chop($_ = <STDIN>);
return $_[0] if /^$/;
return "Y" if /^[yY]/;
return "N" if /^[nN]/;
}
#############################################################################
# Mandatory TRUE return value.
#
1;
#############################################################################
# POD documentation...
#
__END__
=head1 NAME
Mozilla::LDAP::Utils.pm - Collection of useful little utilities.
=head1 SYNOPSIS
use Mozilla::LDAP::Utils;
=head1 ABSTRACT
=head1 DESCRIPTION
=head1 OBJECT CLASS METHODS
=over 13
=item B<normalizeDN>
This function will remove all extraneous white spaces in the DN, and also
change all upper case characters to lower case. The only argument is the
DN string to normalize, and the return value is the new, clean DN.
=back
=head1 EXAMPLES
There are plenty of examples to look at, in the examples directory. We are
adding more examples every day (almost).
=head1 INSTALLATION
Installing this package is part of the Makefile supplied in the
package. See the installation procedures which are part of this package.
=head1 AVAILABILITY
This package can be retrieved from a number of places, including:
http://www.mozilla.org/directory/
Your local CPAN server
=head1 CREDITS
Most of this code was developed by Leif Hedstrom, Netscape Communications
Corporation.
=head1 BUGS
None. :)
=head1 SEE ALSO
L<Mozilla::LDAP::Conn>, L<Mozilla::LDAP::Entry>, L<Mozilla::LDAP::API>, and
of course L<Perl>.
=cut

View File

@@ -1,954 +0,0 @@
/*
******************************************************************************
* $Id: constant.h,v 1.7.6.2 2000-10-05 22:22:16 leif%netscape.com Exp $
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.1 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is PerLDAP. The Initial Developer of the Original
* Code is Netscape Communications Corp. and Clayton Donley. Portions
* created by Netscape are Copyright (C) Netscape Communications
* Corp., portions created by Clayton Donley are Copyright (C) Clayton
* Donley. All Rights Reserved.
*
* Contributor(s): Leif Hedstrom <leif@perldap.org>
* Kevin McCarthy <kevin@perldap.org>
* DESCRIPTION
* Constants.
*
*****************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
#include "EXTERN.h"
#include "perl.h"
#include "XSUB.h"
#ifdef __cplusplus
}
#endif
#include <ldap.h>
static int
not_here(s)
char *s;
{
croak("%s not implemented on this architecture", s);
return -1;
}
double
constant(name, arg)
char *name;
int arg;
{
errno = 0;
if (name[0] == 'L' && name[1] == 'D' && name[2] == 'A' && name[3] == 'P'
&& name[4] == '_')
{
switch (name[5]) {
case 'A':
if (strEQ(name, "LDAP_ADMINLIMIT_EXCEEDED"))
#ifdef LDAP_ADMINLIMIT_EXCEEDED
return LDAP_ADMINLIMIT_EXCEEDED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_AFFECTS_MULTIPLE_DSAS"))
#ifdef LDAP_AFFECTS_MULTIPLE_DSAS
return LDAP_AFFECTS_MULTIPLE_DSAS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_ALIAS_DEREF_PROBLEM"))
#ifdef LDAP_ALIAS_DEREF_PROBLEM
return LDAP_ALIAS_DEREF_PROBLEM;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_ALIAS_PROBLEM"))
#ifdef LDAP_ALIAS_PROBLEM
return LDAP_ALIAS_PROBLEM;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_ALREADY_EXISTS"))
#ifdef LDAP_ALREADY_EXISTS
return LDAP_ALREADY_EXISTS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_AUTH_METHOD_NOT_SUPPORTED"))
#ifdef LDAP_AUTH_METHOD_NOT_SUPPORTED
return LDAP_AUTH_METHOD_NOT_SUPPORTED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_AUTH_NONE"))
#ifdef LDAP_AUTH_NONE
return LDAP_AUTH_NONE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_AUTH_SASL"))
#ifdef LDAP_AUTH_SASL
return LDAP_AUTH_SASL;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_AUTH_SIMPLE"))
#ifdef LDAP_AUTH_SIMPLE
return LDAP_AUTH_SIMPLE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_AUTH_UNKNOWN"))
#ifdef LDAP_AUTH_UNKNOWN
return LDAP_AUTH_UNKNOWN;
#else
goto not_there;
#endif
break;
case 'B':
if (strEQ(name, "LDAP_BUSY"))
#ifdef LDAP_BUSY
return LDAP_BUSY;
#else
goto not_there;
#endif
break;
case 'C':
if (strEQ(name, "LDAP_CACHE_CHECK"))
#ifdef LDAP_CACHE_CHECK
return LDAP_CACHE_CHECK;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CACHE_LOCALDB"))
#ifdef LDAP_CACHE_LOCALDB
return LDAP_CACHE_LOCALDB;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CACHE_POPULATE"))
#ifdef LDAP_CACHE_POPULATE
return LDAP_CACHE_POPULATE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CHANGETYPE_ADD"))
#ifdef LDAP_CHANGETYPE_ADD
return LDAP_CHANGETYPE_ADD;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CHANGETYPE_ANY"))
#ifdef LDAP_CHANGETYPE_ANY
return LDAP_CHANGETYPE_ANY;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CHANGETYPE_DELETE"))
#ifdef LDAP_CHANGETYPE_DELETE
return LDAP_CHANGETYPE_DELETE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CHANGETYPE_MODDN"))
#ifdef LDAP_CHANGETYPE_MODDN
return LDAP_CHANGETYPE_MODDN;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CHANGETYPE_MODIFY"))
#ifdef LDAP_CHANGETYPE_MODIFY
return LDAP_CHANGETYPE_MODIFY;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CLIENT_LOOP"))
#ifdef LDAP_CLIENT_LOOP
return LDAP_CLIENT_LOOP;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_COMPARE_FALSE"))
#ifdef LDAP_COMPARE_FALSE
return LDAP_COMPARE_FALSE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_COMPARE_TRUE"))
#ifdef LDAP_COMPARE_TRUE
return LDAP_COMPARE_TRUE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CONFIDENTIALITY_REQUIRED"))
#ifdef LDAP_CONFIDENTIALITY_REQUIRED
return LDAP_CONFIDENTIALITY_REQUIRED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CONNECT_ERROR"))
#ifdef LDAP_CONNECT_ERROR
return LDAP_CONNECT_ERROR;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_CONSTRAINT_VIOLATION"))
#ifdef LDAP_CONSTRAINT_VIOLATION
return LDAP_CONSTRAINT_VIOLATION;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_DECODING_ERROR"))
#ifdef LDAP_DECODING_ERROR
return LDAP_DECODING_ERROR;
#else
goto not_there;
#endif
break;
case 'D':
if (strEQ(name, "LDAP_DEREF_ALWAYS"))
#ifdef LDAP_DEREF_ALWAYS
return LDAP_DEREF_ALWAYS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_DEREF_FINDING"))
#ifdef LDAP_DEREF_FINDING
return LDAP_DEREF_FINDING;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_DEREF_NEVER"))
#ifdef LDAP_DEREF_NEVER
return LDAP_DEREF_NEVER;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_DEREF_SEARCHING"))
#ifdef LDAP_DEREF_SEARCHING
return LDAP_DEREF_SEARCHING;
#else
goto not_there;
#endif
break;
case 'E':
if (strEQ(name, "LDAP_ENCODING_ERROR"))
#ifdef LDAP_ENCODING_ERROR
return LDAP_ENCODING_ERROR;
#else
goto not_there;
#endif
break;
case 'F':
if (strEQ(name, "LDAP_FILTER_ERROR"))
#ifdef LDAP_FILTER_ERROR
return LDAP_FILTER_ERROR;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_FILT_MAXSIZ"))
#ifdef LDAP_FILT_MAXSIZ
return LDAP_FILT_MAXSIZ;
#else
goto not_there;
#endif
break;
case 'I':
if (strEQ(name, "LDAP_INAPPROPRIATE_AUTH"))
#ifdef LDAP_INAPPROPRIATE_AUTH
return LDAP_INAPPROPRIATE_AUTH;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_INAPPROPRIATE_MATCHING"))
#ifdef LDAP_INAPPROPRIATE_MATCHING
return LDAP_INAPPROPRIATE_MATCHING;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_INSUFFICIENT_ACCESS"))
#ifdef LDAP_INSUFFICIENT_ACCESS
return LDAP_INSUFFICIENT_ACCESS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_INVALID_CREDENTIALS"))
#ifdef LDAP_INVALID_CREDENTIALS
return LDAP_INVALID_CREDENTIALS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_INVALID_DN_SYNTAX"))
#ifdef LDAP_INVALID_DN_SYNTAX
return LDAP_INVALID_DN_SYNTAX;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_INVALID_SYNTAX"))
#ifdef LDAP_INVALID_SYNTAX
return LDAP_INVALID_SYNTAX;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_IS_LEAF"))
#ifdef LDAP_IS_LEAF
return LDAP_IS_LEAF;
#else
goto not_there;
#endif
break;
case 'L':
if (strEQ(name, "LDAP_LOCAL_ERROR"))
#ifdef LDAP_LOCAL_ERROR
return LDAP_LOCAL_ERROR;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_LOOP_DETECT"))
#ifdef LDAP_LOOP_DETECT
return LDAP_LOOP_DETECT;
#else
goto not_there;
#endif
break;
case 'M':
if (strEQ(name, "LDAP_MOD_ADD"))
#ifdef LDAP_MOD_ADD
return LDAP_MOD_ADD;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_MOD_BVALUES"))
#ifdef LDAP_MOD_BVALUES
return LDAP_MOD_BVALUES;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_MOD_DELETE"))
#ifdef LDAP_MOD_DELETE
return LDAP_MOD_DELETE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_MOD_REPLACE"))
#ifdef LDAP_MOD_REPLACE
return LDAP_MOD_REPLACE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_MORE_RESULTS_TO_RETURN"))
#ifdef LDAP_MORE_RESULTS_TO_RETURN
return LDAP_MORE_RESULTS_TO_RETURN;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_MSG_ALL"))
#ifdef LDAP_MSG_ALL
return LDAP_MSG_ALL;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_MSG_ONE"))
#ifdef LDAP_MSG_ONE
return LDAP_MSG_ONE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_MSG_RECEIVED"))
#ifdef LDAP_MSG_RECEIVED
return LDAP_MSG_RECEIVED;
#else
goto not_there;
#endif
break;
case 'N':
if (strEQ(name, "LDAP_NAMING_VIOLATION"))
#ifdef LDAP_NAMING_VIOLATION
return LDAP_NAMING_VIOLATION;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NOT_ALLOWED_ON_NONLEAF"))
#ifdef LDAP_NOT_ALLOWED_ON_NONLEAF
return LDAP_NOT_ALLOWED_ON_NONLEAF;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NOT_ALLOWED_ON_RDN"))
#ifdef LDAP_NOT_ALLOWED_ON_RDN
return LDAP_NOT_ALLOWED_ON_RDN;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NOT_SUPPORTED"))
#ifdef LDAP_NOT_SUPPORTED
return LDAP_NOT_SUPPORTED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NO_LIMIT"))
#ifdef LDAP_NO_LIMIT
return LDAP_NO_LIMIT;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NO_MEMORY"))
#ifdef LDAP_NO_MEMORY
return LDAP_NO_MEMORY;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NO_OBJECT_CLASS_MODS"))
#ifdef LDAP_NO_OBJECT_CLASS_MODS
return LDAP_NO_OBJECT_CLASS_MODS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NO_RESULTS_RETURNED"))
#ifdef LDAP_NO_RESULTS_RETURNED
return LDAP_NO_RESULTS_RETURNED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NO_SUCH_ATTRIBUTE"))
#ifdef LDAP_NO_SUCH_ATTRIBUTE
return LDAP_NO_SUCH_ATTRIBUTE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_NO_SUCH_OBJECT"))
#ifdef LDAP_NO_SUCH_OBJECT
return LDAP_NO_SUCH_OBJECT;
#else
goto not_there;
#endif
break;
case 'O':
if (strEQ(name, "LDAP_OBJECT_CLASS_VIOLATION"))
#ifdef LDAP_OBJECT_CLASS_VIOLATION
return LDAP_OBJECT_CLASS_VIOLATION;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPERATIONS_ERROR"))
#ifdef LDAP_OPERATIONS_ERROR
return LDAP_OPERATIONS_ERROR;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_CACHE_ENABLE"))
#ifdef LDAP_OPT_CACHE_ENABLE
return LDAP_OPT_CACHE_ENABLE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_CACHE_FN_PTRS"))
#ifdef LDAP_OPT_CACHE_FN_PTRS
return LDAP_OPT_CACHE_FN_PTRS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_CACHE_STRATEGY"))
#ifdef LDAP_OPT_CACHE_STRATEGY
return LDAP_OPT_CACHE_STRATEGY;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_CLIENT_CONTROLS"))
#ifdef LDAP_OPT_CLIENT_CONTROLS
return LDAP_OPT_CLIENT_CONTROLS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_DEREF"))
#ifdef LDAP_OPT_DEREF
return LDAP_OPT_DEREF;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_DESC"))
#ifdef LDAP_OPT_DESC
return LDAP_OPT_DESC;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_DNS"))
#ifdef LDAP_OPT_DNS
return LDAP_OPT_DNS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_DNS_FN_PTRS"))
#ifdef LDAP_OPT_DNS_FN_PTRS
return LDAP_OPT_DNS_FN_PTRS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_ERROR_NUMBER"))
#ifdef LDAP_OPT_ERROR_NUMBER
return LDAP_OPT_ERROR_NUMBER;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_ERROR_STRING"))
#ifdef LDAP_OPT_ERROR_STRING
return LDAP_OPT_ERROR_STRING;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_HOST_NAME"))
#ifdef LDAP_OPT_HOST_NAME
return LDAP_OPT_HOST_NAME;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_IO_FN_PTRS"))
#ifdef LDAP_OPT_IO_FN_PTRS
return LDAP_OPT_IO_FN_PTRS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_MEMALLOC_FN_PTRS"))
#ifdef LDAP_OPT_MEMALLOC_FN_PTRS
return LDAP_OPT_MEMALLOC_FN_PTRS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_PREFERRED_LANGUAGE"))
#ifdef LDAP_OPT_PREFERRED_LANGUAGE
return LDAP_OPT_PREFERRED_LANGUAGE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_PROTOCOL_VERSION"))
#ifdef LDAP_OPT_PROTOCOL_VERSION
return LDAP_OPT_PROTOCOL_VERSION;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_REBIND_ARG"))
#ifdef LDAP_OPT_REBIND_ARG
return LDAP_OPT_REBIND_ARG;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_REBIND_FN"))
#ifdef LDAP_OPT_REBIND_FN
return LDAP_OPT_REBIND_FN;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_RECONNECT"))
#ifdef LDAP_OPT_RECONNECT
return LDAP_OPT_RECONNECT;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_REFERRALS"))
#ifdef LDAP_OPT_REFERRALS
return LDAP_OPT_REFERRALS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_REFERRAL_HOP_LIMIT"))
#ifdef LDAP_OPT_REFERRAL_HOP_LIMIT
return LDAP_OPT_REFERRAL_HOP_LIMIT;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_RESTART"))
#ifdef LDAP_OPT_RESTART
return LDAP_OPT_RESTART;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_RETURN_REFERRALS"))
#ifdef LDAP_OPT_RETURN_REFERRALS
return LDAP_OPT_RETURN_REFERRALS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_SERVER_CONTROLS"))
#ifdef LDAP_OPT_SERVER_CONTROLS
return LDAP_OPT_SERVER_CONTROLS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_SIZELIMIT"))
#ifdef LDAP_OPT_SIZELIMIT
return LDAP_OPT_SIZELIMIT;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_SSL"))
#ifdef LDAP_OPT_SSL
return LDAP_OPT_SSL;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_THREAD_FN_PTRS"))
#ifdef LDAP_OPT_THREAD_FN_PTRS
return LDAP_OPT_THREAD_FN_PTRS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OPT_TIMELIMIT"))
#ifdef LDAP_OPT_TIMELIMIT
return LDAP_OPT_TIMELIMIT;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_OTHER"))
#ifdef LDAP_OTHER
return LDAP_OTHER;
#else
goto not_there;
#endif
break;
case 'P':
if (strEQ(name, "LDAP_PARAM_ERROR"))
#ifdef LDAP_PARAM_ERROR
return LDAP_PARAM_ERROR;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_PARTIAL_RESULTS"))
#ifdef LDAP_PARTIAL_RESULTS
return LDAP_PARTIAL_RESULTS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_PORT"))
#ifdef LDAP_PORT
return LDAP_PORT;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_PORT_MAX"))
#ifdef LDAP_PORT_MAX
return LDAP_PORT_MAX;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_PROTOCOL_ERROR"))
#ifdef LDAP_PROTOCOL_ERROR
return LDAP_PROTOCOL_ERROR;
#else
goto not_there;
#endif
break;
case 'R':
if (strEQ(name, "LDAP_REFERRAL"))
#ifdef LDAP_REFERRAL
return LDAP_REFERRAL;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_REFERRAL_LIMIT_EXCEEDED"))
#ifdef LDAP_REFERRAL_LIMIT_EXCEEDED
return LDAP_REFERRAL_LIMIT_EXCEEDED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RESULTS_TOO_LARGE"))
#ifdef LDAP_RESULTS_TOO_LARGE
return LDAP_RESULTS_TOO_LARGE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_ADD"))
#ifdef LDAP_RES_ADD
return LDAP_RES_ADD;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_ANY"))
#ifdef LDAP_RES_ANY
return LDAP_RES_ANY;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_BIND"))
#ifdef LDAP_RES_BIND
return LDAP_RES_BIND;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_COMPARE"))
#ifdef LDAP_RES_COMPARE
return LDAP_RES_COMPARE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_DELETE"))
#ifdef LDAP_RES_DELETE
return LDAP_RES_DELETE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_EXTENDED"))
#ifdef LDAP_RES_EXTENDED
return LDAP_RES_EXTENDED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_MODIFY"))
#ifdef LDAP_RES_MODIFY
return LDAP_RES_MODIFY;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_MODRDN"))
#ifdef LDAP_RES_MODRDN
return LDAP_RES_MODRDN;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_RENAME"))
#ifdef LDAP_RES_RENAME
return LDAP_RES_RENAME;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_SEARCH_ENTRY"))
#ifdef LDAP_RES_SEARCH_ENTRY
return LDAP_RES_SEARCH_ENTRY;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_SEARCH_REFERENCE"))
#ifdef LDAP_RES_SEARCH_REFERENCE
return LDAP_RES_SEARCH_REFERENCE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_RES_SEARCH_RESULT"))
#ifdef LDAP_RES_SEARCH_RESULT
return LDAP_RES_SEARCH_RESULT;
#else
goto not_there;
#endif
break;
case 'S':
if (strEQ(name, "LDAP_SASL_BIND_IN_PROGRESS"))
#ifdef LDAP_SASL_BIND_IN_PROGRESS
return LDAP_SASL_BIND_IN_PROGRESS;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SASL_SIMPLE"))
#ifdef LDAP_SASL_SIMPLE
return LDAP_SASL_SIMPLE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SCOPE_BASE"))
#ifdef LDAP_SCOPE_BASE
return LDAP_SCOPE_BASE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SCOPE_ONELEVEL"))
#ifdef LDAP_SCOPE_ONELEVEL
return LDAP_SCOPE_ONELEVEL;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SCOPE_SUBTREE"))
#ifdef LDAP_SCOPE_SUBTREE
return LDAP_SCOPE_SUBTREE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SECURITY_NONE"))
#ifdef LDAP_SECURITY_NONE
return LDAP_SECURITY_NONE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SERVER_DOWN"))
#ifdef LDAP_SERVER_DOWN
return LDAP_SERVER_DOWN;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SIZELIMIT_EXCEEDED"))
#ifdef LDAP_SIZELIMIT_EXCEEDED
return LDAP_SIZELIMIT_EXCEEDED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SORT_CONTROL_MISSING"))
#ifdef LDAP_SORT_CONTROL_MISSING
return LDAP_SORT_CONTROL_MISSING;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_STRONG_AUTH_NOT_SUPPORTED"))
#ifdef LDAP_STRONG_AUTH_NOT_SUPPORTED
return LDAP_STRONG_AUTH_NOT_SUPPORTED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_STRONG_AUTH_REQUIRED"))
#ifdef LDAP_STRONG_AUTH_REQUIRED
return LDAP_STRONG_AUTH_REQUIRED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_SUCCESS"))
#ifdef LDAP_SUCCESS
return LDAP_SUCCESS;
#else
goto not_there;
#endif
break;
case 'T':
if (strEQ(name, "LDAP_TIMELIMIT_EXCEEDED"))
#ifdef LDAP_TIMELIMIT_EXCEEDED
return LDAP_TIMELIMIT_EXCEEDED;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_TIMEOUT"))
#ifdef LDAP_TIMEOUT
return LDAP_TIMEOUT;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_TYPE_OR_VALUE_EXISTS"))
#ifdef LDAP_TYPE_OR_VALUE_EXISTS
return LDAP_TYPE_OR_VALUE_EXISTS;
#else
goto not_there;
#endif
break;
case 'U':
if (strEQ(name, "LDAP_UNAVAILABLE"))
#ifdef LDAP_UNAVAILABLE
return LDAP_UNAVAILABLE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_UNAVAILABLE_CRITICAL_EXTENSION"))
#ifdef LDAP_UNAVAILABLE_CRITICAL_EXTENSION
return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_UNDEFINED_TYPE"))
#ifdef LDAP_UNDEFINED_TYPE
return LDAP_UNDEFINED_TYPE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_UNWILLING_TO_PERFORM"))
#ifdef LDAP_UNWILLING_TO_PERFORM
return LDAP_UNWILLING_TO_PERFORM;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_URL_ERR_BADSCOPE"))
#ifdef LDAP_URL_ERR_BADSCOPE
return LDAP_URL_ERR_BADSCOPE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_URL_ERR_MEM"))
#ifdef LDAP_URL_ERR_MEM
return LDAP_URL_ERR_MEM;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_URL_ERR_NODN"))
#ifdef LDAP_URL_ERR_NODN
return LDAP_URL_ERR_NODN;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_URL_ERR_NOTLDAP"))
#ifdef LDAP_URL_ERR_NOTLDAP
return LDAP_URL_ERR_NOTLDAP;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_URL_ERR_PARAM"))
#ifdef LDAP_URL_ERR_PARAM
return LDAP_URL_ERR_PARAM;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_URL_OPT_SECURE"))
#ifdef LDAP_URL_OPT_SECURE
return LDAP_URL_OPT_SECURE;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_USER_CANCELLED"))
#ifdef LDAP_USER_CANCELLED
return LDAP_USER_CANCELLED;
#else
goto not_there;
#endif
break;
case 'V':
if (strEQ(name, "LDAP_VERSION"))
#ifdef LDAP_VERSION
return LDAP_VERSION;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_VERSION1"))
#ifdef LDAP_VERSION1
return LDAP_VERSION1;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_VERSION2"))
#ifdef LDAP_VERSION2
return LDAP_VERSION2;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_VERSION3"))
#ifdef LDAP_VERSION3
return LDAP_VERSION3;
#else
goto not_there;
#endif
if (strEQ(name, "LDAP_VERSION_MAX"))
#ifdef LDAP_VERSION_MAX
return LDAP_VERSION_MAX;
#else
goto not_there;
#endif
break;
}
} else {
if (strEQ(name, "LDAPS_PORT"))
#ifdef LDAPS_PORT
return LDAPS_PORT;
#else
goto not_there;
#endif
}
errno = EINVAL;
return 0;
not_there:
errno = ENOENT;
return 0;
}

View File

@@ -1,44 +0,0 @@
1999-09-05 Leif Hedstrom <leif@perldap.org>
* changes2ldif.pl, modattr.pl, qsearch.pl, rmentry.pl,
ldappasswd.pl, monitor.pl, rand_mods.pl, tabdump.pl, lfinger.pl,
psoftsync.pl, rename.pl: Changed headers.
* qsearch.pl: Added support for the "-v" flag, and changed all the
calls to search() reflect new argument passing syntax.
1999-06-30 Leif Hedstrom <leif@netscape.com>
* rmentry.pl: Added support for "-p".
1999-01-05 Leif Hedstrom <leif@netscape.com>
* psoftsync.pl (delAttr): Fixed annoying bug where I missed to
"my" $entry.
1999-01-04 Leif Hedstrom <leif@netscape.com>
* modattr.pl: Bug fixes for handling bad cases better (like
missing attribute, adding empty values etc).
1998-12-11 Leif Hedstrom <leif@netscape.com>
* modattr.pl: Modified slightly to enable the rebind proc.
1998-08-03 Leif Hedstrom <leif@netscape.com>
* psoftsync.pl: New file, also merged in some modules from
LdapUtils.pm, to make sure this works. NOTE: This script currently
doesn't work, since all "modify" operations are horked.
1998-07-30 Leif Hedstrom <leif@netscape.com>
* tabdump.pl: Actually works!
* ldappasswd.pl: Cleaned out some code, and moved it over to the
::Utils module.
1998-07-29 Leif Hedstrom <leif@netscape.com>
* qsearch.pl: First working version.

View File

@@ -1,117 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: changes2ldif.pl,v 1.2.4.2 2000-10-06 18:23:19 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Search the changelog, and produce an LDIF file suitable for ldapmodify
# for instance. This should be merged into LDIF.pm eventually.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
use strict;
no strict "vars";
#################################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "changes2ldif";
$USAGE = "$APPNAM [-nv] -b base -h host -D bind -w pswd -P cert [min [max]]";
#################################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('nvb:h:D:p:s:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
$ld{root} = "cn=changelog" if (!defined($ld{root}) || $ld{root} eq "");
#################################################################################
# Instantiate an LDAP object, which also binds to the LDAP server.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
#################################################################################
# Create the search filter.
#
$min = $ARGV[$[];
$max = $ARGV[$[ + 1];
if ($min ne "")
{
if ($max ne "")
{
$search = "(&(changenumber>=$min)(changenumber<=$max))";
}
else
{
$search = "(changenumber>=$min)";
}
}
else
{
$search = "(changenumber=*)";
}
#################################################################################
# Do the searches, and print the results.
#
$entry = $conn->search($ld{root}, "ONE", "$search");
while ($entry)
{
print "dn: ", $entry->{targetdn}[0], "\n";
$type = $entry->{changetype}[0];
print "changetype: $type\n";
if ($type =~ /modify/i)
{
# Should we filter out modifiersname and modifytimestamp ? We do chop
# off the trailing \0 though.
chop($entry->{changes}[0]);
print $entry->{changes}[0], "\n";
}
elsif ($type =~ /add/i)
{
print $entry->{changes}[0], "\n";
}
else
{
print "\n";
}
$entry = $conn->nextEntry;
}
#################################################################################
# Close the connection.
#
$ld{conn}->close if $ld{conn};

View File

@@ -1,103 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: ldappasswd.pl,v 1.6.6.2 2000-10-06 18:23:19 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# This is an LDAP version of the normal passwd/yppasswd command found
# on most Unix systems. Note that this will only use the {crypt}
# encryption/hash algorithm (at this point).
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
#############################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "ldappasswd";
$USAGE = "$APPNAM [-nv] -b base -h host -D bind -w pswd -P cert search ...";
@ATTRIBUTES = ("uid", "userpassword");
#############################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('nvb:s:h:D:w:P:')) {
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
Mozilla::LDAP::Utils::userCredentials(\%ld) unless $opt_n;
#############################################################################
# Ask for the new password, and confirm it's correct.
#
do
{
print "New password: ";
$new = Mozilla::LDAP::Utils::askPassword();
print "New password (again): ";
$new2 = Mozilla::LDAP::Utils::askPassword();
print "Passwords didn't match, try again!\n\n" if ($new ne $new2);
} until ($new eq $new2);
print "\n";
$crypted = Mozilla::LDAP::Utils::unixCrypt("$new");
#############################################################################
# Now do all the searches, one by one. If there are no search criteria, we
# will change the password for the user running the script.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
foreach $search ($#ARGV >= $[ ? @ARGV : $ld{bind})
{
$entry = $conn->search($search, "subtree", "ALL", 0, @ATTRIBUTES);
$entry = $conn->search($ld{root}, "subtree", $search, 0, @ATTRIBUTES)
unless $entry;
print "No such user: $search\n" unless $entry;
while ($entry)
{
$entry->{userpassword} = ["{crypt}" . $crypted];
print "Changing password for: $entry->{dn}\n" if $opt_v;
if (!$opt_n)
{
$conn->update($entry);
$conn->printError() if $conn->getErrorCode();
}
$entry = $conn->nextEntry();
}
}
#############################################################################
# Close the connection.
#
$conn->close if $conn;

View File

@@ -1,127 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: lfinger.pl,v 1.10.6.2 2000-10-06 18:23:20 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# "finger" version using LDAP information (using RFC 2307 objectclass).
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
#############################################################################
# Constants, shouldn't have to edit these... The HIDE mechanism is a very
# Netscape internal specific feature. We use this objectclass to mark some
# entries to be "hidden", and some of our applications will honor this. With
# more recent versions of the Directory Server this can be accomplished more
# effectively with appropriate ACI/ACLs.
#
$APPNAM = "lfinger";
$USAGE = "$APPNAM -m -b base -h host -D bind -w pswd -P cert user_info";
@ATTRIBUTES = ("uid", "cn", "homedirectory", "loginshell", "pager",
"telephonenumber", "facsimiletelephonenumber", "mobile");
$HIDE = "(objectclass=nscphidethis)";
#############################################################################
# Print a "finger" entry.
#
sub printIt
{
my($entry) = @_;
print "Login name: $entry->{uid}[0]";
print " " x (39 - 11 - length($entry->{uid}[0]));
print "In real life: $entry->{cn}[0]\n";
if ($entry->{homedirectory}[0] || $entry->{loginshell}[0])
{
print "Directory: $entry->{homedirectory}[0]";
print " " x (39 - 10 - length($entry->{homedirectory}[0]));
print "Shell: $entry->{loginshell}[0]\n";
}
if ($entry->{telephonenumber}[0] || $entry->{pager}[0])
{
print "Phone: $entry->{telephonenumber}[0]";
print " " x (39 - 6 - length($entry->{telephonenumber}[0]));
print "Pager: $entry->{pager}[0]\n";
}
if ($entry->{mobile}[0] || $entry->{facsimiletelephonenumber}[0])
{
print "Mobile: $entry->{mobile}[0]";
print " " x (39 - 7 - length($entry->{mobile}[0]));
print "Fax: $entry->{facsimiletelephonenumber}[0]\n";
}
print "\n";
}
#############################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('mb:h:D:p:w:P:') || !defined($ARGV[$[]))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
$user=$ARGV[$[];
#############################################################################
# Instantiate an LDAP object, which also binds to the LDAP server.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
#############################################################################
# Ok, lets generate the filter, and do the search!
#
if ($opt_m)
{
$search = "(&(uid=$user)(!$HIDE))";
}
else
{
$search = "(&(|(cn=*$user*)(uid=*$user*)(telephonenumber=*$user*))(!$HIDE))";
}
$entry = $conn->search($ld{root}, "subtree", $search, 0, @ATTRIBUTES);
$conn->printError() if $conn->getErrorCode();
while($entry)
{
printIt($entry);
$entry = $conn->nextEntry();
}
#############################################################################
# Close the connection.
#
$conn->close if $conn;

View File

@@ -1,330 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: modattr.pl,v 1.8.4.2 2000-10-06 18:23:21 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# This script can be used to do a number of different modification
# operations on a script. Like adding/deleting values, or entire
# attributes.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
use strict;
no strict "vars";
#############################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "modattr";
$USAGE = "$APPNAM [-dnvW] -b base -h host -D bind -w pswd -P cert attr=value filter";
#############################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('adnvWb:h:D:p:s:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
Mozilla::LDAP::Utils::userCredentials(\%ld) unless $opt_n;
#############################################################################
# Let's process the changes requested, and commit them unless the "-n"
# option was given.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
$conn->setDefaultRebindProc($ld{bind}, $ld{pswd});
($change, $search) = @ARGV;
if (($change eq "") || ($search eq ""))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
($attr, $value) = split(/=/, $change, 2);
$entry = $conn->search($ld{root}, $ld{scope}, $search);
while ($entry)
{
$changed = 0;
if ($opt_d)
{
if (defined $entry->{$attr})
{
if ($value)
{
$changed = $entry->removeValue($attr, $value);
if ($changed && $opt_v)
{
print "Removed value from ", $entry->getDN(), "\n" if $opt_v;
}
}
else
{
delete $entry->{$attr};
print "Deleted attribute $attr for ", $entry->getDN(), "\n" if $opt_v;
$changed = 1;
}
}
else
{
print "No attribute values for: $attr\n";
}
}
else
{
if (!defined($value) || !$value)
{
print "No value provided for the attribute $attr\n";
}
elsif ($opt_a)
{
$changed = $entry->addValue($attr, $value);
if ($changed && $opt_v)
{
print "Added attribute to ", $entry->getDN(), "\n" if $opt_v;
}
}
else
{
$entry->setValue($attr, $value);
$changed = 1;
print "Set attribute for ", $entry->getDN(), "\n" if $opt_v;
}
}
if ($changed && ! $opt_n)
{
$conn->update($entry);
$conn->printError() if $conn->getErrorCode();
}
$entry = $conn->nextEntry();
}
#############################################################################
# Close the connection.
#
$conn->close if $conn;
#############################################################################
# POD documentation...
#
__END__
=head1 NAME
modattr - Modify an attribute for one or more LDAP entries
=head1 SYNOPSIS
modattr [-adnvW] -b base -h host -D bind DN -w pwd -P cert attr=value filter
=head1 ABSTRACT
This command line utility can be used to modify one attribute for one or
more LDAP entries. As simple as this sounds, this turns out to be a very
common operation. For instance, let's say you want to change "mailHost"
for all users on a machine named I<dredd>, to be I<judge>. With this
script all you have to do is
modattr mailHost=judge '(mailHost=dredd)'
=head1 DESCRIPTION
There are four primary operations that can be made with this utility:
=over 4
=item *
Set an attribute to a (single) specified value.
=item *
Add a value to an attribute (for multi-value attributes).
=item *
Delete a value from an attribute. If it's the last value (or if it's a
single value), this will remove the entire attribute.
=item *
Delete an entire attribute, even if it has multiple values.
=back
The first three requires an option of the form B<attr=value>, while the
last one only takes the name of the attribute as the option. The last
argument is always an LDAP search filter, specifying which entries the
operation should be applied to.
=head1 OPTIONS
All but the first two command line options for this tool are standard LDAP
options, to set parameters for the LDAP connection. The two new options
are I<-a> and I<-d> to add and remove attribute values.
Without either of these two options specified (they are both optional),
the default action is to set the attribute to the specified value. That
will effectively remove any existing values for this attribute.
=over 12
=item -a
Specify that the operation is an I<add>, to add a value to the
attribute. If there is no existing value for this attribute, we'll create
a new attribute, otherwise we add the new value if it's not already there.
=item -d
Delete the attribute value, or the entire attribute if there's no value
specified. As you can see this option has two forms, and it's function
depends on the last arguments. Be careful here, if you forget to specify
the value to delete, you will remove all of them.
=item -h <host>
Name of the LDAP server to connect to.
=item -p <port>
TCP port for the LDAP connection.
=item -b <DN>
Base DN for the search
=item -D <bind>
User (DN) to bind as. We support a few convenience shortcuts here, like
I<root>, I<user> and I<repl>.
=item -w <passwd>
This specifies the password to use when connecting to the LDAP
server. This is strongly discouraged, and without this option the script
will ask for the password interactively.
=item -s <scope>
Search scope, default is I<sub>, the other possible values are I<base> and
I<one>. You can also specify the numeric scopes, I<0>, I<1> or I<2>.
=item -P
Use SSL for the LDAP connection, using the specified cert.db file for
certificate information.
=item -n
Don't do anything, only show the changes that would have been made. This
is very convenient, and can save you from embarrassing mistakes.
=item -v
Verbose output.
=back
The last two arguments are special for this script. The first
argument specifies the attribute (and possibly the value) to operate on,
and the last argument is a properly formed LDAP search filter.
=head1 EXAMPLES
We'll give one example for each of the four operations this script can
currently handle. Since the script itself is quite flexible, you'll
probably find you can use this script for a lot of other applications, or
call it from other scripts. Note that we don't specify any LDAP specific
options here, we assume you have configured your defaults properly.
To set the I<description> attribute for user "leif", you would do
modattr 'description=Company Swede' '(uid=leif)'
The examples shows how to use this command without either of the I<-a> or
the I<-d> argument. To add an e-mail alias (alternate address) to the same
user, you would do
modattr -a 'mailAlternateAddress=theSwede@netscape.com' '(uid=leif)'
To remove an object class from all entries which uses it, you could do
modattr -d 'objectclass=dummyClass' '(objectclass=dummyClass)'
This example is not great, since unless you've assured that no entries
uses any of the attributes in this class, you'll get schema
violations. But don't despair, you can use this tool to clean up all
entries first! To completely remove all usage of an attribute named
I<dummyAttr>, you'd simply do
modattr -d dummyAttr '(dummyAttr=*)'
This shows the final format of this command, notice how we don't specify a
value, to assure that the entire attribute is removed. This is potentially
dangerous, so again be careful.
=head1 INSTALLATION
In order to use this script, you'll need Perl version 5.004 or later, the
LDAP SDK, and also the LDAP Perl module (aka PerLDAP). Once you've installed
these packages, just copy this file to where you keep your admin binaries,
e.g. /usr/local/bin.
In order to get good performance, you should make sure you have indexes on
the attributes you typically use with this script. Our experience has been
that in most cases the standard indexes in the Directory Server are
sufficient, e.g. I<CN>, I<UID> and I<MAIL>.
=head1 AVAILABILITY
This package can be retrieved from a number of places, including:
http://www.mozilla.org/directory/
Your local CPAN server
=head1 CREDITS
This little tool was developed internally at Netscape, by Leif Hedstrom.
=head1 BUGS
None, of course...
=head1 SEE ALSO
L<Mozilla::LDAP::API> and L<Perl>
=cut

View File

@@ -1,66 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: monitor.pl,v 1.2.6.2 2000-10-06 18:23:21 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Ask the directory server for it's monitor entry, to see some
# performance and usage stats.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
#################################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "monitor";
$USAGE = "$APPNAM [-nv] -b base -h host -D bind -w pswd -P cert";
#################################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('b:h:D:p:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs("", "cn=monitor");
#################################################################################
# Instantiate an LDAP object, which also binds to the LDAP server, and then
# do the simple search.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
$entry = $conn->search($ld{root}, "base", "objectclass=*");
Mozilla::LDAP::Utils::printEntry($entry)
if ($entry);
#################################################################################
# Close the connection.
#
$conn->close if $conn;

View File

@@ -1,614 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: psoftsync.pl,v 1.5.4.2 2000-10-06 18:23:22 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Synchronise some LDAP info with a PeopleSoft "dump". This "dump" file
# is a "tab" separated file, as generated by an SQL utility on the
# Oracle server.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
#############################################################################
# Local configurations, check these out . Note that SYNCS and ORDER has to
# have the same fields, this is because the hash array doesn't preserve
# the order of it's entries... :-( The "codes" are bit fields, where the
# three LSB are used as
#
# 1 Force the update, even if attribute is empty (i.e. delete it)
# 2 The attribute is the base for a DN (e.g. "manager").
# 4 The attribute should be deleted if the user is not in PeopleSoft.
# 8 Don't warn if the attribute is missing in the Psoft file (-W option).
# 16 Always delete this attribute in the PeopleSoft entry.
# 32 Delete this attribute if the account has "expired".
#
%SYNCS = (
"nscpharold" => 1 + 4,
"uid" => 0,
"" => 0,
"" => 0,
"employeenumber" => 1 + 4 + 32,
"departmentnumber" => 1 + 4,
"" => 0,
"" => 0,
"" => 0,
"manager" => 1 + 2,
"title" => 1 + 4 + 16 + 32,
"ou" => 1 + 4 + 32,
"businesscategory" => 1 + 4 + 32,
"employeetype" => 0,
"nscppersonexpdate" => 1 + 8
);
@ORDER = (
"nscpharold",
"uid",
"",
"",
"employeenumber",
"departmentnumber",
"",
"",
"",
"manager",
"title",
"ou",
"businesscategory",
"employeetype",
"nscppersonexpdate"
);
# This is used for mapping the employeeType attribute into a readable format.
%EMPCODES = (
"A" => "Applicant",
"C" => "Contractor",
"E" => "Employee",
"O" => "OEM Partner",
"T" => "Interim",
"V" => "Vendor"
);
# Expiration policy for other attributes, the EXPDELAY is a convenience
# default setting.
$EXPDELAY = 24 * 7;
%EXPIRES = (
"carlicense" => $EXPDELAY,
"mailautoreplymode" => $EXPDELAY,
"mailautoreplytext" => $EXPDELAY,
"mailforwardingaddress" => $EXPDELAY,
"facsimiletelephonenumber" => $EXPDELAY
);
$NOTYPE = "Unknown";
$DELIMITER = "%%";
$SENDMAIL = "/usr/lib/sendmail";
$SEARCH = "(&(uid=*)(!(objectclass=pseudoAccount)))";
$MAILTO = "leif\@netscape.com";
#$LDAP_DEBUG = 1;
#############################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "psoftsync";
$USAGE = "$APPNAM [-nvW] -b base -h host -D bind -w passwd -P cert PS_file";
@ATTRIBUTES = uniq(@ORDER);
push(@ATTRIBUTES, "objectclass");
$TODAY = `/usr/bin/date '+%Y%m%d'`;
chop($TODAY);
#############################################################################
# Print an error for the PeopleSoft data. Note that we use the "__XXX__" fields
# here, to avoid the problem when an attribute is "expired" or modified.
#
sub psoftError
{
my ($str, $entry) = @_;
print "Error: $str: ";
print $entry->key(), " (";
print $entry->{__employeenumber__}, ", ";
print $entry->{__employeetype__}, ", ";
print $entry->{__departmentnumber__}, ")\n";
}
#############################################################################
# Read in a PeopleSoft file, and create all the entries.
#
sub readDump
{
my ($file) = @_;
my (@info, %entries);
my $val;
if (!open(PSOFT, $file))
{
print "Error: Can't read file $file\n";
exit(1);
}
while (<PSOFT>)
{
next unless /$DELIMITER/;
@info = split(/\s*%%\s*/);
$entry = new PsoftEntry($info[$[]);
foreach $attr (@ORDER)
{
$val = shift(@info);
next if ($attr eq "");
$entry->add($attr, $val, $SYNCS{$attr});
}
#
# Perhaps we should do some sanity checks here on the PeopleSoft data?
#
# Clean up some data if the user has expired ("best before...")
if ($entry->expired($entry->{nscppersonexpdate}))
{
foreach $attr (@ORDER)
{
next unless $attr;
delete($entry->{$attr}) if ($SYNCS{$attr} & 32);
}
}
if ($entry->{uid})
{
$entries{$entry->{uid}} = $entry;
}
elsif ($opt_W)
{
psoftError("No UID", $entry);
}
}
close(PSOFT);
return %entries;
}
#############################################################################
# Make a list "uniq", just like the Unix command.
#
sub uniq { # uniq(elements[])
my %tmp;
grep($tmp{$_}++, @_);
return sort(keys(%tmp));
}
#############################################################################
# Delete an attribute from an entry.
#
sub delAttr { # delAttr(ENTRY, ATTR)
my ($entry, $attr) = @_;
if (defined($entry->{$attr}))
{
$out->write("Deleted $attr for user: $entry->{uid}[0]") if $opt_v;
delete($entry->{$attr});
return 1;
}
return 0;
}
#############################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('nvMWb:h:D:p:s:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
Mozilla::LDAP::Utils::userCredentials(\%ld) unless $opt_n;
$out = new Mail();
if ($opt_M)
{
$out->set("to", $MAILTO);
$out->set("subject", "Hoth: PeopleSoft synchronization report");
}
else
{
$out->echo();
$out->nomail();
}
#############################################################################
# Read in all the PeopleSoft entries, and then instantiate an LDAP object,
# which also binds to the LDAP server.
#
%psoft = readDump(@ARGV[$[]);
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
#############################################################################
# Now process all the users, one by one.
#
$entry = $conn->search($ld{root}, "subtree", $SEARCH, 0, @ATTRIBUTES);
while ($entry)
{
$uid = $entry->{"uid"}[0];
$changed = 0;
$psent = $psoft{$uid};
if (!$psent)
{
print "Error: LDAP user $uid: No entry in PeopleSoft\n" if $opt_W;
foreach $attr (@ORDER)
{
next unless $attr;
$changed += delAttr($entry, $attr) if ($SYNCS{$attr} & 4);
}
if ($entry->{employeetype}[0] ne "$NOTYPE")
{
$entry->{employeetype} = ["$NOTYPE"];
$changed = 1;
$out->write("Set employeeType to $NOTYPE for user: $uid") if $opt_v;
}
}
else
{
$psent->handled(1);
foreach $attr (@ORDER)
{
next unless $attr;
if (!defined($psent->{$attr}) || ($psent->{$attr} eq ""))
{
$changed += delAttr($entry, $attr) if ($SYNCS{$attr} & 1);
}
elsif ($entry->{$attr}[0] ne $psent->{$attr})
{
$entry->{$attr} = [$psent->{$attr}];
$changed = 1;
$out->write("Set $attr to $psent->{$attr} for user: $uid") if $opt_v;
}
}
# Now handle the Expire date special case...
if ($psent->expired() ne "")
{
if ($entry->addValue("objectclass", "nscphidethis"))
{
$changed = 1;
$out->write("Expiring the user: $uid") if $opt_v;
}
# Expire other attributes, IFF the expire is over a certain
# treshhold (e.g. a week).
}
elsif ($entry->removeValue("objectclass", "nscphidethis"))
{
$changed = 1;
$out->write("Enabling the user: $uid") if $opt_v;
}
}
$conn->update($entry) if ($changed && ! $opt_n);
$entry = $conn->nextEntry();
}
#############################################################################
# Close the LDAP connection.
#
$conn->close if $conn;
#############################################################################
# Post process, figure out which PSoft entries have no entry in LDAP.
#
if ($opt_W)
{
foreach (keys(%psoft))
{
$ent=$psoft{$_};
psoftError("No LDAP entry", $ent) unless $ent->handled();
}
}
#############################################################################
# Package to an entry from the PeopleSoft database.
#
package PsoftEntry;
#############################################################################
# Creator.
#
sub new
{
my ($class, $key) = @_;
my $self = {};
bless $self, ref $class || $class;
$self->{__key__} = $key;
return $self;
}
#############################################################################
# Add an attribute/field to the entry.
#
sub add
{
my ($self, $attr, $val, $lev) = @_;
return if ($lev & 16);
$attr = lc $attr;
if ($attr eq "employeetype")
{
if (defined($main::EMPCODES{$val}))
{
$self->{$attr} = $main::EMPCODES{$val};
}
else
{
$self->{$attr} = $main::NOTYPE;
}
$self->{__employeetype__} = $val;
}
elsif (!defined($val) || ($val eq ""))
{
main::psoftError("No attribute $attr", $self)
if ($main::opt_W && ($lev & 1) && !($lev & 8));
}
else
{
$self->{$attr} = ($lev & 2) ? "uid=$val,$main::ld{root}" : $val;
$self->{"__${attr}__"} = $val;
}
}
#############################################################################
# Return the value for an attribute/field.
#
sub get
{
my ($self, $attr) = @_;
return $self->{$attr};
}
#############################################################################
# Mark the entry as "expired". If there is no "date" argument, we'll return
# the current entries expire status.
#
sub expired
{
my ($self, $date) = @_;
if ($date)
{
# Only expire entries with reasonable expire dates...
if (length($date) != 8)
{
main::psoftError("Bad expire date", $self) if $main::opt_W;
return 0;
}
if ($date lt $main::TODAY)
{
$self->{employeetype} = "$main::NOTYPE";
$self->{__expired__} = 1;
return 1;
}
}
return $self->{__expired__};
}
#############################################################################
# Mark the entry as "handled", i.e. it exists in LDAP.
#
sub handled
{
my ($self, $flag) = @_;
$self->{__handled__} = 1 if $flag;
return $self->{__handled__};
}
#############################################################################
# Return the "key" of this entry, typically the name field.
#
sub key
{
my ($self) = @_;
return $self->{__key__};
}
#################################################################################
# This sub-package will send mail to some recipients, IFF there is anything to
# send, or your force it to send. Note that the Subject doesn't qualify it to
# send a message (force it to send if you have to).
#
package Mail;
#################################################################################
# The constructor, which optionally takes the TO, FROM and SUBJECT.
#
sub new
{
my ($class, $to, $from, $subject) = @_;
my $self = {};
bless $self, ref $class || $class;
$self->{to} = $to || "root";
$self->{from} = $from || "ldap";
$self->{subject} = $subject || "Output from LDAP script\n";
@{$self->{message}} = ();
$self->{send} = 0;
$self->{nomail} = 0;
$self->{echo} = 0;
return $self;
}
#################################################################################
# Destructor, which will also send the message, if appropriate.
#
sub DESTROY
{
my ($self) = @_;
if ($self->{send} && !$self->{nomail})
{
$self->send();
$self->{send} = 0;
}
}
#################################################################################
# Set a field for this entry, e.g. From:, To: etc.
#
sub set
{
my ($self, $field, $string) = @_;
if ($field && $string)
{
$field = lc $field;
$self->{$field} = $string;
}
}
#################################################################################
# Add a line to the message, the argument is the string.
#
sub write
{
my ($self, $string) = @_;
if ($string ne "")
{
push(@{$self->{message}}, $string);
print "$string\n" if $self->{echo};
$self->{send}++;
}
}
#################################################################################
# Force the object to send the message, no matter if there's anything in the
# body or not.
#
sub force
{
my ($self) = @_;
$self->{send} = 1;
$self->{nomail} = 0;
}
#################################################################################
# Don't send the mail, this is the oppositte to "force...
#
sub nomail
{
my ($self) = @_;
$self->{send} = 0;
$self->{nomail} = 1;
}
#################################################################################
# Enable echo-mode, where we will also print everything to STDOUT.
#
sub echo
{
my ($self) = @_;
$self->{echo} = 1;
}
#################################################################################
# Actually send the message. This is automatically done by the DESTROY method,
# but we can force it to do it this way.
#
sub send
{
my ($self) = @_;
if ($self->{send} && !$self->{nomail})
{
open(MAILER, "|$main::SENDMAIL -t");
print MAILER "From: $self->{from}\n";
print MAILER "To: $self->{to}\n";
print MAILER "Subject: $self->{subject}\n\n";
foreach (@{$self->{message}})
{
print MAILER "$_\n";
}
print MAILER ".\n";
close(MAILER);
$self->{send} = 0;
}
}

View File

@@ -1,104 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: qsearch.pl,v 1.8.4.3 2000-10-06 18:23:23 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Quick Search, like ldapsearch, but in Perl. Look how simple it is.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
use strict;
no strict "vars";
#################################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "qsearch";
$USAGE = "$APPNAM -b base -h host -D bind -w pswd -P cert filter [attr...]";
#################################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('b:h:D:p:s:vw:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
#################################################################################
# Now do all the searches, one by one.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
foreach (@ARGV)
{
if (/\=/)
{
push(@srch, $_);
}
else
{
push(@attr, $_);
}
}
foreach $search (@srch)
{
if ($#attr >= $[)
{
$entry = $conn->search(basedn => $ld{base},
scope => $ld{scope},
filter => $search,
attributes => [ @attr ],
verbose => $opt_v);
}
else
{
$entry = $conn->search(basedn => $ld{base},
scope => $ld{scope},
filter => $search,
verbose => $opt_v);
}
print "Searched for `$search':\n\n";
$conn->printError() if $conn->getErrorCode();
while (defined($entry))
{
print "$entry";
$entry = $conn->nextEntry;
}
print "\n";
}
#################################################################################
# Close the connection.
#
$conn->close if $conn;

View File

@@ -1,140 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: rand_mods.pl,v 1.2.2.2 2000-10-06 18:23:24 leif%netscape.com Exp $
#
# The contents of this file are subject to the Netscape Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/NPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
# See the License for the specific language governing rights and
# limitations under the License.
#
# The Original Code is mozilla.org code.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are Copyright (C) 1998
# Netscape Communications Corporation. All Rights Reserved.
#
# Contributor(s):
#
# SYNOPSIS:
# Modify an attribute for one or more entries, or possibly delete it.
#
# USAGE:
# rand_mods [-adnvW] -b base -h host -D bind DN -w pwd -P cert filter
# loops attribute ...
#
#############################################################################
#############################################################################
# Modules we need. Note that we depend heavily on the Ldapp module,
# which needs to be built from the C code. It also requires an LDAP SDK.
#
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
use Carp;
use strict;
no strict "vars";
#############################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "rand_mods";
$USAGE = "$APPNAM [-dnvW] -b base -h host -D bind -w pswd filter loops attr ...";
#############################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('adnvWb:h:D:p:s:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
#############################################################################
# Instantiate an LDAP object, which also binds to the LDAP server.
#
if (!getopts('b:h:D:p:s:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
$conn = new Mozilla::LDAP::Conn(\%ld);
croak "Could't connect to LDAP server $ld{host}" unless $conn;
#############################################################################
# Parse some extra argumens
#
my $srch, $loop;
my (@attrs) = ("givenName", "sn");
if (! ($srch = shift(@ARGV)))
{
print "Usage: $APPNAME $USAGE\n";
exit;
}
$srch = "(&(!(objectclass=nscpHideThis))(uid=*))" if ($srch eq "");
if (! ($loops = shift(@ARGV)))
{
print "Usage: $APPNAME $USAGE\n";
exit;
}
@attrs = @ARGV if ($#ARGV > $[);
$num_attrs = $#attrs;
#############################################################################
# Find all the argument
#
my $num = 0;
$entry = $conn->search($ld{root}, $ld{scope}, $srch, 0, ("0.0"));
while ($entry)
{
push(@users, $entry->getDN());
$num++;
$entry = $conn->nextEntry();
}
print "Found $num users, randomizing changes now...\n";
srand(time ^ $$);
my $tmp, $tmp2, $dn, $loop2;
while ($loops--)
{
$dn = $users[rand($num)];
print "$loops loops left...\n" if (($loops % 100) == 0);
$entry = $conn->browse($dn, @attrs);
if ($entry)
{
$loop2 = $num_attrs + 1;
while ($loop2--)
{
$tmp = $entry->{$attrs[$loop2]}[0];
$tmp2 = rand($num_attrs);
$entry->{$attrs[$loop2]} = [ $entry->{$attrs[$tmp2]}[0] ];
$entry->{$attrs[$tmp2]} = [ $tmp] ;
$entry->printLDIF();
}
$conn->update($entry);
}
}

View File

@@ -1,97 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: rename.pl,v 1.4.4.2 2000-10-06 18:23:25 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Rename an LDAP entry, changing it's DN. Note that currently this only
# works with RDNs.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
#############################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "rename";
$USAGE = "$APPNAM [-nvI] -b base -h host -D bind -w pswd -P cert filter new_rdn";
#############################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('nvIb:h:D:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
Mozilla::LDAP::Utils::userCredentials(\%ld) unless $opt_n;
($search, $rdn) = @ARGV;
if (($search eq "") || ($rdn eq ""))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
#############################################################################
# Instantiate an LDAP object, which also binds to the LDAP server.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
$key = "Y" if $opt_I;
$entry = $conn->search($ld{root}, $ld{scope}, $search, 0, @ATTRIBUTES);
$conn->printError() if $conn->getErrorCode();
if (! $entry || $conn->nextEntry())
{
print "Error: The search did not return exactly one match, abort!\n";
exit;
}
if (! $opt_I)
{
print "Rename ", $entry->getDN(), " with $rdn [N]? ";
$key = Mozilla::LDAP::Utils::answer("N") unless $opt_I;
}
if ($key eq "Y")
{
# Note: I have to explicitly specify the original DN below, since the call
# to nextEntry() above blows the DN away from the ::Conn object.
if (! $opt_n)
{
$conn->modifyRDN($rdn, $entry->getDN());
$conn->printError() if $conn->getErrorCode();
}
print "Renamed $entry->{dn}\n" if $opt_v;
}
#################################################################################
# Close the connection.
#
$conn->close if $conn;

View File

@@ -1,94 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: rmentry.pl,v 1.5.2.2 2000-10-06 18:23:25 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Remove one or several LDAP objects. By default this tool is
# interactive, which can be disabled with the "-I" option (but
# please be careful...).
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
#################################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "rmentry";
$USAGE = "$APPNAM [-nvI] -b base -h host -p port -D bind -w pswd" .
"-P cert filter ...";
@ATTRIBUTES = ("uid");
#################################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('nvIb:h:p:D:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
Mozilla::LDAP::Utils::userCredentials(\%ld) unless $opt_n;
#################################################################################
# Do the search, and process all the entries.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
$key = "Y" if $opt_I;
foreach $search (@ARGV)
{
$entry = $conn->search($ld{root}, $ld{scope}, $search, 0, @ATTRIBUTES);
$conn->printError() if $conn->getErrorCode();
while ($entry)
{
if (! $opt_I)
{
print "Delete $entry->{dn} [N]? ";
$key = Mozilla::LDAP::Utils::answer("N") unless $opt_I;
}
if ($key eq "Y")
{
if (! $opt_n)
{
$conn->delete($entry);
$conn->printError() if $conn->getErrorCode();
}
print "Deleted $entry->{dn}\n" if $opt_v;
}
$entry = $conn->nextEntry();
}
}
#################################################################################
# Close the connection.
#
$conn->close if $conn;

View File

@@ -1,81 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: tabdump.pl,v 1.3.6.2 2000-10-06 18:23:26 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Generate a TAB separate "dump" of entries matching the search criteria,
# using the list of attributes specified.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
#################################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "tabdump";
$USAGE = "$APPNAM [-nv] -b base -h host -D bind -w pswd -P [-t <sep>] cert attr1,attr2,.. srch";
#################################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('nvb:h:D:p:s:w:P:t:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs();
$separator = (defined($opt_t) ? $opt_t : "\t");
$attributes = $ARGV[$[];
$search = $ARGV[$[ + 1];
die "Need to specify a list of attributes and the search filter.\n"
unless ($attributes && $search);
#################################################################################
# Do the searches, and produce the output.
#
$conn = new Mozilla::LDAP::Conn(\%ld);
die "Could't connect to LDAP server $ld{host}" unless $conn;
@attr = split(/,/, $attributes);
$entry = $conn->search($ld{root}, $ld{scope}, $search, 0, @attr);
$conn->printError() if $conn->getErrorCode();
while ($entry)
{
foreach (@attr)
{
print $entry->{$_}[0], $separator;
}
print "\n";
$entry = $conn->nextEntry;
}
#################################################################################
# Close the connection.
#
$conn->close if $conn;

View File

@@ -1,18 +0,0 @@
1999-08-26 Leif Hedstrom <leif@netscape.com>
* conn.pl: Cleaned up $entry tests (if defined($entry)).
1999-08-06 Leif Hedstrom <leif@netscape.com>
* conn.pl: Added support for browse() and compare().
1999-03-19 Leif Hedstrom <leif@netscape.com>
* conn.pl: Added test for add() with a hash array.
1999-01-05 Leif Hedstrom <leif@netscape.com>
* entry.pl: New script, to test all Entry:: methods.
* conn.pl: Added test for modifyRDN().

View File

@@ -1,4 +0,0 @@
print "This is not a real test, yet...\n";
print "1..1\n";
print "ok 1\n";

Binary file not shown.

View File

@@ -1,4 +0,0 @@
print "This is not a real test, yet...\n";
print "1..1\n";
print "ok 1\n";

View File

@@ -1,142 +0,0 @@
#!/usr/bin/perl5
#############################################################################
# $Id: entry.pl,v 1.2.4.2 2000-10-10 21:49:09 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Leif Hedstrom and Netscape Communications. Portions created
# by Leif are Copyright (C) Leif Hedstrom, portions created by Netscape
# are Copyright (C) Netscape Communications Corp. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Test most (all?) of the LDAP::Mozilla::Conn methods.
#
#############################################################################
use Getopt::Std; # To parse command line arguments.
use Mozilla::LDAP::Conn; # Main "OO" layer for LDAP
use Mozilla::LDAP::Utils; # LULU, utilities.
use Mozilla::LDAP::API;
use strict;
no strict "vars";
#################################################################################
# Configurations, modify these as needed.
#
$BIND = "uid=ldapadmin";
$BASE = "dc=ogre,dc=com";
$PEOPLE = "ou=ogres";
$GROUPS = "ou=groups";
$UID = "leif-test";
$CN = "test-group-1";
#################################################################################
# Constants, shouldn't have to edit these...
#
$APPNAM = "entry.pl";
$USAGE = "$APPNAM -b base -h host -D bind -w pswd -P cert";
#################################################################################
# Check arguments, and configure some parameters accordingly..
#
if (!getopts('b:h:D:p:s:w:P:'))
{
print "usage: $APPNAM $USAGE\n";
exit;
}
%ld = Mozilla::LDAP::Utils::ldapArgs($BIND, $BASE);
#################################################################################
# Get an LDAP connection
#
sub getConn
{
my $conn;
if ($main::reuseConn)
{
if (!defined($main::mainConn))
{
$main::mainConn = new Mozilla::LDAP::Conn(\%main::ld);
die "Could't connect to LDAP server $main::ld{host}"
unless $main::mainConn;
}
return $main::mainConn;
}
else
{
$conn = new Mozilla::LDAP::Conn(\%main::ld);
die "Could't connect to LDAP server $main::ld{host}" unless $conn;
}
return $conn;
}
#################################################################################
# Some small help functions...
#
sub dotPrint
{
my $str = shift;
print $str . '.' x (20 - length($str));
}
sub attributeEQ
{
my @a, @b;
my $i;
@a = @{$_[0]};
@b = @{$_[1]};
return 1 if (($#a < 0) && ($#b < 0));
return 0 unless ($#a == $#b);
@a = sort(@a);
@b = sort(@b);
for ($i = 0; $i <= $#a; $i++)
{
return 0 unless ($a[$i] eq $b[$i]);;
}
return 1; # We passed all the tests, we're ok.
}
#################################################################################
# Setup the test entries.
#
#$conn = getConn();
$conn = new Mozilla::LDAP::Conn(host => "localhost",
port => "389",
verbose => "1",
);
$entry = new Mozilla::LDAP::Entry(dn => "uid=leif,ou=people,dc=com",
cn => "Leif Hedstrom",
sn => ["Hedstrom",
"The Swede",
],
givenName => "Leif",
uid => "leif",
);
$entry2 = $conn->newEntry(dn => "foo",
cn => "bar",);

View File

@@ -1,4 +0,0 @@
print "This is not a real test, yet...\n";
print "1..1\n";
print "ok 1\n";

View File

@@ -1,4 +0,0 @@
print "This is not a real test, yet...\n";
print "1..1\n";
print "ok 1\n";

View File

@@ -1,4 +0,0 @@
print "This is not a real test, yet...\n";
print "1..1\n";
print "ok 1\n";

View File

@@ -1,280 +0,0 @@
#!/usr/bin/perl -w
#############################################################################
# $Id: api.pl,v 1.7.4.1 2000-10-06 18:17:31 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Netscape Communications Corp. and Clayton Donley. Portions
# created by Netscape are Copyright (C) Netscape Communications
# Corp., portions created by Clayton Donley are Copyright (C) Clayton
# Donley. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# api.pl - Test all LDAPv2 API function
# Author: Clayton Donley <donley@wwa.com>
#
# Performs all API calls directly in order to test for possible issues
# on a particular platform.
#
#############################################################################
use Mozilla::LDAP::API qw(:api :constant);
use strict;
my $BASE = "ou=Test,o=Test,c=US";
my $DN = "cn=Directory Manager";
my $PASS = "abcd1234";
my $HOST = "";
my $PORT = 389;
if (!$HOST)
{
print "Please edit the variables at the top of this file.\n";
exit -1;
}
print "\nPerLDAP API TestSuite\n";
print "\nNote: Failures in earlier tests will cause later tests to fail.\n";
print "\n";
my $howmany = 10;
# Initialize the Connection
{
my $ld = ldap_init($HOST,$PORT);
if ($ld <0)
{
print "init - Failed!\n";
die;
}
print "init - OK\n";
# Set an LDAP Session Option
if (ldap_set_option($ld,LDAP_OPT_PROTOCOL_VERSION,LDAP_VERSION3)
!= LDAP_SUCCESS)
{
print "set_option - Failed!\n";
} else {
print "set_option - OK\n";
}
# Get an LDAP Session Option
my $option;
ldap_get_option($ld,LDAP_OPT_REFERRALS,$option);
if ($option != 1)
{
print "get_option - Failed!\n";
} else {
print "get_option - OK\n";
}
# Anonymous Bind
if (ldap_simple_bind_s($ld,"","") != LDAP_SUCCESS)
{
print "anon_bind - Failed!\n";
} else {
print "anon_bind - OK\n";
}
# Authenticated Simple Bind
if (ldap_simple_bind_s($ld,$DN,$PASS) != LDAP_SUCCESS)
{
print "simple_bind - Failed!\n";
} else {
print "simple_bind - OK\n";
}
# Set Rebind Process
my $rebindproc = sub { return($DN,$PASS,LDAP_AUTH_SIMPLE); };
ldap_set_rebind_proc($ld,$rebindproc);
print "set_rebind - OK\n";
# Add an OrgUnit Entry
my $entry = {
"objectclass" => ["top","organizationalUnit"],
"ou" => "Test",
};
if (ldap_add_s($ld,$BASE,$entry) != LDAP_SUCCESS)
{
print "add_org - Failed!\n";
} else {
print "add_org - OK\n";
}
# Add People
foreach my $number (1..$howmany)
{
$entry = {
"objectclass" => ["top","person"],
"cn" => "Mozilla $number",
"sn" => ["$number"],
};
if (ldap_add_s($ld,"cn=Mozilla $number,$BASE",$entry)
!= LDAP_SUCCESS)
{
print "add_user_$number - Failed!\n";
} else {
print "add_user_$number - OK\n";
}
}
# Modify People
foreach my $number (1..$howmany)
{
$entry = {
"sn" => {"ab",["Test"]},
"telephoneNumber" => {"ab",[123.456]},
# "telephoneNumber" => "800-555-111$number",
};
if (ldap_modify_s($ld,"cn=Mozilla $number,$BASE",$entry)
!= LDAP_SUCCESS)
{
print "mod_user_$number - Failed!\n";
} else {
print "mod_user_$number - OK\n";
}
}
# Search People
my $filter = "(sn=Test)";
my $attrs = ["cn","sn"];
my $res;
if (ldap_search_s($ld,$BASE,LDAP_SCOPE_SUBTREE,$filter,$attrs,0,$res)
!= LDAP_SUCCESS)
{
print "search_user - Failed!\n";
} else {
print "search_user - OK\n";
}
# Count Results
if (ldap_count_entries($ld,$res) != $howmany)
{
print "count_res - Failed!\n";
} else {
print "count_res - OK\n";
}
# Sort Results
if (ldap_sort_entries($ld,$res,"sn") != LDAP_SUCCESS)
{
print "sort_ent - Failed!\n";
} else {
print "sort_ent - OK\n";
}
# Multisort Results
if (ldap_multisort_entries($ld,$res,["sn","telephoneNumber"]) != LDAP_SUCCESS)
{
print "multisort - Failed!\n";
} else {
print "multisort - OK\n";
}
# Get First Entry
my $ent = ldap_first_entry($ld,$res);
if (!$ent)
{
print "first_entry - Failed!\n";
} else {
print "first_entry - OK\n";
}
# Get Next Entry
$ent = ldap_next_entry($ld,$ent);
if (!$ent)
{
print "next_entry - Failed!\n";
} else {
print "next_entry - OK\n";
}
# Get DN
my $dn = ldap_get_dn($ld,$ent);
if (!$dn)
{
print "get_dn - Failed!\n";
} else {
print "get_dn - OK\n";
}
# Get First Attribute
my $ber;
my $attr = ldap_first_attribute($ld,$ent,$ber);
if (!$attr)
{
print "first_attr - Failed!\n";
} else {
print "first_attr - OK\n";
}
# Get Next Attribute
$attr = ldap_next_attribute($ld,$ent,$ber);
if (!$attr)
{
print "next_attr - Failed!\n";
} else {
print "next_attr - OK\n";
}
# Get Attribute Values
my @vals = ldap_get_values($ld,$ent,$attr);
if ($#vals < 0)
{
print "get_values - Failed!\n";
} else {
print "get_values - OK\n";
}
# Free structures pointed to by $ber and $res to prevent memory leak
ldap_ber_free($ber,1);
ldap_msgfree($res);
# Compare Attribute Values
foreach my $number (1..$howmany)
{
if(ldap_compare_s($ld,"cn=Mozilla $number,$BASE","sn",$number)
!= LDAP_COMPARE_TRUE)
{
print "comp_user_$number - Failed!\n";
} else {
print "comp_user_$number - OK\n";
}
}
# Delete Users
foreach my $number (1..$howmany)
{
if (ldap_delete_s($ld,"cn=Mozilla $number,$BASE") != LDAP_SUCCESS)
{
print "del_user_$number - Failed!\n";
} else {
print "del_user_$number - OK\n";
}
}
if (ldap_delete_s($ld,"$BASE") != LDAP_SUCCESS)
{
print "del_org - Failed!\n";
} else {
print "del_org - OK\n";
}
# Unbind
ldap_unbind($ld);
}

View File

@@ -1,131 +0,0 @@
#!/usr/bin/perl
#############################################################################
# $Id: search.pl,v 1.4.6.1 2000-10-06 18:17:31 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerlDAP. The Initial Developer of the Original
# Code is Netscape Communications Corp. and Clayton Donley. Portions
# created by Netscape are Copyright (C) Netscape Communications
# Corp., portions created by Clayton Donley are Copyright (C) Clayton
# Donley. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# Test the search capabilities of the API, similar to write.pl.
#
#############################################################################
use Mozilla::LDAP::API qw(:api :constant);
use strict;
my $ldap_host = "";
my $BASEDN = "o=Org,c=US";
my $filter = $ARGV[0];
if (!$ldap_host)
{
print "Edit the top portion of this file before continuing.\n";
exit -1;
}
my $attrs = [];
my ($ld,$result,$count);
##
## Initialize LDAP Connection
##
if (($ld = ldap_init($ldap_host,LDAP_PORT)) == -1)
{
die "Can not open LDAP connection to $ldap_host";
}
##
## Bind as DN, PASSWORD (NULL,NULL) on LDAP connection $ld
##
if (ldap_simple_bind_s($ld,"","") != LDAP_SUCCESS)
{
ldap_perror($ld,"bind_s");
die;
}
##
## ldap_search_s - Synchronous Search
##
if (ldap_search_s($ld,$BASEDN,LDAP_SCOPE_SUBTREE,$filter,$attrs,0,$result) != LDAP_SUCCESS)
{
ldap_perror($ld,"search_s");
die;
}
##
## ldap_count_entries - Count Matched Entries
##
if (($count = ldap_count_entries($ld,$result)) == -1)
{
ldap_perror($ld,"count_entry");
die;
}
##
## first_entry - Get First Matched Entry
## next_entry - Get Next Matched Entry
##
for (my $ent = ldap_first_entry($ld,$result); $ent; $ent = ldap_next_entry($ld,$ent))
{
##
## ldap_get_dn - Get DN for Matched Entries
##
my ($dn,$attr,@vals,$val,$ber);
if (($dn = ldap_get_dn($ld,$ent)) ne "")
{
print "dn: $dn\n";
} else {
ldap_perror($ld,"get_dn");
die;
}
for ($attr = ldap_first_attribute($ld,$ent,$ber); $attr; $attr = ldap_next_attribute($ld,$ent,$ber))
{
##
## ldap_get_values
##
@vals = ldap_get_values($ld,$ent,$attr);
if ($#vals >= 0)
{
foreach $val (@vals)
{
print "$attr: $val\n";
}
}
}
ldap_ber_free($ber,0);
}
ldap_msgfree($result);
##
## Unbind LDAP Connection
##
ldap_unbind($ld);

View File

@@ -1,110 +0,0 @@
#!/usr/bin/perl -w
#############################################################################
# $Id: write.pl,v 1.4.6.1 2000-10-06 18:17:32 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerlDAP. The Initial Developer of the Original
# Code is Netscape Communications Corp. and Clayton Donley. Portions
# created by Netscape are Copyright (C) Netscape Communications
# Corp., portions created by Clayton Donley are Copyright (C) Clayton
# Donley. All Rights Reserved.
#
# Contributor(s):
#
# DESCRIPTION
# write.pl - Test of LDAP Modify Operations in Perl5
# Author: Clayton Donley <donley@wwa.com>
#
# This utility is mostly to demonstrate all the write operations
# that can be done with LDAP through this PERL5 module.
#
#############################################################################
use strict;
use Mozilla::LDAP::API qw(:constant :api);
# This is the entry we will be adding. Do not use a pre-existing entry.
my $ENTRYDN = "cn=Test Guy, o=Org, c=US";
# This is the DN and password for an Administrator
my $ROOTDN = "cn=DSManager,o=Org,c=US";
my $ROOTPW = "";
my $ldap_server = "";
if (!$ldap_server)
{
print "Edit the top portion of this file before continuing.\n";
exit -1;
}
my $ld = ldap_init($ldap_server,LDAP_PORT);
if ($ld == -1)
{
die "Connection to LDAP Server Failed";
}
if (ldap_simple_bind_s($ld,$ROOTDN,$ROOTPW) != LDAP_SUCCESS)
{
ldap_perror($ld,"bind_s");
die;
}
my %testwrite = (
"cn" => "Test User",
"sn" => "User",
"givenName" => "Test",
"telephoneNumber" => "8475551212",
"objectClass" => ["top","person","organizationalPerson",
"inetOrgPerson"],
"mail" => "tuser\@my.org",
);
if (ldap_add_s($ld,$ENTRYDN,\%testwrite) != LDAP_SUCCESS)
{
ldap_perror($ld,"add_s");
die;
}
print "Entry Added.\n";
%testwrite = (
"telephoneNumber" => "7085551212",
"mail" => {"a",["Test_User\@my.org"]},
);
if (ldap_modify_s($ld,$ENTRYDN,\%testwrite) != LDAP_SUCCESS)
{
ldap_perror($ld,"modify_s");
die;
}
print "Entry Modified.\n";
#
# Delete the entry for $ENTRYDN
#
if (ldap_delete_s($ld,$ENTRYDN) != LDAP_SUCCESS)
{
ldap_perror($ld,"delete_s");
die;
}
print "Entry Deleted.\n";
# Unbind to LDAP server
ldap_unbind($ld);
exit;

View File

@@ -1,173 +0,0 @@
#############################################################################
# $Id: typemap,v 1.4.6.5 2000-10-05 22:19:24 leif%netscape.com Exp $
#
# The contents of this file are subject to the Mozilla Public License
# Version 1.1 (the "License"); you may not use this file except in
# compliance with the License. You may obtain a copy of the License at
# http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS IS"
# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
# License for the specific language governing rights and limitations
# under the License.
#
# The Original Code is PerLDAP. The Initial Developer of the Original
# Code is Netscape Communications Corp. and Clayton Donley. Portions
# created by Netscape are Copyright (C) Netscape Communications
# Corp., portions created by Clayton Donley are Copyright (C) Clayton
# Donley. All Rights Reserved.
#
# Contributor(s): Leif Hedstrom <leif@perldap.org>
# Kevin McCarthy <kevin@perldap.org>
# DESCRIPTION
# Typemap to declare XSUB data types.
#
# Notes:
# These are how the typemaps work within API.xs. Most are straightforward,
# but a few require special explanation, so if you hack API.xs you don't
# cause a memory leak (or can fix one)
#
# char *:
# INPUT:
# Changed the standard T_PV INPUT mapping to translate "undef"
# (PL_sv_undef) to NULL. I don't know if this will screw anything
# up - this needs to be tested CAREFULLY.
# OUTPUT:
# Most the of functions returning a char * malloc() the char *
# and return it. char * is mapped to a SvPv * on the way out.
# This *copies* the data from the char * to a new char *.
# These cases need to be freed in the CLEANUP section.
# Free the char * by calling ldap_memfree().
#
# char **:
# INPUT:
# When an avref of SvPv's is passed in, this is converted to a
# char **. The char ** as well as all the char * are malloc()ed
# inside avref2charptrptr().
# Therefore, you need to free this memory in the CLEANUP section.
# Do this by calling ldap_value_free().
# OUTPUT:
# No work is required. charptrptr2avref calls ldap_value_free for you.
#
# LDAPControl **:
# INPUT:
# When a SV or RV is passed in, the LDAPControl ** is malloc()ed.
# The LDAPControl * in the array are _not_ malloc()ed though - they
# are copied from the SvIv entries (which are pointers).
# Therefore, you need to free only the LDAPControl ** in the CLEANUP.
# Do this by calling Safefree()
# OUTPUT:
# No work required, the function calls Safefree() for you.
#
# struct berval:
# NOTE TODO:
# The input typemap for this currently uses na, which is a global
# variable, to hold the length of the string. This isn't threadsafe -
# needs to be changed eventually.
# INPUT:
# struct berval is directly translated to a SvPv variable in Perl.
# Although many functions expect a parameter of struct berval *, we
# are passing in a struct berval. It makes no sense to malloc()
# a struct berval just to have the parameter type of the XS function
# be struct berval *, therefore we use &var in the function
# declaration. This is 'cheating' but allows us to avoid malloc()ing
# and having to free the struct berval.
# OUTPUT:
# We do not use this for output. All functions seem to want
# to work with only struct berval *, so that is used for output
#
# struct berval *:
# INPUT:
# Don't use this for type input. Use struct berval &var instead.
# OUTPUT:
# All the functions returning a struct berval * seem take a parameter
# of type struct berval ** and modify the pointer. Therefore we
# have to convert this to a SvPv using the function. This function
# takes care of freeing the struct berval * using ber_bvfree().
#
# struct berval **:
# A few functions return struct berval ** - we don't have typemaps for
# those though. We use the macro RET_BVPP to convert it to an
# array of SvPv and return them on the stack. The original author of
# API.xs had some typemaps, but they aren't used so I deleted them.
#
# FriendlyMap:
# FriendlyMap is a typedef to a pointer. Therefore we treat it like
# a pointer.
# The two functions using this are ldap_friendly_name() and
# ldap_free_friendlymap().
# Both use a parameter of type FriendlyMap * in the API, however
# we use type FriendlyMap in API.xs and use "pass by reference" using the
# &map. This is appropriate for ldap_friendly_map() - it returns the
# map, but seems wrong for ldap_free_friendlymap(). It is NOT wrong
# for ldap_free_friendlymap() though because the Perl variable we are
# passing in contains a FriendlyMap, not a FriendlyMap *.
#
# LDAPVirtualList *
# INPUT:
# This converts either a RvAV or a RvHV to a LDAPVirtualList *.
# The LDAPVirtualList * is malloc()ed inside the function.
# Call Safefree() in the CLEANUP section to free this memory.
#
# LDAPMod **
# INPUT:
# This is _manually_ converted in the API.xs code by calling
# hash2mod($arg, 0:1, "$func_name")
# The typemap is not used!
# Why? To change the second parameter based on whether this is
# an add function or not.
# You need to free the return value using ldap_mods_free()
#
#############################################################################
const int T_IV
char * T_PV
const char * T_PV
char ** T_charptrptr
LDAP * T_PTR
LDAPMessage * T_PTR
BerElement * T_PTR
LDAPControl * T_PTR
LDAPControl ** T_ldapcontrolptrptr
LDAPVersion * T_PTR
struct berval T_berval
struct berval * T_bervalptr
FriendlyMap T_PTR
LDAPsortkey ** T_PTR
LDAPVirtualList * T_ldapvirtuallistptr
LDAPURLDesc * T_PTR
LDAPFiltDesc * T_PTR
LDAPFiltInfo * T_PTR
LDAPMemCache * T_PTR
struct ldap_thread_fns * T_PTR
LDAPMod ** T_PTR
LDAP_CMP_CALLBACK * T_PTR
LDAP_REBINDPROC_CALLBACK * T_PTR
struct timeval T_timeval
#########
INPUT
T_PV
if ( $arg == &PL_sv_undef )
$var = NULL;
else
$var = ($type)SvPV($arg,PL_na)
T_timeval
$var.tv_sec = atof((char *)SvPV($arg,PL_na));
$var.tv_usec = 0
T_berval
$var.bv_val = (char *)SvPV($arg,PL_na);
$var.bv_len = PL_na
T_charptrptr
$var = (char **)avref2charptrptr($arg)
T_ldapcontrolptrptr
$var = sv2ldapcontrolptrptr($arg)
T_ldapvirtuallistptr
$var = sv2ldapvirtuallistptr($arg)
OUTPUT
T_charptrptr
$arg = charptrptr2avref($var);
T_bervalptr
$arg = berptr2svpv($var);
T_ldapcontrolptrptr
$arg = ldapcontrolptrptr2avref($var);

View File

@@ -0,0 +1,134 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "BitSet.h"
// Return the next bit after index set to true or -1 if none.
//
Int32 BitSet::nextOne(Int32 pos) const
{
++pos;
if (pos < 0 || Uint32(pos) >= universeSize)
return -1;
Uint32 offset = getWordOffset(pos);
Uint8 index = getBitOffset(pos);
Word* ptr = &word[offset];
Word currentWord = *ptr++ >> index;
if (currentWord != Word(0)) {
while ((currentWord & Word(1)) == 0) {
++index;
currentWord >>= 1;
}
return (offset << nBitsInWordLog2) + index;
}
Word* limit = &word[getSizeInWords(universeSize)];
while (ptr < limit) {
++offset;
currentWord = *ptr++;
if (currentWord != Word(0)) {
index = 0;
while ((currentWord & Word(1)) == 0) {
++index;
currentWord >>= 1;
}
return (offset << nBitsInWordLog2) + index;
}
}
return -1;
}
// Return the next bit after index set to false or -1 if none.
//
Int32 BitSet::nextZero(Int32 pos) const
{
++pos;
if (pos < 0 || Uint32(pos) >= universeSize)
return -1;
Uint32 offset = getWordOffset(pos);
Uint8 index = getBitOffset(pos);
Word* ptr = &word[offset];
Word currentWord = *ptr++ >> index;
if (currentWord != Word(~0)) {
for (; index < nBitsInWord; ++index) {
if ((currentWord & Word(1)) == 0) {
Int32 ret = (offset << nBitsInWordLog2) + index;
return (Uint32(ret) < universeSize) ? ret : -1;
}
currentWord >>= 1;
}
}
Word* limit = &word[getSizeInWords(universeSize)];
while (ptr < limit) {
++offset;
currentWord = *ptr++;
if (currentWord != Word(~0)) {
for (index = 0; index < nBitsInWord; ++index) {
if ((currentWord & Word(1)) == 0) {
Int32 ret = (offset << nBitsInWordLog2) + index;
return (Uint32(ret) < universeSize) ? ret : -1;
}
currentWord >>= 1;
}
}
}
return -1;
}
#ifdef DEBUG_LOG
// Print the set.
//
void BitSet::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("[ "));
for (Int32 i = firstOne(); i != -1; i = nextOne(i)) {
Int32 currentBit = i;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", currentBit));
Int32 nextBit = nextOne(currentBit);
if (nextBit != currentBit + 1) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" "));
continue;
}
while ((nextBit != -1) && (nextBit == (currentBit + 1))) {
currentBit = nextBit;
nextBit = nextOne(nextBit);
}
if (currentBit > (i+1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("-%d ", currentBit));
else
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" %d ", currentBit));
i = currentBit;
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("]\n"));
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,195 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _BITSET_H_
#define _BITSET_H_
#include "Fundamentals.h"
#include "LogModule.h"
#include "Pool.h"
#include <string.h>
//------------------------------------------------------------------------------
// BitSet -
class BitSet
{
private:
#if (PR_BITS_PER_WORD == 64)
typedef Uint64 Word;
#elif (PR_BITS_PER_WORD == 32)
typedef Uint32 Word;
#endif
static const nBitsInWord = PR_BITS_PER_WORD;
static const nBytesInWord = PR_BYTES_PER_WORD;
static const nBitsInWordLog2 = PR_BITS_PER_WORD_LOG2;
static const nBytesInWordLog2 = PR_BYTES_PER_WORD_LOG2;
// Return the number of Word need to store the universe.
static Uint32 getSizeInWords(Uint32 sizeOfUniverse) {return (sizeOfUniverse + (nBitsInWord - 1)) >> nBitsInWordLog2;}
// Return the given element offset in its containing Word.
static Uint32 getBitOffset(Uint32 element) {return element & (nBitsInWord - 1);}
// Return the Word offset for the given element int the universe.
static Uint32 getWordOffset(Uint32 element) {return element >> nBitsInWordLog2;}
// Return the mask for the given bit index.
static Word getMask(Uint8 index) {return Word(1) << index;}
private:
Uint32 universeSize; // Size of the universe
Word* word; // universe memory.
private:
// No copy constructor.
BitSet(const BitSet&);
// Check if the given set's universe is of the same size than this universe.
void checkUniverseCompatibility(const BitSet& set) const {assert(set.universeSize == universeSize);}
// Check if pos is valid for this set's universe.
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
public:
// Create a bitset of universeSize bits.
BitSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {word = new(pool) Word[getSizeInWords(universeSize)]; clear();}
// Return the size of this bitset.
Uint32 getSize() const {return universeSize;}
// Clear the bitset.
void clear() {memset(word, 0x00, getSizeInWords(universeSize) << nBytesInWordLog2);}
// Clear the bit at index.
void clear(Uint32 index) {checkMember(index); word[getWordOffset(index)] &= ~getMask(index);}
// Set the bitset.
void set() {memset(word, 0xFF, getSizeInWords(universeSize) << nBytesInWordLog2);}
// Set the bit at index.
void set(Uint32 index) {checkMember(index); word[getWordOffset(index)] |= getMask(index);}
// Return true if the bit at index is set.
bool test(Uint32 index) const {checkMember(index); return (word[getWordOffset(index)] & getMask(index)) != 0;}
// Union with the given bitset.
inline void or(const BitSet& set);
// Intersection with the given bitset.
inline void and(const BitSet& set);
// Difference with the given bitset.
inline void difference(const BitSet& set);
// Copy set.
inline BitSet& operator = (const BitSet& set);
// Return true if the bitset are identical.
friend bool operator == (const BitSet& set1, const BitSet& set2);
// Return true if the bitset are different.
friend bool operator != (const BitSet& set1, const BitSet& set2);
// Logical operators.
BitSet& operator |= (const BitSet& set) {or(set); return *this;}
BitSet& operator &= (const BitSet& set) {and(set); return *this;}
BitSet& operator -= (const BitSet& set) {difference(set); return *this;}
// Return the first bit at set to true or -1 if none.
Int32 firstOne() const {return nextOne(-1);}
// Return the next bit after index set to true or -1 if none.
Int32 nextOne(Int32 pos) const;
// Return the first bit at set to false or -1 if none.
Int32 firstZero() const {return nextZero(-1);}
// Return the next bit after index set to false or -1 if none.
Int32 nextZero(Int32 pos) const;
// Iterator to conform with the set API.
typedef Int32 iterator;
// Return true if the walk is ordered.
static bool isOrdered() {return true;}
// Return the iterator for the first element of this set.
iterator begin() const {return firstOne();}
// Return the next iterator.
iterator advance(iterator pos) const {return nextOne(pos);}
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos == -1;}
// Return the element corresponding to the given iterator.
Uint32 get(iterator pos) const {return pos;}
#ifdef DEBUG_LOG
// Print the set.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
// Union with the given bitset.
//
inline void BitSet::or(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ |= *src++;
}
// Intersection with the given bitset.
//
inline void BitSet::and(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ &= *src++;
}
// Difference with the given bitset.
//
inline void BitSet::difference(const BitSet& set)
{
checkUniverseCompatibility(set);
Word* src = set.word;
Word* dst = word;
Word* limit = &src[getSizeInWords(universeSize)];
while (src < limit)
*dst++ &= ~*src++;
}
// Copy the given set into this set.
//
inline BitSet& BitSet::operator = (const BitSet& set)
{
checkUniverseCompatibility(set);
if (this != &set)
memcpy(word, set.word, getSizeInWords(universeSize) << nBytesInWordLog2);
return *this;
}
// Return true if the given set is identical to this set.
inline bool operator == (const BitSet& set1, const BitSet& set2)
{
set1.checkUniverseCompatibility(set2);
if (&set1 == &set2)
return true;
return memcmp(set1.word, set2.word, BitSet::getSizeInWords(set1.universeSize) << BitSet::nBytesInWordLog2) == 0;
}
inline bool operator != (const BitSet& set1, const BitSet& set2) {return !(set1 == set2);}
#endif // _BITSET_H

View File

@@ -0,0 +1,159 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _COALESCING_H_
#define _COALESCING_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "RegisterPressure.h"
#include "InterferenceGraph.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "SparseSet.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
#if 1
// Performing an ultra conservative coalescing meens that when we look at
// candidates (source,destination) for coalescing we need to make sure
// that the combined interference of the source and destination register
// will not exceed the total number of register available for the register
// class.
#define ULTRA_CONSERVATIVE_COALESCING
#else
// If we are not doing an ultra conservative coalescing we have to make sure
// that the total number of neighbor whose degree is greater than the total
// number of register is not greater than the total number of register.
#undef ULTRA_CONSERVATIVE_COALESCING
#endif
template <class RegisterPressure>
struct Coalescing
{
static bool coalesce(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
bool Coalescing<RegisterPressure>::coalesce(RegisterAllocator& registerAllocator)
{
Pool& pool = registerAllocator.pool;
// Initialize the lookup table
//
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* newRange = new RegisterName[2 * rangeCount];
RegisterName* coalescedRange = &newRange[rangeCount];
RegisterName* name2range = registerAllocator.name2range;
init(coalescedRange, rangeCount);
SparseSet interferences(pool, rangeCount);
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
bool removedInstructions = false;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.lndList;
Uint32 nNodes = controlGraph.nNodes;
// Walk the nodes in the loop nesting depth list.
for (Int32 n = nNodes - 1; n >= 0; n--) {
InstructionList& instructions = nodes[n]->getInstructions();
InstructionList::iterator it = instructions.begin();
while (!instructions.done(it)) {
Instruction& instruction = instructions.get(it);
it = instructions.advance(it);
if ((instruction.getFlags() & ifCopy) != 0) {
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
RegisterName source = findRoot(name2range[instruction.getInstructionUseBegin()[0].getRegisterName()], coalescedRange);
RegisterName destination = findRoot(name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()], coalescedRange);
if (source == destination) {
instruction.remove();
} else if (!iGraph.interfere(source, destination)) {
InterferenceVector* sourceVector = iGraph.getInterferenceVector(source);
InterferenceVector* destinationVector = iGraph.getInterferenceVector(destination);
#ifdef ULTRA_CONSERVATIVE_COALESCING
interferences.clear();
InterferenceVector* vector;
for (vector = sourceVector; vector != NULL; vector = vector->next) {
RegisterName* neighbors = vector->neighbors;
for (Uint32 i = 0; i < vector->count; i++)
interferences.set(findRoot(neighbors[i], coalescedRange));
}
for (vector = destinationVector; vector != NULL; vector = vector->next) {
RegisterName* neighbors = vector->neighbors;
for (Uint32 i = 0; i < vector->count; i++)
interferences.set(findRoot(neighbors[i], coalescedRange));
}
Uint32 count = interferences.getSize();
#else // ULTRA_CONSERVATIVE_COALESCING
trespass("not implemented");
Uint32 count = 0;
#endif // ULTRA_CONSERVATIVE_COALESCING
if (count < 6 /* FIX: should get the number from the class */) {
// Update the interferences vector.
if (sourceVector == NULL) {
iGraph.setInterferenceVector(source, destinationVector);
sourceVector = destinationVector;
} else if (destinationVector == NULL)
iGraph.setInterferenceVector(destination, sourceVector);
else {
InterferenceVector* last = NULL;
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next)
last = v;
assert(last);
last->next = destinationVector;
iGraph.setInterferenceVector(destination, sourceVector);
}
// Update the interference matrix.
for (InterferenceVector* v = sourceVector; v != NULL; v = v->next) {
RegisterName* neighbors = v->neighbors;
for (Uint32 i = 0; i < v->count; i++) {
RegisterName neighbor = findRoot(neighbors[i], coalescedRange);
iGraph.setInterference(neighbor, source);
iGraph.setInterference(neighbor, destination);
}
}
instruction.remove();
coalescedRange[source] = destination;
removedInstructions = true;
}
}
}
}
}
registerAllocator.rangeCount = compress(registerAllocator.name2range, coalescedRange, registerAllocator.nameCount, rangeCount);
delete newRange;
return removedInstructions;
}
#endif // _COALESCING_H_

View File

@@ -0,0 +1,283 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef NEW_LAURENTM_CODE
#include "Coloring.h"
#include "VirtualRegister.h"
#include "FastBitSet.h"
#include "FastBitMatrix.h"
#include "CpuInfo.h"
bool Coloring::
assignRegisters(FastBitMatrix& interferenceMatrix)
{
PRUint32 *stackPtr = new(pool) PRUint32[vRegManager.count()];
return select(interferenceMatrix, stackPtr, simplify(interferenceMatrix, stackPtr));
}
PRInt32 Coloring::
getLowestSpillCostRegister(FastBitSet& bitset)
{
PRInt32 lowest = bitset.firstOne();
if (lowest != -1)
{
Flt32 cost = vRegManager.getVirtualRegister(lowest).spillInfo.spillCost;
for (PRInt32 r = bitset.nextOne(lowest); r != -1; r = bitset.nextOne(r))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
if (!vReg.spillInfo.infiniteSpillCost && (vReg.spillInfo.spillCost < cost))
{
cost = vReg.spillInfo.spillCost;
lowest = r;
}
}
}
return lowest;
}
PRUint32* Coloring::
simplify(FastBitMatrix interferenceMatrix, PRUint32* stackPtr)
{
// first we construct the sets low and high. low contains all nodes of degree
// inferior to the number of register available on the processor. All the
// nodes with an high degree and a finite spill cost are placed in high.
// Nodes of high degree and infinite spill cost are not included in either sets.
PRUint32 nRegisters = vRegManager.count();
FastBitSet low(pool, nRegisters);
FastBitSet high(pool, nRegisters);
FastBitSet stack(pool, nRegisters);
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
if (vReg.getClass() == vrcStackSlot)
{
stack.set(i);
vReg.colorRegister(nRegisters);
}
else
{
if (vReg.colorInfo.interferenceDegree < NUMBER_OF_REGISTERS)
low.set(i);
else // if (!vReg.spillInfo.infiniteSpillCost)
high.set(i);
// Set coloring info.
vReg.spillInfo.willSpill = false;
switch(vReg.getClass())
{
case vrcInteger:
vReg.colorRegister(LAST_GREGISTER + 1);
break;
case vrcFloatingPoint:
case vrcFixedPoint:
vReg.colorRegister(LAST_FPREGISTER + 1);
break;
default:
PR_ASSERT(false); // Cannot happen.
}
}
}
// push the stack registers
PRInt32 j;
for (j = stack.firstOne(); j != -1; j = stack.nextOne(j))
*stackPtr++ = j;
// simplify
while (true)
{
PRInt32 r;
while ((r = getLowestSpillCostRegister(low)) != -1)
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
/* update low and high */
FastBitSet inter(interferenceMatrix.getRow(r), nRegisters);
for (j = inter.firstOne(); j != -1; j = inter.nextOne(j))
{
VirtualRegister& neighbor = vRegManager.getVirtualRegister(j);
// if the new interference degree of one of his neighbor becomes
// NUMBER_OF_REGISTERS - 1 then it is added to the set 'low'.
PRUint32 maxInterference = 0;
switch (neighbor.getClass())
{
case vrcInteger:
maxInterference = NUMBER_OF_GREGISTERS;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
maxInterference = NUMBER_OF_FPREGISTERS;
break;
default:
PR_ASSERT(false);
}
if ((vRegManager.getVirtualRegister(j).colorInfo.interferenceDegree-- == maxInterference))
{
high.clear(j);
low.set(j);
}
vReg.colorInfo.interferenceDegree--;
interferenceMatrix.clear(r, j);
interferenceMatrix.clear(j, r);
}
low.clear(r);
// Push this register.
*stackPtr++ = r;
}
if ((r = getLowestSpillCostRegister(high)) != -1)
{
high.clear(r);
low.set(r);
}
else
break;
}
return stackPtr;
}
bool Coloring::
select(FastBitMatrix& interferenceMatrix, PRUint32* stackBase, PRUint32* stackPtr)
{
PRUint32 nRegisters = vRegManager.count();
FastBitSet usedRegisters(NUMBER_OF_REGISTERS + 1); // usedRegisters if used for both GR & FPR.
FastBitSet preColoredRegisters(NUMBER_OF_REGISTERS + 1);
FastBitSet usedStack(nRegisters + 1);
bool success = true;
Int32 lastUsedSSR = -1;
// select
while (stackPtr != stackBase)
{
// Pop one register.
PRUint32 r = *--stackPtr;
VirtualRegister& vReg = vRegManager.getVirtualRegister(r);
FastBitSet neighbors(interferenceMatrix.getRow(r), nRegisters);
if (vReg.getClass() == vrcStackSlot)
// Stack slots coloring.
{
usedStack.clear();
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
usedStack.set(vRegManager.getVirtualRegister(i).getColor());
Int32 color = usedStack.firstZero();
vReg.colorRegister(color);
if (color > lastUsedSSR)
lastUsedSSR = color;
}
else
// Integer & Floating point register coloring.
{
usedRegisters.clear();
preColoredRegisters.clear();
for (PRInt32 i = neighbors.firstOne(); i != -1; i = neighbors.nextOne(i))
{
VirtualRegister& nvReg = vRegManager.getVirtualRegister(i);
usedRegisters.set(nvReg.getColor());
if (nvReg.isPreColored())
preColoredRegisters.set(nvReg.getPreColor());
}
if (vReg.hasSpecialInterference)
usedRegisters |= vReg.specialInterference;
PRInt8 c = -1;
PRInt8 maxColor = 0;
PRInt8 firstColor = 0;
switch (vReg.getClass())
{
case vrcInteger:
firstColor = FIRST_GREGISTER;
maxColor = LAST_GREGISTER;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
firstColor = FIRST_FPREGISTER;
maxColor = LAST_FPREGISTER;
break;
default:
PR_ASSERT(false);
}
if (vReg.isPreColored())
{
c = vReg.getPreColor();
if (usedRegisters.test(c))
c = -1;
}
else
{
for (c = usedRegisters.nextZero(firstColor - 1); (c >= 0) && (c <= maxColor) && (preColoredRegisters.test(c));
c = usedRegisters.nextZero(c)) {}
}
if ((c >= 0) && (c <= maxColor))
{
vReg.colorRegister(c);
}
else
{
VirtualRegister& stackRegister = vRegManager.newVirtualRegister(vrcStackSlot);
vReg.equivalentRegister[vrcStackSlot] = &stackRegister;
vReg.spillInfo.willSpill = true;
success = false;
}
}
}
#ifdef DEBUG
if (success)
{
for (VirtualRegisterManager::iterator i = vRegManager.begin(); !vRegManager.done(i); i = vRegManager.advance(i))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(i);
switch (vReg.getClass())
{
case vrcInteger:
if (vReg.getColor() > LAST_GREGISTER)
PR_ASSERT(false);
break;
case vrcFloatingPoint:
case vrcFixedPoint:
#if NUMBER_OF_FPREGISTERS != 0
if (vReg.getColor() > LAST_FPREGISTER)
PR_ASSERT(false);
#endif
break;
default:
break;
}
}
}
#endif
vRegManager.nUsedStackSlots = lastUsedSSR + 1;
return success;
}
#endif // NEW_LAURENTM_CODE

View File

@@ -0,0 +1,284 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "VirtualRegister.h"
#include "InterferenceGraph.h"
#include "SparseSet.h"
#include "Spilling.h"
#include "Splits.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
template <class RegisterPressure>
class Coloring
{
private:
static RegisterName* simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack);
static bool select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr);
public:
static bool color(RegisterAllocator& registerAllocator);
static void finalColoring(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
void Coloring<RegisterPressure>::finalColoring(RegisterAllocator& registerAllocator)
{
RegisterName* color = registerAllocator.color;
RegisterName* name2range = registerAllocator.name2range;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
usePtr->setRegisterName(color[name2range[usePtr->getRegisterName()]]);
#ifdef DEBUG
RegisterID rid = usePtr->getRegisterID();
setColoredRegister(rid);
usePtr->setRegisterID(rid);
#endif // DEBUG
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
definePtr->setRegisterName(color[name2range[definePtr->getRegisterName()]]);
#ifdef DEBUG
RegisterID rid = definePtr->getRegisterID();
setColoredRegister(rid);
definePtr->setRegisterID(rid);
#endif // DEBUG
}
}
}
}
template <class RegisterPressure>
bool Coloring<RegisterPressure>::select(RegisterAllocator& registerAllocator, RegisterName* coloringStack, RegisterName* coloringStackPtr)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* color = new RegisterName[rangeCount];
registerAllocator.color = color;
for (Uint32 r = 1; r < rangeCount; r++)
color[r] = RegisterName(6); // FIX;
// Color the preColored registers.
//
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
RegisterName* name2range = registerAllocator.name2range;
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
if (machinePtr->id != invalidID) {
color[name2range[getName(machinePtr->id)]] = machinePtr->color;
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill preColor range %d as %d\n", name2range[getName(machinePtr->id)], machinePtr->color));
}
SpillCost* cost = registerAllocator.spillCost;
Pool& pool = registerAllocator.pool;
SparseSet& spill = *new(pool) SparseSet(pool, rangeCount);
registerAllocator.willSpill = &spill;
SparseSet neighborColors(pool, 6); // FIX
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
bool coloringFailed = false;
while (coloringStackPtr > coloringStack) {
RegisterName range = *--coloringStackPtr;
if (!cost[range].infinite && cost[range].cost < 0) {
coloringFailed = true;
spill.set(range);
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, will spill.\n", range));
} else {
neighborColors.clear();
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = vector->count - 1; i >= 0; --i) {
RegisterName neighborColor = color[vector->neighbors[i]];
if (neighborColor < 6) // FIX
neighborColors.set(neighborColor);
}
if (neighborColors.getSize() == 6) { // FIX
coloringFailed = true;
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tfailed to color %d, ", range));
if (!Splits<RegisterPressure>::findSplit(registerAllocator, color, range)) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will spill.\n"));
spill.set(range);
} else
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("will split.\n"));
} else {
for (Uint32 i = 0; i < 6; i++) // FIX
if (!neighborColors.test(i)) {
fprintf(stdout, "\twill color %d as %d\n", range, i);
color[range] = RegisterName(i);
break;
}
}
}
}
#ifdef DEBUG_LOG
if (coloringFailed) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring failed:\n"));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\twill spill: "));
spill.printPretty(UT_LOG_MODULE(RegAlloc));
} else {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring succeeded:\n"));
for (Uint32 i = 1; i < rangeCount; i++)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\trange %d colored as %d\n", i, color[i]));
}
#endif
return !coloringFailed;
}
template <class RegisterPressure>
RegisterName* Coloring<RegisterPressure>::simplify(RegisterAllocator& registerAllocator, RegisterName* coloringStack)
{
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
SpillCost* spillCost = registerAllocator.spillCost;
Uint32 rangeCount = registerAllocator.rangeCount;
Uint32* degree = new Uint32[rangeCount];
for (RegisterName i = RegisterName(1); i < rangeCount; i = RegisterName(i + 1)) {
InterferenceVector* vector = iGraph.getInterferenceVector(i);
degree[i] = (vector != NULL) ? vector->count : 0;
}
Pool& pool = registerAllocator.pool;
SparseSet low(pool, rangeCount);
SparseSet high(pool, rangeCount);
SparseSet highInfinite(pool, rangeCount);
SparseSet preColored(pool, rangeCount);
// Get the precolored registers.
//
VirtualRegisterManager& vrManager = registerAllocator.vrManager;
RegisterName* name2range = registerAllocator.name2range;
PreColoredRegister* machineEnd = vrManager.getMachineRegistersEnd();
for (PreColoredRegister* machinePtr = vrManager.getMachineRegistersBegin(); machinePtr < machineEnd; machinePtr++)
if (machinePtr->id != invalidID)
preColored.set(name2range[getName(machinePtr->id)]);
// Insert the live ranges in the sets.
//
for (Uint32 range = 1; range < rangeCount; range++)
if (!preColored.test(range))
if (degree[range] < 6) // FIX
low.set(range);
else if (!spillCost[range].infinite)
high.set(range);
else
highInfinite.set(range);
#ifdef DEBUG_LOG
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring sets:\n\tlow = "));
low.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thigh = "));
high.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\thighInfinite = "));
highInfinite.printPretty(UT_LOG_MODULE(RegAlloc));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tpreColored = "));
preColored.printPretty(UT_LOG_MODULE(RegAlloc));
#endif // DEBUG_LOG
RegisterName* coloringStackPtr = coloringStack;
while (low.getSize() != 0 || high.getSize() != 0) {
while (low.getSize() != 0) {
RegisterName range = RegisterName(low.getOne());
low.clear(range);
*coloringStackPtr++ = range;
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = (vector->count - 1); i >= 0; --i) {
RegisterName neighbor = vector->neighbors[i];
degree[neighbor]--;
if (degree[neighbor] < 6) // FIX
if (high.test(neighbor)) {
high.clear(neighbor);
low.set(neighbor);
} else if (highInfinite.test(neighbor)) {
highInfinite.clear(neighbor);
low.set(neighbor);
}
}
}
if (high.getSize() != 0) {
RegisterName best = RegisterName(high.getOne());
double bestCost = spillCost[best].cost;
double bestDegree = degree[best];
// Choose the next best candidate.
//
for (SparseSet::iterator i = high.begin(); !high.done(i); i = high.advance(i)) {
RegisterName range = RegisterName(high.get(i));
double thisCost = spillCost[range].cost;
double thisDegree = degree[range];
if (thisCost * bestDegree < bestCost * thisDegree) {
best = range;
bestCost = thisCost;
bestDegree = thisDegree;
}
}
high.clear(best);
low.set(best);
}
}
assert(highInfinite.getSize() == 0);
delete degree;
#ifdef DEBUG_LOG
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("Coloring stack:\n\t"));
for (RegisterName* sp = coloringStack; sp < coloringStackPtr; ++sp)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("%d ", *sp));
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\n"));
#endif // DEBUG_LOG
return coloringStackPtr;
}
template <class RegisterPressure>
bool Coloring<RegisterPressure>::color(RegisterAllocator& registerAllocator)
{
RegisterName* coloringStack = new RegisterName[registerAllocator.rangeCount];
return select(registerAllocator, coloringStack, simplify(registerAllocator, coloringStack));
}

View File

@@ -0,0 +1,212 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include <string.h>
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "DominatorGraph.h"
DominatorGraph::DominatorGraph(ControlGraph& controlGraph) : controlGraph(controlGraph)
{
Uint32 nNodes = controlGraph.nNodes;
GtoV = new Uint32[nNodes + 1];
VtoG = new Uint32[nNodes + 1];
Uint32 v = 1;
for (Uint32 n = 0; n < nNodes; n++) {
VtoG[v] = n;
GtoV[n] = v++;
}
// Initialize all the 1-based arrays.
//
parent = new Uint32[v];
semi = new Uint32[v];
vertex = new Uint32[v];
label = new Uint32[v];
size = new Uint32[v];
ancestor = new Uint32[v];
child = new Uint32[v];
dom = new Uint32[v];
bucket = new DGLinkedList*[v];
memset(semi, '\0', v * sizeof(Uint32));
memset(bucket, '\0', v * sizeof(DGLinkedList*));
vCount = v;
build();
delete parent;
delete semi;
delete vertex;
delete label;
delete size;
delete ancestor;
delete child;
delete dom;
delete bucket;
}
Uint32 DominatorGraph::DFS(Uint32 vx, Uint32 n)
{
semi[vx] = ++n;
vertex[n] = label[vx] = vx;
ancestor[vx] = child[vx] = 0;
size[vx] = 1;
ControlNode& node = *controlGraph.dfsList[VtoG[vx]];
ControlEdge* successorEnd = node.getSuccessorsEnd();
for (ControlEdge* successorPtr = node.getSuccessorsBegin(); successorPtr < successorEnd; successorPtr++) {
Uint32 w = GtoV[successorPtr->getTarget().dfsNum];
if (semi[w] == 0) {
parent[w] = vx;
n = DFS(w, n);
}
}
return n;
}
void DominatorGraph::LINK(Uint32 vx, Uint32 w)
{
Uint32 s = w;
while (semi[label[w]] < semi[label[child[s]]]) {
if (size[s] + size[child[child[s]]] >= (size[child[s]] << 1)) {
ancestor[child[s]] = s;
child[s] = child[child[s]];
} else {
size[child[s]] = size[s];
s = ancestor[s] = child[s];
}
}
label[s] = label[w];
size[vx] += size[w];
if(size[vx] < (size[w] << 1)) {
Uint32 t = s;
s = child[vx];
child[vx] = t;
}
while( s != 0 ) {
ancestor[s] = vx;
s = child[s];
}
}
void DominatorGraph::COMPRESS(Uint32 vx)
{
if(ancestor[ancestor[vx]] != 0) {
COMPRESS(ancestor[vx]);
if(semi[label[ancestor[vx]]] < semi[label[vx]])
label[vx] = label[ancestor[vx]];
ancestor[vx] = ancestor[ancestor[vx]];
}
}
Uint32 DominatorGraph::EVAL(Uint32 vx)
{
if(ancestor[vx] == 0)
return label[vx];
COMPRESS(vx);
return (semi[label[ancestor[vx]]] >= semi[label[vx]]) ? label[vx] : label[ancestor[vx]];
}
void DominatorGraph::build()
{
Uint32 n = DFS(GtoV[0], 0);
size[0] = label[0] = semi[0];
for (Uint32 i = n; i >= 2; i--) {
Uint32 w = vertex[i];
ControlNode& node = *controlGraph.dfsList[VtoG[w]];
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p)) {
Uint32 vx = GtoV[predecessors.get(p).getSource().dfsNum];
Uint32 u = EVAL(vx);
if(semi[u] < semi[w])
semi[w] = semi[u];
}
DGLinkedList* elem = new DGLinkedList();
elem->next = bucket[vertex[semi[w]]];
elem->index = w;
bucket[vertex[semi[w]]] = elem;
LINK(parent[w], w);
elem = bucket[parent[w]];
while(elem != NULL) {
Uint32 vx = elem->index;
Uint32 u = EVAL(vx);
dom[vx] = (semi[u] < semi[vx]) ? u : parent[w];
elem = elem->next;
}
}
memset(size, '\0', n * sizeof(Uint32));
Pool& pool = controlGraph.pool;
nodes = new(pool) DGNode[n];
for(Uint32 j = 2; j <= n; j++) {
Uint32 w = vertex[j];
Uint32 d = dom[w];
if(d != vertex[semi[w]]) {
d = dom[d];
dom[w] = d;
}
size[d]++;
}
dom[GtoV[0]] = 0;
for (Uint32 k = 1; k <= n; k++) {
DGNode& node = nodes[VtoG[k]];
Uint32 count = size[k];
node.successorsEnd = node.successorsBegin = (count) ? new(pool) Uint32[count] : (Uint32*) 0;
}
for (Uint32 l = 2; l <= n; l++)
*(nodes[VtoG[dom[l]]].successorsEnd)++ = VtoG[l];
}
#ifdef DEBUG_LOG
void DominatorGraph::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Dominator Graph:\n"));
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 i = 0; i < nNodes; i++) {
DGNode& node = nodes[i];
if (node.successorsBegin != node.successorsEnd) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tN%d dominates ", i));
for (Uint32* successorsPtr = node.successorsBegin; successorsPtr < node.successorsEnd; successorsPtr++)
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d ", *successorsPtr));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _DOMINATOR_GRAPH_H_
#define _DOMINATOR_GRAPH_H_
#include "LogModule.h"
class ControlGraph;
struct DGNode
{
Uint32* successorsBegin;
Uint32* successorsEnd;
};
struct DGLinkedList
{
DGLinkedList* next;
Uint32 index;
};
class DominatorGraph
{
private:
ControlGraph& controlGraph;
Uint32 vCount;
Uint32* VtoG;
Uint32* GtoV;
Uint32* parent;
Uint32* semi;
Uint32* vertex;
Uint32* label;
Uint32* size;
Uint32* ancestor;
Uint32* child;
Uint32* dom;
DGLinkedList** bucket;
DGNode* nodes;
private:
void build();
Uint32 DFS(Uint32 vx, Uint32 n);
void LINK(Uint32 vx, Uint32 w);
void COMPRESS(Uint32 vx);
Uint32 EVAL(Uint32 vx);
public:
DominatorGraph(ControlGraph& controlGraph);
Uint32* getSuccessorsBegin(Uint32 n) const {return nodes[n].successorsBegin;}
Uint32* getSuccessorsEnd(Uint32 n) const {return nodes[n].successorsEnd;}
#ifdef DEBUG_LOG
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
#endif // _DOMINATOR_GRAPH_H_

View File

@@ -0,0 +1,20 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "HashSet.h"

View File

@@ -0,0 +1,97 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _HASH_SET_H_
#define _HASH_SET_H_
#include "Fundamentals.h"
#include "Pool.h"
#include <string.h>
struct HashSetElement
{
Uint32 index;
HashSetElement* next;
};
class HashSet
{
private:
static const hashSize = 64;
// Return the hash code for the given element index.
static Uint32 getHashCode(Uint32 index) {return index & (hashSize - 1);} // Could be better !
private:
Pool& allocationPool;
HashSetElement** bucket;
HashSetElement* free;
private:
// No copy constructor.
HashSet(const HashSet&);
// No copy operator.
void operator = (const HashSet&);
public:
// Create a new HashSet.
inline HashSet(Pool& pool, Uint32 universeSize);
// Clear the hashset.
void clear();
// Clear the element for the given index.
void clear(Uint32 index);
// Set the element for the given index.
void set(Uint32 index);
// Return true if the element at index is a member.
bool test(Uint32 index) const;
// Union with the given hashset.
inline void or(const HashSet& set);
// Intersection with the given hashset.
inline void and(const HashSet& set);
// Difference with the given hashset.
inline void difference(const HashSet& set);
// Logical operators.
HashSet& operator |= (const HashSet& set) {or(set); return *this;}
HashSet& operator &= (const HashSet& set) {and(set); return *this;}
HashSet& operator -= (const HashSet& set) {difference(set); return *this;}
// Iterator to conform with the set API.
typedef HashSetElement* iterator;
// Return the iterator for the first element of this set.
iterator begin() const;
// Return the next iterator.
iterator advance(iterator pos) const;
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos == NULL;}
};
inline HashSet::HashSet(Pool& pool, Uint32 /*universeSize*/)
: allocationPool(pool), free(NULL)
{
bucket = new(pool) HashSetElement*[hashSize];
memset(bucket, '\0', sizeof(HashSetElement*));
}
#endif // _HASH_SET_H_

View File

@@ -0,0 +1,213 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _INDEXED_POOL_H_
#define _INDEXED_POOL_H_
#include "Fundamentals.h"
#include <string.h>
#include <stdlib.h>
//------------------------------------------------------------------------------
// IndexedPool<IndexedObjectSubclass> is an indexed pool of objects. The
// template parameter 'IndexedObjectSubclass' must be a subclass of the struct
// IndexedObject.
//
// When the indexed pool is ask to allocate and initialize a new object (using
// the operator new(anIndexedPool) it will zero the memory used to store the
// object and initialize the field 'index' of this object to its position in
// the pool.
//
// An object allocated by the indexed pool can be freed by calling the method
// IndexedPool::release(IndexedElement& objectIndex).
//
// example:
//
// IndexedPool<IndexedElement> elementPool;
//
// IndexedElement& element1 = *new(elementPool) IndexedElement();
// IndexedElement& element2 = *new(elementPool) IndexedElement();
//
// indexedPool.release(element1);
// IndexedElement& element3 = *new(elementPool) IndexedElement();
//
// At this point element1 is no longer a valid object, element2 is at
// index 2 and element3 is at index 1.
//
//------------------------------------------------------------------------------
// IndexedObject -
//
template<class Object>
struct IndexedObject
{
Uint32 index; // Index in the pool.
Object* next; // Used to link IndexedObject together.
Uint32 getIndex() {return index;}
};
//------------------------------------------------------------------------------
// IndexedPool<IndexedObject> -
//
template <class IndexedObject>
class IndexedPool
{
private:
static const blockSize = 4; // Size of one block.
Uint32 nBlocks; // Number of blocks in the pool.
IndexedObject** block; // Array of block pointers.
IndexedObject* freeObjects; // Chained list of free IndexedObjects.
Uint32 nextIndex; // Index of the next free object in the last block.
private:
void allocateAnotherBlock();
IndexedObject& newObject();
public:
IndexedPool() : nBlocks(0), block(NULL), freeObjects(NULL), nextIndex(1) {}
~IndexedPool();
IndexedObject& get(Uint32 index) const;
void release(IndexedObject& object);
void setSize(Uint32 size) {assert(size < nextIndex); nextIndex = size;}
// Return the universe size.
Uint32 getSize() {return nextIndex;}
friend void* operator new(size_t, IndexedPool<IndexedObject>& pool); // Needs to call newObject().
};
// Free all the memory allocated for this object.
//
template <class IndexedObject>
IndexedPool<IndexedObject>::~IndexedPool()
{
for (Uint32 n = 0; n < nBlocks; n++)
free(&((IndexedObject **) &block[n][n*blockSize])[-(n + 1)]);
}
// Release the given. This object will be iserted in the chained
// list of free IndexedObjects. To minimize the fragmentation the chained list
// is ordered by ascending indexes.
//
template <class IndexedObject>
void IndexedPool<IndexedObject>::release(IndexedObject& object)
{
Uint32 index = object.index;
IndexedObject* list = freeObjects;
assert(&object == &get(index)); // Make sure that object is owned by this pool.
if (list == NULL) { // The list is empty.
freeObjects = &object;
object.next = NULL;
} else { // The list contains at least 1 element.
if (index < list->index) { // insert as first element.
freeObjects = &object;
object.next = list;
} else { // Find this object's place.
while ((list->next) != NULL && (list->next->index < index))
list = list->next;
object.next = list->next;
list->next = &object;
}
}
#ifdef DEBUG
// Sanity check to be sure that the list is correctly ordered.
for (IndexedObject* obj = freeObjects; obj != NULL; obj = obj->next)
if (obj->next != NULL)
assert(obj->index < obj->next->index);
#endif
}
// Create a new block of IndexedObjects. We will allocate the memory to
// store IndexedPool::blockSize IndexedObject and the new Array of block
// pointers.
// The newly created IndexedObjects will not be initialized.
//
template <class IndexedObject>
void IndexedPool<IndexedObject>::allocateAnotherBlock()
{
void* memory = (void *) malloc((nBlocks + 1) * sizeof(Uint32) + blockSize * sizeof(IndexedObject));
memcpy(memory, block, nBlocks * sizeof(Uint32));
block = (IndexedObject **) memory;
IndexedObject* objects = (IndexedObject *) &block[nBlocks + 1];
block[nBlocks] = &objects[-(nBlocks * blockSize)];
nBlocks++;
}
// Return the IndexedObject at the position 'index' in the pool.
//
template <class IndexedObject>
IndexedObject& IndexedPool<IndexedObject>::get(Uint32 index) const
{
Uint32 blockIndex = index / blockSize;
assert(blockIndex < nBlocks);
return block[blockIndex][index];
}
// Return the reference of an unused object in the pool.
//
template <class IndexedObject>
IndexedObject& IndexedPool<IndexedObject>::newObject()
{
if (freeObjects != NULL) {
IndexedObject& newObject = *freeObjects;
freeObjects = newObject.next;
return newObject;
}
Uint32 nextIndex = this->nextIndex++;
Uint32 blockIndex = nextIndex / blockSize;
while (blockIndex >= nBlocks)
allocateAnotherBlock();
IndexedObject& newObject = block[blockIndex][nextIndex];
newObject.index = nextIndex;
return newObject;
}
// Return the address of the next unsused object in the given
// indexed pool. The field index of the newly allocated object
// will be initialized to the corresponding index of this object
// in the pool.
//
template <class IndexedObject>
void* operator new(size_t size, IndexedPool<IndexedObject>& pool)
{
assert(size == sizeof(IndexedObject));
return (void *) &pool.newObject();
}
#endif // _INDEXED_POOL_H_

View File

@@ -0,0 +1,258 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _INTERFERENCE_GRAPH_H_
#define _INTERFERENCE_GRAPH_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "Primitives.h"
#include "Instruction.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h"
#include "SparseSet.h"
#include <string.h>
struct InterferenceVector
{
Uint32 count;
InterferenceVector* next;
RegisterName* neighbors;
InterferenceVector() : count(0), next(NULL) {}
};
class RegisterAllocator;
template <class RegisterPressure>
class InterferenceGraph
{
private:
RegisterAllocator& registerAllocator;
RegisterPressure::Set* interferences;
InterferenceVector** vector;
Uint32* offset;
Uint32 rangeCount;
private:
// No copy constructor.
InterferenceGraph(const InterferenceGraph&);
// No copy operator.
void operator = (const InterferenceGraph&);
// Check if reg is a member of the universe.
void checkMember(RegisterName name) {assert(name < rangeCount);}
// Return the edge index for the interference between name1 and name2.
Uint32 getEdgeIndex(RegisterName name1, RegisterName name2);
public:
InterferenceGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
// Calculate the interferences.
void build();
// Return true if reg1 and reg2 interfere.
bool interfere(RegisterName name1, RegisterName name2);
// Return the interference vector for the given register or NULL if there is none.
InterferenceVector* getInterferenceVector(RegisterName name) {return vector[name];}
// Set the interference between name1 and name2.
void setInterference(RegisterName name1, RegisterName name2);
// Set the interference vector for the given register.
void setInterferenceVector(RegisterName name, InterferenceVector* v) {vector[name] = v;}
#ifdef DEBUG_LOG
// Print the interferences.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::build()
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
this->rangeCount = rangeCount;
// Initialize the structures.
//
offset = new(pool) Uint32[rangeCount + 1];
vector = new(pool) InterferenceVector*[rangeCount];
memset(vector, '\0', sizeof(InterferenceVector*) * rangeCount);
Uint32 o = 0;
offset[0] = 0;
for (Uint32 i = 1; i <= rangeCount; ++i) {
offset[i] = o;
o += i;
}
interferences = new(pool) RegisterPressure::Set(pool, (rangeCount * rangeCount) / 2);
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
LivenessInfo<RegisterPressure> liveness = Liveness<RegisterPressure>::analysis(controlGraph, rangeCount, name2range);
registerAllocator.liveness = liveness;
SparseSet currentLive(pool, rangeCount);
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
currentLive = liveness.liveOut[n];
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
// Handle the copy instruction to avoid unnecessary interference between the 2 registers.
if ((instruction.getFlags() & ifCopy) != 0) {
assert(useBegin != useEnd && useBegin[0].isRegister());
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
}
// Create the interferences.
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName define = name2range[definePtr->getRegisterName()];
for (SparseSet::iterator e = currentLive.begin(); !currentLive.done(e); e = currentLive.advance(e)) {
RegisterName live = RegisterName(currentLive.get(e));
if ((live != define) && !interfere(live, define) && registerAllocator.canInterfere(live, define)) {
if (vector[define] == NULL)
vector[define] = new(pool) InterferenceVector();
vector[define]->count++;
if (vector[live] == NULL)
vector[live] = new(pool) InterferenceVector();
vector[live]->count++;
setInterference(live, define);
}
}
}
// Now update the liveness.
//
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
currentLive.set(name2range[usePtr->getRegisterName()]);
}
}
// Allocate the memory to store the interferences.
//
for (Uint32 e = 0; e < rangeCount; e++)
if (vector[e] != NULL) {
InterferenceVector& v = *vector[e];
v.neighbors = new(pool) RegisterName[v.count];
v.count = 0;
}
// Initialize the edges.
//
if (RegisterPressure::Set::isOrdered()) {
RegisterName name1 = RegisterName(0);
for (RegisterPressure::Set::iterator i = interferences->begin(); !interferences->done(i); i = interferences->advance(i)) {
Uint32 interferenceIndex = interferences->get(i);
while(interferenceIndex >= offset[name1 + 1])
name1 = RegisterName(name1 + 1);
assert((interferenceIndex >= offset[name1]) && (interferenceIndex < offset[name1 + 1]));
RegisterName name2 = RegisterName(interferenceIndex - offset[name1]);
assert(interfere(name1, name2));
InterferenceVector& vector1 = *vector[name1];
vector1.neighbors[vector1.count++] = name2;
InterferenceVector& vector2 = *vector[name2];
vector2.neighbors[vector2.count++] = name1;
}
} else {
trespass("not Implemented"); // FIX: need one more pass to initialize the vectors.
}
}
template <class RegisterPressure>
Uint32 InterferenceGraph<RegisterPressure>::getEdgeIndex(RegisterName name1, RegisterName name2)
{
checkMember(name1); checkMember(name2);
assert(name1 != name2); // This is not possible.
return (name1 < name2) ? offset[name2] + name1 : offset[name1] + name2;
}
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::setInterference(RegisterName name1, RegisterName name2)
{
interferences->set(getEdgeIndex(name1, name2));
}
template <class RegisterPressure>
bool InterferenceGraph<RegisterPressure>::interfere(RegisterName name1, RegisterName name2)
{
return interferences->test(getEdgeIndex(name1, name2));
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void InterferenceGraph<RegisterPressure>::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Vectors:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
if (vector[i] != NULL) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tvr%d: (", i));
for (InterferenceVector* v = vector[i]; v != NULL; v = v->next)
for (Uint32 j = 0; j < v->count; j++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%d", v->neighbors[j]));
if (v->next != NULL || j != (v->count - 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (","));
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (")\n"));
}
}
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Interference Matrix:\n"));
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && interfere(name1, name2)) ? '1' : '0'));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _INTERFERENCE_GRAPH_H_

View File

@@ -0,0 +1,87 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVE_RANGE_H_
#define _LIVE_RANGE_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Primitives.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
template <class RegisterPressure>
struct LiveRange
{
static void build(RegisterAllocator& registerAllocator);
};
template <class RegisterPressure>
void LiveRange<RegisterPressure>::build(RegisterAllocator& registerAllocator)
{
// Intialize the lookup table.
//
Uint32 nameCount = registerAllocator.nameCount;
RegisterName* nameTable = new(registerAllocator.pool) RegisterName[2*nameCount];
RegisterName* rangeName = &nameTable[nameCount];
init(rangeName, nameCount);
// Walk the graph.
//
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
SparseSet destination(registerAllocator.pool, nameCount);
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
destination.clear();
for (InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
Instruction& phiNode = phiNodes.get(i);
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
destination.set(findRoot(phiNode.getInstructionDefineBegin()[0].getRegisterName(), rangeName));
}
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
RegisterName destinationName = phiNode.getInstructionDefineBegin()[0].getRegisterName();
RegisterName destinationRoot = findRoot(destinationName, rangeName);
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
assert(usePtr->isRegister());
RegisterName sourceName = usePtr->getRegisterName();
RegisterName sourceRoot = findRoot(sourceName, rangeName);
if (sourceRoot != destinationRoot && !destination.test(sourceRoot))
rangeName[sourceRoot] = destinationRoot;
}
}
}
registerAllocator.rangeCount = compress(registerAllocator.name2range, rangeName, nameCount, nameCount);
}
#endif // _LIVE_RANGE_H_

View File

@@ -0,0 +1,163 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVE_RANGE_GRAPH_
#define _LIVE_RANGE_GRAPH_
#include "Fundamentals.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterTypes.h"
class RegisterAllocator;
template <class RegisterPressure>
class LiveRangeGraph
{
private:
RegisterAllocator& registerAllocator;
RegisterPressure::Set* edges;
Uint32 rangeCount;
public:
//
//
LiveRangeGraph(RegisterAllocator& registerAllocator) : registerAllocator(registerAllocator) {}
//
//
void build();
//
//
void addEdge(RegisterName name1, RegisterName name2);
//
//
bool haveEdge(RegisterName name1, RegisterName name2);
#ifdef DEBUG_LOG
//
//
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::build()
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
this->rangeCount = rangeCount;
edges = new(pool) RegisterPressure::Set(pool, rangeCount * rangeCount);
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
LivenessInfo<RegisterPressure>& liveness = registerAllocator.liveness;
SparseSet currentLive(pool, rangeCount);
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
currentLive = liveness.liveOut[n];
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
if ((instruction.getFlags() & ifCopy) != 0) {
assert(useBegin != useEnd && useBegin[0].isRegister());
currentLive.clear(name2range[useBegin[0].getRegisterName()]);
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName define = name2range[definePtr->getRegisterName()];
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
RegisterName live = RegisterName(currentLive.get(l));
if (define != live && registerAllocator.canInterfere(define, live))
addEdge(define, live);
}
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
currentLive.set(name2range[usePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName use = name2range[usePtr->getRegisterName()];
for (SparseSet::iterator l = currentLive.begin(); !currentLive.done(l); l = currentLive.advance(l)) {
RegisterName live = RegisterName(currentLive.get(l));
if (use != live && registerAllocator.canInterfere(use, live))
addEdge(use, live);
}
}
}
}
}
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::addEdge(RegisterName name1, RegisterName name2)
{
assert(name1 != name2);
edges->set(name1 * rangeCount + name2);
}
template <class RegisterPressure>
bool LiveRangeGraph<RegisterPressure>::haveEdge(RegisterName name1, RegisterName name2)
{
assert(name1 != name2);
return edges->test(name1 * rangeCount + name2);
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void LiveRangeGraph<RegisterPressure>::printPretty(LogModuleObject log)
{
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Live ranges graph:\n"));
for (RegisterName name1 = RegisterName(1); name1 < rangeCount; name1 = RegisterName(name1 + 1)) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\t%d:\t", name1));
for (RegisterName name2 = RegisterName(1); name2 < rangeCount; name2 = RegisterName(name2 + 1))
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%c", ((name1 != name2) && haveEdge(name1, name2)) ? '1' : '0'));
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _LIVE_RANGE_GRAPH_

View File

@@ -0,0 +1,21 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "Liveness.h"

View File

@@ -0,0 +1,301 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _LIVENESS_H_
#define _LIVENESS_H_
#include "Fundamentals.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterTypes.h"
// ----------------------------------------------------------------------------
// LivenessInfo -
template <class RegisterPressure>
struct LivenessInfo
{
RegisterPressure::Set* liveIn;
RegisterPressure::Set* liveOut;
DEBUG_LOG_ONLY(Uint32 size);
#ifdef DEBUG_LOG
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
// ----------------------------------------------------------------------------
// Liveness
//
// The liveness is defined by the following data-flow equations:
//
// LiveIn(n) = LocalLive(n) U (LiveOut(n) - Killed(n)).
// LiveOut(n) = U LiveIn(s) (s a successor of n).
//
// where LocalLive(n) is the set of used registers in the block n, Killed(n)
// is the set of defined registers in the block n, LiveIn(n) is the set of
// live registers at the begining of the block n and LiveOut(n) is the set
// of live registers at the end of the block n.
//
//
// We will compute the liveness analysis in two stages:
//
// 1- Build LocalLive(n) (wich is an approximation of LiveIn(n)) and Killed(n)
// for each block n.
// 2- Perform a backward data-flow analysis to propagate the liveness information
// through the entire control-flow graph.
//
template <class RegisterPressure>
struct Liveness
{
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range);
static LivenessInfo<RegisterPressure> analysis(ControlGraph& controlGraph, Uint32 nameCount);
};
template <class RegisterPressure>
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 rangeCount, const RegisterName* name2range)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Allocate the temporary sets.
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
// Allocate the globals sets.
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, rangeCount);
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
//
for (Uint32 n = 0; n < (nNodes - 1); n++) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLocalLive = liveIn[n];
RegisterPressure::Set& currentKilled = killed[n];
// Find the instructions contributions to the sets LocalLive and Killed.
//
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
Uint32 index = name2range[usePtr->getRegisterName()];
if (!currentKilled.test(index))
currentLocalLive.set(index);
}
// If a Virtualregister is 'defined' then we add it to the set Killed.
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentKilled.set(name2range[definePtr->getRegisterName()]);
}
}
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
// control-flow graph.
//
RegisterPressure::Set temp(pool, rangeCount);
bool changed;
do {
changed = false;
// For all nodes is this graph except the endNode.
for (Int32 n = (nNodes - 2); n >= 0; n--) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLiveIn = liveIn[n];
RegisterPressure::Set& currentLiveOut = liveOut[n];
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
// temp will be the new LiveOut(n).
Uint32 nSuccessors = node.nSuccessors();
if (nSuccessors != 0) {
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
for (Uint32 s = 1; s < nSuccessors; s++)
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
} else
temp.clear();
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
// new LiveIn(n).
if (currentLiveOut != temp) {
currentLiveOut = temp;
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
temp |= currentLiveIn;
if (currentLiveIn != temp) {
currentLiveIn = temp;
changed = true;
}
}
}
} while(changed);
LivenessInfo<RegisterPressure> liveness;
liveness.liveIn = liveIn;
liveness.liveOut = liveOut;
DEBUG_LOG_ONLY(liveness.size = nNodes);
return liveness;
}
template <class RegisterPressure>
LivenessInfo<RegisterPressure> Liveness<RegisterPressure>::analysis(ControlGraph& controlGraph, Uint32 nameCount)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Allocate the temporary sets.
RegisterPressure::Set* killed = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
RegisterPressure::Set* usedByPhiNodes = NULL;
// Allocate the globals sets.
RegisterPressure::Set* liveIn = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
RegisterPressure::Set* liveOut = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
// First stage of the liveness analysis: Compute the sets LocalLive(stored in LiveIn) and Killed.
//
for (Uint32 n = 0; n < (nNodes - 1); n++) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLocalLive = liveIn[n];
RegisterPressure::Set& currentKilled = killed[n];
InstructionList& phiNodes = node.getPhiNodeInstructions();
if ((usedByPhiNodes == NULL) && !phiNodes.empty())
usedByPhiNodes = new(pool) RegisterPressure::Set[nNodes](pool, nameCount);
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
InstructionDefine& define = phiNode.getInstructionDefineBegin()[0];
currentKilled.set(define.getRegisterName());
typedef DoublyLinkedList<ControlEdge> ControlEdgeList;
const ControlEdgeList& predecessors = node.getPredecessors();
ControlEdgeList::iterator p = predecessors.begin();
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++, p = predecessors.advance(p))
if (usePtr->isRegister())
usedByPhiNodes[predecessors.get(p).getSource().dfsNum].set(usePtr->getRegisterName());
}
// Find the instructions contributions to the sets LocalLive and Killed.
//
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
// If a VirtualRegister is 'used' before being 'defined' then we add it to set LocalLive.
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
Uint32 index = usePtr->getRegisterName();
if (!currentKilled.test(index))
currentLocalLive.set(index);
}
// If a Virtualregister is 'defined' then we add it to the set Killed.
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentKilled.set(definePtr->getRegisterName());
}
}
// Second stage of the liveness analysis: We propagate the LiveIn & LiveOut through the entire
// control-flow graph.
//
RegisterPressure::Set temp(pool, nameCount);
bool changed;
do {
changed = false;
// For all nodes is this graph except the endNode.
for (Int32 n = (nNodes - 2); n >= 0; n--) {
ControlNode& node = *nodes[n];
RegisterPressure::Set& currentLiveIn = liveIn[n];
RegisterPressure::Set& currentLiveOut = liveOut[n];
// Compute temp = Union of LiveIn(s) (s a successor of this node) | usedByPhiNodes(n).
// temp will be the new LiveOut(n).
Uint32 nSuccessors = node.nSuccessors();
if (nSuccessors != 0) {
temp = liveIn[node.nthSuccessor(0).getTarget().dfsNum];
for (Uint32 s = 1; s < nSuccessors; s++)
temp |= liveIn[node.nthSuccessor(s).getTarget().dfsNum];
} else
temp.clear();
// Insert the phiNodes contribution.
if (usedByPhiNodes != NULL)
temp |= usedByPhiNodes[n];
// If temp and LiveOut(n) differ then set LiveOut(n) = temp and recalculate the
// new LiveIn(n).
if (currentLiveOut != temp) {
currentLiveOut = temp;
temp -= killed[n]; // FIX: could be optimized with one call to unionDiff !
temp |= currentLiveIn;
if (currentLiveIn != temp) {
currentLiveIn = temp;
changed = true;
}
}
}
} while(changed);
LivenessInfo<RegisterPressure> liveness;
liveness.liveIn = liveIn;
liveness.liveOut = liveOut;
DEBUG_LOG_ONLY(liveness.size = nNodes);
return liveness;
}
#ifdef DEBUG_LOG
template <class RegisterPressure>
void LivenessInfo<RegisterPressure>::printPretty(LogModuleObject log)
{
for (Uint32 n = 0; n < size; n++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Node N%d:\n\tliveIn = ", n));
liveIn[n].printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\tliveOut = "));
liveOut[n].printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
#endif // DEBUG_LOG
#endif // _LIVENESS_H_

View File

@@ -0,0 +1,40 @@
#! gmake
DEPTH = ../..
MODULE_NAME = RegisterAllocator
include $(DEPTH)/config/config.mk
INCLUDES += \
-I$(DEPTH)/Utilities/General \
-I$(DEPTH)/Utilities/zlib \
-I$(DEPTH)/Runtime/ClassReader \
-I$(DEPTH)/Runtime/NativeMethods \
-I$(DEPTH)/Runtime/System \
-I$(DEPTH)/Runtime/ClassInfo \
-I$(DEPTH)/Runtime/FileReader \
-I$(DEPTH)/Compiler/PrimitiveGraph \
-I$(DEPTH)/Compiler/FrontEnd \
-I$(DEPTH)/Compiler/Optimizer \
-I$(DEPTH)/Compiler/CodeGenerator \
-I$(DEPTH)/Compiler/CodeGenerator/md \
-I$(DEPTH)/Compiler/CodeGenerator/md/$(CPU_ARCH) \
-I$(DEPTH)/Compiler/RegisterAllocator \
-I$(DEPTH)/Driver/StandAloneJava \
-I$(DEPTH)/Debugger \
$(NULL)
CXXSRCS = \
RegisterAllocator.cpp \
RegisterAllocatorTools.cpp \
DominatorGraph.cpp \
VirtualRegister.cpp \
BitSet.cpp \
SparseSet.cpp \
$(NULL)
include $(DEPTH)/config/rules.mk
libs:: $(MODULE)

View File

@@ -0,0 +1,392 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _PHI_NODE_REMOVER_H_
#define _PHI_NODE_REMOVER_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "DominatorGraph.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h"
#include "Liveness.h"
#include "Instruction.h"
#include "InstructionEmitter.h"
#include "SparseSet.h"
#include <string.h>
//------------------------------------------------------------------------------
// RegisterNameNode -
struct RegisterNameNode
{
RegisterNameNode* next;
RegisterName newName;
Uint32 nextPushed;
};
//------------------------------------------------------------------------------
// CopyData -
struct CopyData
{
RegisterName source;
RegisterClassKind classKind;
Uint32 useCount;
bool isLiveOut;
RegisterName sourceNameToUse;
RegisterName temporaryName;
RegisterNameNode* newName;
};
//------------------------------------------------------------------------------
// PhiNodeRemover<RegisterPressure> -
template <class RegisterPressure>
struct PhiNodeRemover
{
// Replace the phi nodes by copy instructions.
static void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
};
// Split some of the critical edges and return true if there are still some
// in the graph after that.
//
static bool splitCriticalEdges(ControlGraph& /*cg*/)
{
// FIX: not implemented.
return true;
}
inline void pushName(Pool& pool, RegisterNameNode** stack, SparseSet& pushed, Uint32* nodeListPointer, RegisterName oldName, RegisterName newName)
{
RegisterNameNode& newNode = *new(pool) RegisterNameNode();
if (pushed.test(oldName))
(*stack)->newName = newName;
else {
newNode.newName = newName;
newNode.nextPushed = *nodeListPointer;
*nodeListPointer = oldName;
newNode.next = *stack;
*stack = &newNode;
pushed.set(oldName);
}
}
template <class RegisterPressure>
void PhiNodeRemover<RegisterPressure>::replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
// Initialize the local variables.
//
// When we insert the copies we will also need to create new VirtualRegisters for
// the insertion of temporaries. The maximum number of temporary register will not
// exceed the number of phiNodes in the primitive graph.
Uint32 nameCount = vrManager.getSize();
Uint32 maxNameCount = nameCount;
for (Uint32 n = 0; n < nNodes; n++)
maxNameCount += nodes[n]->getPhiNodes().length();
// If the CFG contains some critical edges (backward edge which source has more than one
// outgoing edge and destination has more than one incomimg edge) then we need the liveness
// information to be able to insert temporary copies.
RegisterPressure::Set* liveOut = NULL;
if (splitCriticalEdges(controlGraph))
liveOut = Liveness<LowRegisterPressure>::analysis(controlGraph, nameCount).liveOut;
DominatorGraph dGraph(controlGraph);
SparseSet pushed(pool, maxNameCount);
SparseSet destinationList(pool, maxNameCount);
SparseSet workList(pool, maxNameCount);
CopyData* copyStats = new(pool) CopyData[maxNameCount];
memset(copyStats, '\0', maxNameCount*sizeof(CopyData));
struct NodeStack {
Uint32* next;
Uint32* limit;
Uint32 pushedList;
};
// Allocate the node stack and initialize the node stack pointer.
NodeStack* nodeStack = new(pool) NodeStack[nNodes + 1];
NodeStack* nodeStackPtr = nodeStack;
// We start by the begin node.
Uint32 startNode = 0;
Uint32* next = &startNode;
Uint32* limit = &startNode + 1;
while (true) {
if (next == limit) {
// If there are no more node in the sibling, we have to pop the current
// frame from the stack and update the copyStats of the pushed nodes.
//
if (nodeStackPtr == nodeStack)
// We are at the bottom of the stack and there are no more nodes
// to look at. We are done !
break;
--nodeStackPtr;
// We are done with all the children of this node in the dominator tree.
// We need to update the copy information of all the new names pushed
// during the walk over this node.
Uint32 pushedList = nodeStackPtr->pushedList;
while (pushedList != 0) {
Uint32 nextName = copyStats[pushedList].newName->nextPushed;
copyStats[pushedList].newName = copyStats[pushedList].newName->next;
pushedList = nextName;
}
// restore the previous frame.
next = nodeStackPtr->next;
limit = nodeStackPtr->limit;
} else {
Uint32 currentNode = *next++;
Uint32 pushedList = 0;
// Initialize the sets.
pushed.clear();
destinationList.clear();
// STEP1:
// Walk the instruction list and to replace all the instruction uses with their new name.
// If the instruction is a phi node and its defined register is alive at the end of this
// block then we push the defined register into the stack.
//
ControlNode& node = *nodes[currentNode];
RegisterPressure::Set* currentLiveOut = (liveOut != NULL) ? &liveOut[currentNode] : (RegisterPressure::Set*) 0;
InstructionList& phiNodes = node.getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
InstructionUse* useEnd = phiNode.getInstructionUseEnd();
for (InstructionUse* usePtr = phiNode.getInstructionUseBegin(); usePtr < useEnd; usePtr++) {
assert(usePtr->isRegister());
RegisterName name = usePtr->getRegisterName();
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
usePtr->setRegisterName(copyStats[name].newName->newName);
}
if (currentLiveOut != NULL) {
// This is a phi node and we have to push its defined name if it is live
// at the end of the node. We only need to do this if the CFG has critical edges.
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd() && phiNode.getInstructionDefineBegin()[0].isRegister());
RegisterName name = phiNode.getInstructionDefineBegin()[0].getRegisterName();
if (currentLiveOut->test(name))
pushName(pool, &(copyStats[name].newName), pushed, &pushedList, name, name);
}
}
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (copyStats[name].newName != NULL && copyStats[name].newName->newName != name)
usePtr->setRegisterName(copyStats[name].newName->newName);
}
}
// STEP2:
// Look at this node's successors' phiNodes. We keep track of the number of time
// a VR will be used by another copy instruction and insert each definition into the
// destinationList. This is the only pass over this node's successors as we will
// get all the information we need in the CopyData structures.
//
ControlEdge* successorEdgeEnd = node.getSuccessorsEnd();
for (ControlEdge* successorEdgePtr = node.getSuccessorsBegin(); successorEdgePtr < successorEdgeEnd; successorEdgePtr++) {
Uint32 useIndex = successorEdgePtr->getIndex();
ControlNode& successor = successorEdgePtr->getTarget();
// Look at its phi nodes. The phi nodes are at the top of the instruction list. We exit
// as soon as we find an instruction which is not a phi node
InstructionList& phiNodes = successor.getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& phiNode = phiNodes.get(p);
assert((phiNode.getInstructionUseBegin() + useIndex) < phiNode.getInstructionUseEnd());
assert(phiNode.getInstructionDefineBegin() != phiNode.getInstructionDefineEnd());
InstructionUse& source = phiNode.getInstructionUseBegin()[useIndex];
InstructionDefine& destination = phiNode.getInstructionDefineBegin()[0];
assert(source.isRegister() && destination.isRegister());
RegisterName sourceName = source.getRegisterName();
RegisterName destinationName = destination.getRegisterName();
// Get the correct name for the source.
if (copyStats[sourceName].newName != NULL)
sourceName = copyStats[sourceName].newName->newName;
// Update the CopyData structures.
if ((sourceName != rnInvalid) && (sourceName != destinationName)) {
copyStats[destinationName].source = sourceName;
copyStats[destinationName].classKind = destination.getRegisterClass();
copyStats[destinationName].isLiveOut = (currentLiveOut != NULL) ? currentLiveOut->test(destinationName) : false;
copyStats[destinationName].sourceNameToUse = destinationName;
copyStats[sourceName].sourceNameToUse = sourceName;
copyStats[sourceName].useCount++;
destinationList.set(destinationName);
}
}
}
// STEP3:
// Insert into the worklist only the destination registers that will be not used in
// another copy instruction in this block.
//
assert(workList.getSize() == 0);
for (SparseSet::iterator d = destinationList.begin(); !destinationList.done(d); d = destinationList.advance(d)) {
Uint32 dest = destinationList.get(d);
if (copyStats[dest].useCount == 0)
workList.set(dest);
}
// STEP4:
// Insert the copy instructions.
//
Uint32 destinationListSize = destinationList.getSize();
InstructionList::iterator endOfTheNode = instructions.end();
// Find the right place to insert the copy instructions.
if (destinationListSize != 0)
while (instructions.get(endOfTheNode).getFlags() & ifControl)
endOfTheNode = instructions.retreat(endOfTheNode);
while (destinationListSize != 0) {
while(workList.getSize()) {
RegisterName destinationName = RegisterName(workList.getOne());
RegisterName sourceName = copyStats[destinationName].source;
workList.clear(destinationName);
if (copyStats[destinationName].isLiveOut && !copyStats[destinationName].temporaryName) {
// Lost copy problem.
copyStats[destinationName].isLiveOut = false;
RegisterName sourceName = destinationName;
RegisterClassKind classKind = copyStats[sourceName].classKind;
RegisterName destinationName = getName(vrManager.newVirtualRegister(classKind));
assert(destinationName < maxNameCount);
copyStats[destinationName].classKind = classKind;
copyStats[sourceName].useCount = 0;
// We need to insert a copy to a temporary register to keep the
// source register valid at the end of the node defining it.
// This copy will be inserted right after the phi node defining it.
RegisterName from = copyStats[sourceName].sourceNameToUse;
Instruction* definingPhiNode = vrManager.getVirtualRegister(from).getDefiningInstruction();
assert(definingPhiNode && (definingPhiNode->getFlags() & ifPhiNode) != 0);
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*definingPhiNode->getPrimitive(), fromID, toID);
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
definingPhiNode->getPrimitive()->getContainer()->getInstructions().addFirst(copy);
copyStats[sourceName].temporaryName = destinationName;
copyStats[sourceName].sourceNameToUse = destinationName;
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
}
// Insert the copy instruction at the end of the current node.
RegisterName from = copyStats[sourceName].sourceNameToUse;
RegisterClassKind classKind = copyStats[destinationName].classKind;
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
instructions.insertAfter(copy, endOfTheNode);
endOfTheNode = instructions.advance(endOfTheNode);
copyStats[sourceName].useCount = 0;
if (destinationList.test(sourceName) && copyStats[sourceName].isLiveOut)
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
copyStats[sourceName].isLiveOut = false;
copyStats[sourceName].sourceNameToUse = destinationName;
if (destinationList.test(sourceName))
workList.set(sourceName);
destinationList.clear(destinationName);
}
destinationListSize = destinationList.getSize();
if (destinationListSize != 0) {
RegisterName sourceName = RegisterName(destinationList.getOne());
RegisterName destinationName;
if (!copyStats[sourceName].temporaryName) {
// Cycle problem.
RegisterClassKind classKind = copyStats[sourceName].classKind;
destinationName = getName(vrManager.newVirtualRegister(classKind));
assert(destinationName < maxNameCount);
copyStats[destinationName].classKind = classKind;
copyStats[sourceName].temporaryName = destinationName;
// Insert the copy instruction at the end of the current node.
RegisterName from = copyStats[sourceName].sourceNameToUse;
RegisterID fromID = buildRegisterID(from, classKind);
RegisterID toID = buildRegisterID(destinationName, classKind);
Instruction& copy = emitter.newCopy(*vrManager.getVirtualRegister(from).getDefiningInstruction()->getPrimitive(), fromID, toID);
vrManager.getVirtualRegister(destinationName).setDefiningInstruction(copy);
instructions.insertAfter(copy, endOfTheNode);
endOfTheNode = instructions.advance(endOfTheNode);
} else
destinationName = copyStats[sourceName].temporaryName;
copyStats[sourceName].useCount = 0;
copyStats[sourceName].isLiveOut = false;
copyStats[sourceName].sourceNameToUse = destinationName;
pushName(pool, &(copyStats[sourceName].newName), pushed, &pushedList, sourceName, destinationName);
workList.set(sourceName);
}
}
nodeStackPtr->pushedList = pushedList;
nodeStackPtr->next = next;
nodeStackPtr->limit = limit;
++nodeStackPtr;
next = dGraph.getSuccessorsBegin(currentNode);
limit = dGraph.getSuccessorsEnd(currentNode);
}
}
}
#endif // _PHI_NODE_REMOVER_H_

View File

@@ -0,0 +1,155 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "LogModule.h"
#include "RegisterAllocator.h"
#include "RegisterPressure.h"
#include "RegisterAllocatorTools.h"
#include "PhiNodeRemover.h"
#include "LiveRange.h"
#include "Liveness.h"
#include "InterferenceGraph.h"
#include "LiveRangeGraph.h"
#include "Coalescing.h"
#include "Spilling.h"
#include "Coloring.h"
#include "Splits.h"
class Pool;
class ControlGraph;
class VirtualRegisterManager;
class InstructionEmitter;
UT_DEFINE_LOG_MODULE(RegAlloc);
void RegisterAllocator::allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
{
// Insert the phi node instructions. We want to do this to have a single defined register per instruction.
// If we keep the PhiNode (as a DataNode) and a PhiNode is of DoubleWordKind then we have to execute
// some special code for the high word annotation.
//
RegisterAllocatorTools::insertPhiNodeInstructions(controlGraph, emitter);
// Perform some tests on the instruction graph.
//
DEBUG_ONLY(RegisterAllocatorTools::testTheInstructionGraph(controlGraph, vrManager));
// Replace the phi node instructions by their equivalent copy instructions.
//
PhiNodeRemover<LowRegisterPressure>::replacePhiNodes(controlGraph, vrManager, emitter);
// Do the register allocation.
//
RegisterAllocator registerAllocator(pool, controlGraph, vrManager, emitter);
registerAllocator.doGraphColoring();
}
void RegisterAllocator::doGraphColoring()
{
// Initialize the liverange map.
//
initLiveRanges();
// Build the live ranges. We do this to compress the number of RegisterNames
// used in the insterference graph.
//
LiveRange<LowRegisterPressure>::build(*this);
// Remove unnecessary copies.
//
RegisterAllocatorTools::removeUnnecessaryCopies(*this);
for (Uint8 loop = 0; loop < 10; loop++) {
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********* RegisterAllocator loop %d *********\n", loop));
while(true) {
// Build the interference graph.
//
iGraph.build();
// Coalesce the copy instructions.
//
if (!Coalescing<LowRegisterPressure>::coalesce(*this))
break;
}
// Print the interference graph.
//
DEBUG_LOG_ONLY(iGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
// Calculate the spill costs.
//
Spilling<LowRegisterPressure>::calculateSpillCosts(*this);
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSpillCosts(*this));
// Calculate the split costs.
//
Splits<LowRegisterPressure>::calculateSplitCosts(*this);
DEBUG_LOG_ONLY(RegisterAllocatorTools::printSplitCosts(*this));
// Build the live range graph.
//
lGraph.build();
DEBUG_LOG_ONLY(lGraph.printPretty(UT_LOG_MODULE(RegAlloc)));
// Color the graph. If it succeeds then we're done with the
// register allocation.
//
if (Coloring<LowRegisterPressure>::color(*this)) {
// Write the final colors in the instruction graph.
//
Coloring<LowRegisterPressure>::finalColoring(*this);
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("********** RegisterAllocator done **********\n"));
DEBUG_LOG_ONLY(RegisterAllocatorTools::printInstructions(*this));
return;
}
// We need to spill some registers.
//
Spilling<LowRegisterPressure>::insertSpillCode(*this);
// Insert the split instructions.
//
Splits<LowRegisterPressure>::insertSplitCode(*this);
// Update the live ranges.
//
// FIX
}
#ifdef DEBUG_LOG
RegisterAllocatorTools::updateInstructionGraph(*this);
RegisterAllocatorTools::printInstructions(*this);
#endif
fprintf(stderr, "!!! Coloring failed after 10 loops !!!\n");
abort();
}
void RegisterAllocator::initLiveRanges()
{
Uint32 count = this->nameCount;
RegisterName* name2range = new(pool) RegisterName[nameCount];
for (RegisterName r = RegisterName(1); r < count; r = RegisterName(r + 1))
name2range[r] = r;
this->name2range = name2range;
rangeCount = count;
}

View File

@@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_ALLOCATOR_H_
#define _REGISTER_ALLOCATOR_H_
class Pool;
class ControlGraph;
class InstructionEmitter;
struct SpillCost;
struct SplitCost;
#include "Liveness.h"
#include "VirtualRegister.h"
#include "RegisterPressure.h" // This should included by Backend.cpp
#include "InterferenceGraph.h"
#include "LiveRangeGraph.h"
//template <class RegisterPressure>
class RegisterAllocator
{
public:
Pool& pool; //
ControlGraph& controlGraph; //
VirtualRegisterManager& vrManager; //
InstructionEmitter& emitter; //
RegisterName* name2range; //
RegisterName* color; //
SpillCost* spillCost; //
SparseSet* willSpill; //
SplitCost* splitCost; //
NameLinkedList** splitAround; //
InterferenceGraph<LowRegisterPressure> iGraph; //
LiveRangeGraph<LowRegisterPressure> lGraph; //
LivenessInfo<LowRegisterPressure> liveness; //
Uint32 nameCount; //
Uint32 rangeCount; //
bool splitFound; //
private:
//
//
void doGraphColoring();
public:
//
//
inline RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
//
//
bool canInterfere(RegisterName /*name1*/, RegisterName /*name2*/) const {return true;}
//
//
void initLiveRanges();
//
//
static void allocateRegisters(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter);
};
//
//
inline RegisterAllocator::RegisterAllocator(Pool& pool, ControlGraph& controlGraph, VirtualRegisterManager& vrManager, InstructionEmitter& emitter)
: pool(pool), controlGraph(controlGraph), vrManager(vrManager), emitter(emitter), iGraph(*this), lGraph(*this), nameCount(vrManager.getSize()) {}
#endif // _REGISTER_ALLOCATOR_H_

View File

@@ -0,0 +1,355 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "LogModule.h"
#include "RegisterAllocatorTools.h"
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Primitives.h"
#include "InstructionEmitter.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "Spilling.h"
#include "Splits.h"
#include "BitSet.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
#ifdef DEBUG
void RegisterAllocatorTools::testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
{
// Test the declared VirtualRegisters. The register allocator tries to condense the register universe.
// Any gap in the VirtualRegister names will be a loss of efficiency !!!!
Uint32 nameCount = vrManager.getSize();
BitSet registerSeen(controlGraph.pool, nameCount);
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
registerSeen.set(usePtr->getRegisterName());
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
registerSeen.set(definePtr->getRegisterName());
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
registerSeen.set(usePtr->getRegisterName());
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
registerSeen.set(definePtr->getRegisterName());
}
}
bool renameRegisters = false;
for (BitSet::iterator i = registerSeen.nextZero(0); !registerSeen.done(i); i = registerSeen.nextZero(i)) {
renameRegisters = true;
fprintf(stderr,
"WARNING: The VirtualRegister vr%d has been allocated during CodeGeneration but\n"
" is never used nor defined by any instruction in the instruction graph\n"
" PLEASE FIX \n",
i);
}
if (renameRegisters) {
Instruction** definingInstruction = new Instruction*[nameCount];
memset(definingInstruction, '\0', nameCount * sizeof(Instruction*));
RegisterName* newName = new RegisterName[nameCount];
memset(newName, '\0', nameCount * sizeof(RegisterName));
RegisterName nextName = RegisterName(1);
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
usePtr->setRegisterName(newName[name]);
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName name = definePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
definePtr->setRegisterName(newName[name]);
}
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName name = usePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
usePtr->setRegisterName(newName[name]);
}
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName name = definePtr->getRegisterName();
if (newName[name] == rnInvalid) {
newName[name] = nextName;
definingInstruction[nextName] = vrManager.getVirtualRegister(name).getDefiningInstruction();
nextName = RegisterName(nextName + 1);
}
definePtr->setRegisterName(newName[name]);
}
}
}
vrManager.setSize(nextName);
for (RegisterName r = RegisterName(1); r < nextName; r = RegisterName(r + 1))
vrManager.getVirtualRegister(r).definingInstruction = definingInstruction[r];
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("RegisterMap:\n"));
for (Uint32 i = 1; i < nameCount; i++)
if (newName[i] != 0)
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d becomes vr%d.\n", i, newName[i]));
else
UT_OBJECTLOG(UT_LOG_MODULE(RegAlloc), PR_LOG_ALWAYS, ("\tvr%d is dead.\n", i));
delete newName;
delete definingInstruction;
}
}
#endif // DEBUG
void RegisterAllocatorTools::removeUnnecessaryCopies(RegisterAllocator& registerAllocator)
{
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i);) {
Instruction& instruction = instructions.get(i);
i = instructions.advance(i);
if (instruction.getFlags() & ifCopy) {
assert(instruction.getInstructionUseBegin() != instruction.getInstructionUseEnd() && instruction.getInstructionUseBegin()[0].isRegister());
assert(instruction.getInstructionDefineBegin() != instruction.getInstructionDefineEnd() && instruction.getInstructionDefineBegin()[0].isRegister());
RegisterName source = name2range[instruction.getInstructionUseBegin()[0].getRegisterName()];
RegisterName destination = name2range[instruction.getInstructionDefineBegin()[0].getRegisterName()];
if (source == destination)
instruction.remove();
}
}
}
}
void RegisterAllocatorTools::updateInstructionGraph(RegisterAllocator& registerAllocator)
{
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
RegisterName* name2range = registerAllocator.name2range;
for (Uint32 n = 0; n < nNodes; n++) {
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
}
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
for (InstructionList::iterator p = phiNodes.begin(); !phiNodes.done(p); p = phiNodes.advance(p)) {
Instruction& instruction = phiNodes.get(p);
InstructionUse* useEnd = instruction.getInstructionUseEnd();
for (InstructionUse* usePtr = instruction.getInstructionUseBegin(); usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
usePtr->setRegisterName(name2range[usePtr->getRegisterName()]);
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
for (InstructionDefine* definePtr = instruction.getInstructionDefineBegin(); definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
definePtr->setRegisterName(name2range[definePtr->getRegisterName()]);
}
}
}
void RegisterAllocatorTools::insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter)
{
Pool& pool = controlGraph.pool;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
DoublyLinkedList<PhiNode>& phiNodes = node.getPhiNodes();
if (!phiNodes.empty()) {
// Set the index of the incoming edges.
Uint32 index = 0;
const DoublyLinkedList<ControlEdge>& predecessors = node.getPredecessors();
for (DoublyLinkedList<ControlEdge>::iterator p = predecessors.begin(); !predecessors.done(p); p = predecessors.advance(p))
predecessors.get(p).setIndex(index++);
// Insert the phi node instruction in the instruction list.
for (DoublyLinkedList<PhiNode>::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
PhiNode& phiNode = phiNodes.get(i);
ValueKind kind = phiNode.getKind();
if (!isStorableKind(kind))
continue;
RegisterClassKind classKind = rckGeneral; // FIX: get class kind from phi node kind.
Uint32 nInputs = phiNode.nInputs();
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drLow);
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drLow);
node.addPhiNodeInstruction(phiNodeInstruction);
if (isDoublewordKind(kind)) {
PhiNodeInstruction& phiNodeInstruction = *new(pool) PhiNodeInstruction(&phiNode, pool, nInputs);
emitter.defineProducer(phiNode, phiNodeInstruction, 0, classKind, drHigh);
for (Uint32 whichInput = 0; whichInput < nInputs; whichInput++)
emitter.useProducer(phiNode.nthInputVariable(whichInput), phiNodeInstruction, whichInput, classKind, drHigh);
node.addPhiNodeInstruction(phiNodeInstruction);
}
}
}
}
}
#ifdef DEBUG_LOG
void RegisterAllocatorTools::printSpillCosts(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
Uint32 rangeCount = registerAllocator.rangeCount;
SpillCost* cost = registerAllocator.spillCost;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Spill costs:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : ", i));
if (cost[i].infinite)
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("infinite\n"));
else
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("%f\n", cost[i].cost));
}
}
void RegisterAllocatorTools::printSplitCosts(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
Uint32 rangeCount = registerAllocator.rangeCount;
SplitCost* cost = registerAllocator.splitCost;
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("Split costs:\n"));
for (Uint32 i = 1; i < rangeCount; i++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\trange %d : loads = %f stores = %f\n", i, cost[i].loads, cost[i].stores));
}
}
void RegisterAllocatorTools::printInstructions(RegisterAllocator& registerAllocator)
{
LogModuleObject log = UT_LOG_MODULE(RegAlloc);
ControlNode** nodes = registerAllocator.controlGraph.dfsList;
Uint32 nNodes = registerAllocator.controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("N%d:\n", n));
InstructionList& phiNodes = nodes[n]->getPhiNodeInstructions();
InstructionList& instructions = nodes[n]->getInstructions();
if (!phiNodes.empty()) {
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" PhiNodes:\n", n));
for(InstructionList::iterator i = phiNodes.begin(); !phiNodes.done(i); i = phiNodes.advance(i)) {
phiNodes.get(i).printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
if (!instructions.empty())
UT_OBJECTLOG(log, PR_LOG_ALWAYS, (" Instructions:\n", n));
}
for(InstructionList::iterator i = instructions.begin(); !instructions.done(i); i = instructions.advance(i)) {
instructions.get(i).printPretty(log);
UT_OBJECTLOG(log, PR_LOG_ALWAYS, ("\n"));
}
}
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,117 @@
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
//
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
// NETSCAPE COMMUNICATIONS CORPORATION
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
// Reserved. Use of this Source Code is subject to the terms of the
// applicable license agreement from Netscape Communications Corporation.
// The copyright notice(s) in this Source Code does not indicate actual or
// intended publication of this Source Code.
//
// $Id: RegisterAllocatorTools.h,v 1.1.2.1 1999-03-02 16:12:05 fur%netscape.com Exp $
//
#ifndef _REGISTER_ALLOCATOR_TOOLS_H_
#define _REGISTER_ALLOCATOR_TOOLS_H_
#include "LogModule.h"
#include "RegisterTypes.h"
#include <string.h>
class RegisterAllocator;
class ControlGraph;
class InstructionEmitter;
class VirtualRegisterManager;
struct RegisterAllocatorTools
{
//
//
static void insertPhiNodeInstructions(ControlGraph& controlGraph, InstructionEmitter& emitter);
//
//
static void updateInstructionGraph(RegisterAllocator& registerAllocator);
//
//
static void removeUnnecessaryCopies(RegisterAllocator& registerAllocator);
#ifdef DEBUG
//
//
static void testTheInstructionGraph(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
#endif // DEBUG
#ifdef DEBUG_LOG
//
//
static void printInstructions(RegisterAllocator& registerAllocator);
//
//
static void printSpillCosts(RegisterAllocator& registerAllocator);
//
//
static void printSplitCosts(RegisterAllocator& registerAllocator);
#endif // DEBUG_LOG
};
//
// FIX: this should go in a class (LookupTable ?)
//
inline RegisterName findRoot(RegisterName name, RegisterName* table)
{
RegisterName* stack = table;
RegisterName* stackPtr = stack;
RegisterName newName;
while((newName = table[name]) != name) {
*--stackPtr = name;
name = newName;
}
while (stackPtr != stack)
table[*stackPtr++] = name;
return name;
}
inline void init(RegisterName* table, Uint32 nameCount)
{
for (RegisterName r = RegisterName(0); r < nameCount; r = RegisterName(r + 1))
table[r] = r;
}
inline Uint32 compress(RegisterName* name2range, RegisterName* table, Uint32 nameCount, Uint32 tableSize)
{
RegisterName* liveRange = new RegisterName[tableSize];
memset(liveRange, '\0', tableSize * sizeof(RegisterName));
// Update the lookup table.
for (RegisterName r = RegisterName(1); r < tableSize; r = RegisterName(r + 1))
findRoot(r, table);
// Count the liveranges.
Uint32 liveRangeCount = 1;
for (RegisterName s = RegisterName(1); s < tableSize; s = RegisterName(s + 1))
if (table[s] == s)
liveRange[s] = RegisterName(liveRangeCount++);
for (RegisterName t = RegisterName(1); t < nameCount; t = RegisterName(t + 1))
name2range[t] = liveRange[table[name2range[t]]];
return liveRangeCount;
}
inline double doLog10(Uint32 power)
{
double log = 1.0;
while (power--)
log *= 10.0;
return log;
}
#endif // _REGISTER_ALLOCATOR_TOOLS_H_

View File

@@ -0,0 +1,38 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_ASSIGNER_H_
#define _REGISTER_ASSIGNER_H_
#include "Fundamentals.h"
#include "VirtualRegister.h"
class FastBitMatrix;
class RegisterAssigner
{
protected:
VirtualRegisterManager& vRegManager;
public:
RegisterAssigner(VirtualRegisterManager& vrMan) : vRegManager(vrMan) {}
virtual bool assignRegisters(FastBitMatrix& interferenceMatrix) = 0;
};
#endif /* _REGISTER_ASSIGNER_H_ */

View File

@@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_CLASS_H_
#define _REGISTER_CLASS_H_
#include "Fundamentals.h"
#include "RegisterTypes.h"
#endif // _REGISTER_CLASS_H_

View File

@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_PRESSURE_H_
#define _REGISTER_PRESSURE_H_
#include "BitSet.h"
#include "HashSet.h"
struct LowRegisterPressure
{
typedef BitSet Set;
static const bool setIsOrdered = true;
};
struct HighRegisterPressure
{
typedef HashSet Set;
static const bool setIsOrdered = false;
};
#endif // _REGISTER_PRESSURE_H_

View File

@@ -0,0 +1,104 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _REGISTER_TYPES_H_
#define _REGISTER_TYPES_H_
#include "Fundamentals.h"
//------------------------------------------------------------------------------
// RegisterName -
//
enum RegisterName {
rnInvalid = 0,
};
//------------------------------------------------------------------------------
// RegisterClassKind -
//
enum RegisterClassKind {
rckInvalid = 0,
rckGeneral,
rckStackSlot,
nRegisterClassKind
};
//------------------------------------------------------------------------------
// RegisterID -
//
enum RegisterID {
invalidID = 0
};
//------------------------------------------------------------------------------
// RegisterKind -
//
enum RegisterKind {
rkCallerSave = 0,
rkCalleeSave,
};
struct NameLinkedList {
RegisterName name;
NameLinkedList* next;
};
#ifdef DEBUG
const registerNameMask = 0x03ffffff;
const coloredRegisterMask = 0x04000000;
const machineRegisterMask = 0x08000000;
const registerClassMask = 0xf0000000;
const registerNameShift = 0;
const coloredRegisterShift = 26;
const machineRegisterShift = 27;
const registerClassShift = 28;
#else // DEBUG
const registerNameMask = 0x0fffffff;
const registerClassMask = 0xf0000000;
const registerNameShift = 0;
const registerClassShift = 28;
#endif // DEBUG
inline RegisterClassKind getClass(RegisterID registerID) {return RegisterClassKind((registerID & registerClassMask) >> registerClassShift);}
inline RegisterName getName(RegisterID registerID) {return RegisterName((registerID & registerNameMask) >> registerNameShift);}
inline void setClass(RegisterID& registerID, RegisterClassKind classKind) {registerID = RegisterID((registerID & ~registerClassMask) | ((classKind << registerClassShift) & registerClassMask));}
inline void setName(RegisterID& registerID, RegisterName name) {assert((name & ~registerNameMask) == 0); registerID = RegisterID((registerID & ~registerNameMask) | ((name << registerNameShift) & registerNameMask));}
inline RegisterID buildRegisterID(RegisterName name, RegisterClassKind classKind) {return RegisterID(((classKind << registerClassShift) & registerClassMask) | ((name << registerNameShift) & registerNameMask));}
#ifdef DEBUG
inline bool isMachineRegister(RegisterID rid) {return (rid & machineRegisterMask) != 0;}
inline void setMachineRegister(RegisterID& rid) {rid = RegisterID(rid | machineRegisterMask);}
inline bool isColoredRegister(RegisterID rid) {return (rid & coloredRegisterMask) != 0;}
inline void setColoredRegister(RegisterID& rid) {rid = RegisterID(rid | coloredRegisterMask);}
#endif // DEBUG
#endif // _REGISTER_TYPES_H_

View File

@@ -0,0 +1,32 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "SSATools.h"
#include "ControlGraph.h"
#include "VirtualRegister.h"
#include "Liveness.h"
void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager)
{
if (!controlGraph.hasBackEdges)
return;
Liveness liveness(controlGraph.pool);
liveness.buildLivenessAnalysis(controlGraph, vrManager);
}

View File

@@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SSA_TOOLS_H_
#define _SSA_TOOLS_H_
#include "Fundamentals.h"
class ControlGraph;
class VirtualRegisterManager;
extern void replacePhiNodes(ControlGraph& controlGraph, VirtualRegisterManager& vrManager);
#endif // _SSA_TOOLS_H_

View File

@@ -0,0 +1,37 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "SparseSet.h"
#include "BitSet.h"
#include "Pool.h"
#ifdef DEBUG_LOG
// Print the set.
//
void SparseSet::printPretty(LogModuleObject log)
{
Pool pool;
BitSet set(pool, universeSize);
for (Uint32 i = 0; i < count; i++)
set.set(node[i].element);
set.printPretty(log);
}
#endif // DEBUG_LOG

View File

@@ -0,0 +1,168 @@
// -*- mode:C++; tab-width:4; truncate-lines:t -*-
//
// CONFIDENTIAL AND PROPRIETARY SOURCE CODE OF
// NETSCAPE COMMUNICATIONS CORPORATION
// Copyright © 1996, 1997 Netscape Communications Corporation. All Rights
// Reserved. Use of this Source Code is subject to the terms of the
// applicable license agreement from Netscape Communications Corporation.
// The copyright notice(s) in this Source Code does not indicate actual or
// intended publication of this Source Code.
//
// $Id: SparseSet.h,v 1.1.2.1 1999-03-02 16:12:07 fur%netscape.com Exp $
//
#ifndef _SPARSE_SET_H_
#define _SPARSE_SET_H_
#include "Fundamentals.h"
#include "Pool.h"
#include "LogModule.h"
#include "BitSet.h"
class SparseSet
{
private:
struct Node {
Uint32 element;
Uint32 stackIndex;
};
Node* node;
Uint32 count;
Uint32 universeSize;
private:
// No copy constructor.
SparseSet(const SparseSet&);
// Check if the given set's universe is of the same size than this universe.
void checkUniverseCompatibility(const SparseSet& set) const {assert(set.universeSize == universeSize);}
// Check if pos is valid for this set's universe.
void checkMember(Int32 pos) const {assert(pos >=0 && Uint32(pos) < universeSize);}
public:
SparseSet(Pool& pool, Uint32 universeSize) : universeSize(universeSize) {node = new(pool) Node[universeSize]; clear();}
// Clear the sparse set.
void clear() {count = 0;}
// Clear the element at index.
inline void clear(Uint32 index);
// Set the element at index.
inline void set(Uint32 index);
// Return true if the element at index is set.
inline bool test(Uint32 index) const;
// Union with the given sparse set.
inline void or(const SparseSet& set);
// Intersection with the given sparse set.
inline void and(const SparseSet& set);
// Difference with the given sparse set.
inline void difference(const SparseSet& set);
// Copy set.
inline SparseSet& operator = (const SparseSet& set);
inline SparseSet& operator = (const BitSet& set);
// Return true if the sparse sets are identical.
friend bool operator == (const SparseSet& set1, const SparseSet& set2);
// Return true if the sparse sets are different.
friend bool operator != (const SparseSet& set1, const SparseSet& set2);
// Logical operators.
SparseSet& operator |= (const SparseSet& set) {or(set); return *this;}
SparseSet& operator &= (const SparseSet& set) {and(set); return *this;}
SparseSet& operator -= (const SparseSet& set) {difference(set); return *this;}
// Iterator to conform with the set API.
typedef Int32 iterator;
// Return the iterator for the first element of this set.
iterator begin() const {return count - 1;}
// Return the next iterator.
iterator advance(iterator pos) const {return --pos;}
// Return true if the iterator is at the end of the set.
bool done(iterator pos) const {return pos < 0;}
// Return the element for the given iterator;
Uint32 get(iterator pos) const {return node[pos].element;}
// Return one element of this set.
Uint32 getOne() const {assert(count > 0); return node[0].element;}
// Return the size of this set.
Uint32 getSize() const {return count;}
#ifdef DEBUG_LOG
// Print the set.
void printPretty(LogModuleObject log);
#endif // DEBUG_LOG
};
inline void SparseSet::clear(Uint32 element)
{
checkMember(element);
Uint32 count = this->count;
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
if ((stackIndex < count) && (node[stackIndex].element == element)) {
Uint32 stackTop = node[count - 1].element;
node[stackIndex].element = stackTop;
node[stackTop].stackIndex = stackIndex;
this->count = count - 1;
}
}
inline void SparseSet::set(Uint32 element)
{
checkMember(element);
Uint32 count = this->count;
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
if ((stackIndex >= count) || (node[stackIndex].element != element)) {
node[count].element = element;
node[element].stackIndex = count;
this->count = count + 1;
}
}
inline bool SparseSet::test(Uint32 element) const
{
checkMember(element);
Node* node = this->node;
Uint32 stackIndex = node[element].stackIndex;
return ((stackIndex < count) && (node[stackIndex].element == element));
}
inline SparseSet& SparseSet::operator = (const SparseSet& set)
{
checkUniverseCompatibility(set);
Uint32 sourceCount = set.getSize();
Node* node = this->node;
memcpy(node, set.node, sourceCount * sizeof(Node));
for (Uint32 i = 0; i < sourceCount; i++) {
Uint32 element = node[i].element;
node[element].stackIndex = i;
}
count = sourceCount;
return *this;
}
inline SparseSet& SparseSet::operator = (const BitSet& set)
{
// FIX: there's room for optimization here.
assert(universeSize == set.getSize());
clear();
for (Int32 i = set.firstOne(); i != -1; i = set.nextOne(i))
this->set(i);
return *this;
}
#endif // _SPARSE_SET_H_

View File

@@ -0,0 +1,270 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef NEW_LAURENTM_CODE
#define INCLUDE_EMITTER
#include "CpuInfo.h"
#include "Fundamentals.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "InstructionEmitter.h"
#include "Spilling.h"
void Spilling::
insertSpillCode(ControlNode** dfsList, Uint32 nNodes)
{
PRUint32 nVirtualRegisters = vRegManager.count();
FastBitSet currentLive(vRegManager.pool, nVirtualRegisters);
FastBitSet usedInThisInstruction(vRegManager.pool, nVirtualRegisters);
RegisterFifo grNeedLoad(nVirtualRegisters);
RegisterFifo fpNeedLoad(nVirtualRegisters);
for (PRInt32 n = nNodes - 1; n >= 0; n--)
{
PR_ASSERT(grNeedLoad.empty() & fpNeedLoad.empty());
ControlNode& node = *dfsList[n];
currentLive = node.liveAtEnd;
PRUint32 nGeneralAlive = 0;
PRUint32 nFloatingPointAlive = 0;
// Get the number of registers alive at the end of this node.
for (PRInt32 j = currentLive.firstOne(); j != -1; j = currentLive.nextOne(j))
{
VirtualRegister& vReg = vRegManager.getVirtualRegister(j);
if (vReg.spillInfo.willSpill)
{
currentLive.clear(j);
}
else
{
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive++;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive++;
break;
default:
break;
}
}
}
// if(node.dfsNum == 8) printf("\n________Begin Node %d________\n", node.dfsNum);
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i))
{
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defEnd = instruction.getInstructionDefineEnd();
InstructionDefine* defPtr;
// if(node.dfsNum == 8) { printf("\n");
// instruction.printPretty(stdout);
// printf("\n"); }
// Handle definitions
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
if (defPtr->isVirtualRegister())
{
VirtualRegister& vReg = defPtr->getVirtualRegister();
currentLive.clear(vReg.getRegisterIndex());
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive--;
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive--;
break;
default:
break;
}
}
// Check for deaths
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isVirtualRegister())
{
VirtualRegister& vReg = usePtr->getVirtualRegister();
if (!currentLive.test(vReg.getRegisterIndex()))
// This is the last use of this register.
{
currentLive.set(vReg.getRegisterIndex());
switch (vReg.getClass())
{
case vrcInteger:
nGeneralAlive++;
while (/*(nGeneralAlive > NUMBER_OF_GREGISTERS) &&*/ !grNeedLoad.empty())
{
PRUint32 toLoad = grNeedLoad.get();
currentLive.clear(toLoad);
nGeneralAlive--;
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
nReg.releaseSelf();
}
break;
case vrcFloatingPoint:
case vrcFixedPoint:
nFloatingPointAlive++;
while (/*(nFloatingPointAlive > NUMBER_OF_FPREGISTERS) &&*/ !fpNeedLoad.empty())
{
PRUint32 toLoad = fpNeedLoad.get();
currentLive.clear(toLoad);
nFloatingPointAlive--;
VirtualRegister& nReg = vRegManager.getVirtualRegister(toLoad);
Instruction& lastUsingInstruction = *nReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUsingInstruction.getPrimitive(), lastUsingInstruction.getLinks().prev,
nReg.getAlias(), *nReg.equivalentRegister[vrcStackSlot]);
nReg.releaseSelf();
}
break;
default:
break;
}
}
}
// Handle uses
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isVirtualRegister())
{
VirtualRegister& vReg = usePtr->getVirtualRegister();
PRUint32 registerIndex = vReg.getRegisterIndex();
if (vReg.spillInfo.willSpill) {
#if defined(GENERATE_FOR_X86)
if (!instruction.switchUseToSpill((usePtr - useBegin), *vReg.equivalentRegister[vrcStackSlot]))
#endif
{
switch (vReg.getClass())
{
case vrcInteger:
if (!grNeedLoad.test(registerIndex))
{
grNeedLoad.put(registerIndex);
VirtualRegister& alias = vRegManager.newVirtualRegister(vrcInteger);
if (vReg.isPreColored())
alias.preColorRegister(vReg.getPreColor());
/* if (vReg.hasSpecialInterference) {
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
alias.specialInterference = vReg.specialInterference;
alias.hasSpecialInterference = true;
} */
vReg.setAlias(alias);
vReg.retainSelf();
}
break;
case vrcFloatingPoint:
case vrcFixedPoint:
if (!fpNeedLoad.test(registerIndex))
{
fpNeedLoad.put(registerIndex);
VirtualRegister& alias = vRegManager.newVirtualRegister(vReg.getClass());
if (vReg.isPreColored())
alias.preColorRegister(vReg.getPreColor());
/*if (vReg.hasSpecialInterference) {
alias.specialInterference.sizeTo(NUMBER_OF_REGISTERS);
alias.specialInterference = vReg.specialInterference;
alias.hasSpecialInterference = true;
} */
vReg.setAlias(alias);
vReg.retainSelf();
}
break;
default:
break;
}
usePtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
usedInThisInstruction.set(registerIndex);
vReg.spillInfo.lastUsingInstruction = &instruction;
}
currentLive.clear(registerIndex);
} else { // will not spill
currentLive.set(registerIndex);
}
}
// Handle definitions
for (defPtr = defBegin; defPtr < defEnd; defPtr++)
if (defPtr->isVirtualRegister())
{
VirtualRegister& vReg = defPtr->getVirtualRegister();
if (vReg.spillInfo.willSpill)
#if defined(GENERATE_FOR_X86)
if (!instruction.switchDefineToSpill((defPtr - defBegin), *vReg.equivalentRegister[vrcStackSlot]))
#endif
{
if (usedInThisInstruction.test(vReg.getRegisterIndex()))
// this virtualRegister was used in this instruction and is also defined. We need to move
// this virtual register to its alias first and then save it to memory.
{
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
vReg.getAlias(), *vReg.equivalentRegister[vrcStackSlot]);
defPtr->getVirtualRegisterPtr().initialize(vReg.getAlias());
}
else
{
emitter.emitStoreAfter(*instruction.getPrimitive(), &instruction.getLinks(),
vReg, *vReg.equivalentRegister[vrcStackSlot]);
}
}
}
}
while (!grNeedLoad.empty())
{
PRUint32 nl = grNeedLoad.get();
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
nlReg.releaseSelf();
}
while (!fpNeedLoad.empty())
{
PRUint32 nl = fpNeedLoad.get();
VirtualRegister& nlReg = vRegManager.getVirtualRegister(nl);
Instruction& lastUse = *nlReg.spillInfo.lastUsingInstruction;
emitter.emitLoadAfter(*lastUse.getPrimitive(), lastUse.getLinks().prev,
nlReg.getAlias(), *nlReg.equivalentRegister[vrcStackSlot]);
nlReg.releaseSelf();
}
// if(node.dfsNum == 8) printf("\n________End Node %d________\n", node.dfsNum);
}
}
#endif

View File

@@ -0,0 +1,269 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPILLING_H_
#define _SPILLING_H_
#include "Fundamentals.h"
#include <string.h>
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "SparseSet.h"
template <class RegisterPressure>
class Spilling
{
private:
static void insertStoreAfter(Instruction& instruction, RegisterName name);
static void insertLoadBefore(Instruction& instruction, RegisterName name);
public:
static void calculateSpillCosts(RegisterAllocator& registerAllocator);
static void insertSpillCode(RegisterAllocator& registerAllocator);
};
struct SpillCost
{
double loads;
double stores;
double copies;
double cost;
bool infinite;
};
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertSpillCode(RegisterAllocator& registerAllocator)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
Pool& pool = registerAllocator.pool;
SparseSet currentLive(pool, rangeCount);
SparseSet needLoad(pool, rangeCount);
SparseSet mustSpill(pool, rangeCount);
SparseSet& willSpill = *registerAllocator.willSpill;
ControlGraph& controlGraph = registerAllocator.controlGraph;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
needLoad.clear();
currentLive = liveOut[n];
mustSpill = currentLive;
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i);) {
Instruction& instruction = instructions.get(i);
i = instructions.retreat(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
bool foundLiveDefine = false;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
if (currentLive.test(name2range[definePtr->getRegisterName()])) {
foundLiveDefine = true;
break;
}
} else {
foundLiveDefine = true;
break;
}
if (defineBegin != defineEnd && !foundLiveDefine) {
fprintf(stderr, "!!! Removed instruction because it was only defining unused registers !!!\n");
instruction.remove();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName range = name2range[definePtr->getRegisterName()];
#ifdef DEBUG
if (needLoad.test(range))
if (!mustSpill.test(range) && registerAllocator.spillCost[range].infinite && willSpill.test(range)) {
fprintf(stderr, "Tried to spill a register with infinite spill cost\n");
abort();
}
#endif // DEBUG
if (willSpill.test(range))
insertStoreAfter(instruction, range);
needLoad.clear(range);
}
if (instruction.getFlags() & ifCopy)
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
if (!currentLive.test(range))
for (SparseSet::iterator r = needLoad.begin(); !needLoad.done(r); r = needLoad.advance(r)) {
RegisterName load = RegisterName(needLoad.get(r));
if (willSpill.test(load))
insertLoadBefore(instruction, load);
mustSpill.set(load);
}
needLoad.clear();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
currentLive.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
currentLive.set(range);
needLoad.set(range);
}
}
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
RegisterName load = RegisterName(needLoad.get(l));
if (willSpill.test(load))
insertLoadBefore(instructions.first(), load);
}
}
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertLoadBefore(Instruction& /*instruction*/, RegisterName name)
{
fprintf(stdout, "will insert load for range %d\n", name);
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::insertStoreAfter(Instruction& /*instruction*/, RegisterName name)
{
fprintf(stdout, "will insert store for range %d\n", name);
}
template <class RegisterPressure>
void Spilling<RegisterPressure>::calculateSpillCosts(RegisterAllocator& registerAllocator)
{
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
Pool& pool = registerAllocator.pool;
SparseSet live(pool, rangeCount);
SparseSet needLoad(pool, rangeCount);
SparseSet mustSpill(pool, rangeCount);
SparseSet alreadyStored(pool, rangeCount); // FIX: should get this from previous spilling.
SpillCost* cost = new SpillCost[rangeCount];
memset(cost, '\0', rangeCount * sizeof(SpillCost));
ControlGraph& controlGraph = registerAllocator.controlGraph;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
double weight = doLog10(node.loopDepth);
needLoad.clear();
live = liveOut[n];
mustSpill = live;
InstructionList& instructions = nodes[n]->getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister()) {
RegisterName range = name2range[definePtr->getRegisterName()];
if (needLoad.test(range))
if (!mustSpill.test(range))
cost[range].infinite = true;
if ((false /* !rematerializable(range) */ || !needLoad.test(range)) && !alreadyStored.test(range))
cost[range].stores += weight;
needLoad.clear(range);
}
if (instruction.getFlags() & ifCopy)
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
if (!live.test(name2range[usePtr->getRegisterName()])) {
for (SparseSet::iterator l = needLoad.begin(); !needLoad.done(l); l = needLoad.advance(l)) {
Uint32 range = needLoad.get(l);
cost[range].loads += weight;
mustSpill.set(range);
}
needLoad.clear();
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
live.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
live.set(range);
needLoad.set(range);
}
if (instruction.getFlags() & ifCopy) {
assert(useBegin != useEnd && useBegin[0].isRegister());
assert(defineBegin != defineEnd && defineBegin[0].isRegister());
RegisterName source = name2range[useBegin[0].getRegisterName()];
RegisterName destination = name2range[defineBegin[0].getRegisterName()];
cost[source].copies += weight;
cost[destination].copies += weight;
}
}
for (SparseSet::iterator s = needLoad.begin(); !needLoad.done(s); s = needLoad.advance(s))
cost[needLoad.get(s)].loads += weight;
}
for (Uint32 r = 0; r < rangeCount; r++) {
SpillCost& c = cost[r];
c.cost = 2 * (c.loads + c.stores) - c.copies;
}
registerAllocator.spillCost = cost;
}
#endif // _SPILLING_H_

View File

@@ -0,0 +1,239 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _SPLITS_H_
#define _SPLITS_H_
#include "Fundamentals.h"
#include <string.h>
#include "Pool.h"
#include "ControlGraph.h"
#include "ControlNodes.h"
#include "Instruction.h"
#include "RegisterAllocator.h"
#include "RegisterAllocatorTools.h"
UT_EXTERN_LOG_MODULE(RegAlloc);
template <class RegisterPressure>
struct Splits
{
static void calculateSplitCosts(RegisterAllocator& registerAllocator);
static bool findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range);
static void insertSplitCode(RegisterAllocator& registerAllocator);
};
struct SplitCost
{
double loads;
double stores;
};
template <class RegisterPressure>
void Splits<RegisterPressure>::insertSplitCode(RegisterAllocator& /*registerAllocator*/)
{
// FIX
}
template <class RegisterPressure>
bool Splits<RegisterPressure>::findSplit(RegisterAllocator& registerAllocator, RegisterName* color, RegisterName range)
{
Pool& pool = registerAllocator.pool;
NameLinkedList** neighborsWithColor = new(pool) NameLinkedList*[6]; // FIX
memset(neighborsWithColor, '\0', 6 * sizeof(NameLinkedList*));
InterferenceGraph<RegisterPressure>& iGraph = registerAllocator.iGraph;
for (InterferenceVector* vector = iGraph.getInterferenceVector(range); vector != NULL; vector = vector->next)
for (Int32 i = vector->count - 1; i >=0; --i) {
RegisterName neighbor = vector->neighbors[i];
RegisterName c = color[neighbor];
if (c < 6) { // FIX
NameLinkedList* node = new(pool) NameLinkedList();
node->name = neighbor;
node->next = neighborsWithColor[c];
neighborsWithColor[c] = node;
}
}
bool splitAroundName = true;
LiveRangeGraph<RegisterPressure>& lGraph = registerAllocator.lGraph;
RegisterName bestColor = RegisterName(6); // FIX
double bestCost = registerAllocator.spillCost[range].cost;
SplitCost* splitCost = registerAllocator.splitCost;
for (RegisterName i = RegisterName(0); i < 6; i = RegisterName(i + 1)) { // FIX
double splitAroundNameCost = 0.0;
bool canSplitAroundName = true;
SplitCost& sCost = splitCost[range];
double addedCost = 2.0 * (sCost.stores + sCost.loads);
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
RegisterName neighbor = node->name;
if (lGraph.haveEdge(neighbor, range)) {
canSplitAroundName = false;
break;
} else
splitAroundNameCost += addedCost;
}
if (canSplitAroundName && splitAroundNameCost < bestCost) {
bestCost = splitAroundNameCost;
bestColor = i;
splitAroundName = true;
}
double splitAroundColorCost = 0.0;
bool canSplitAroundColor = true;
for (NameLinkedList* node = neighborsWithColor[i]; node != NULL; node = node->next) {
RegisterName neighbor = node->name;
if (lGraph.haveEdge(range, neighbor)) {
canSplitAroundColor = false;
break;
} else {
SplitCost& sCost = splitCost[neighbor];
double addedCost = 2.0 * (sCost.stores + sCost.loads);
splitAroundColorCost += addedCost;
}
}
if (canSplitAroundColor && splitAroundColorCost < bestCost) {
bestCost = splitAroundColorCost;
bestColor = i;
splitAroundName = false;
}
}
if (bestColor < RegisterName(6)) {
color[range] = bestColor;
registerAllocator.splitFound = true;
NameLinkedList** splitAround = registerAllocator.splitAround;
if (splitAroundName)
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
NameLinkedList* newNode = new(pool) NameLinkedList();
newNode->name = node->name;
newNode->next = splitAround[range];
splitAround[range] = newNode;
}
else
for (NameLinkedList* node = neighborsWithColor[bestColor]; node != NULL; node = node->next) {
NameLinkedList* newNode = new(pool) NameLinkedList();
RegisterName neighbor = node->name;
newNode->name = range;
newNode->next = splitAround[neighbor];
splitAround[neighbor] = newNode;
}
trespass("Found a split");
return true;
}
return false;
}
template <class RegisterPressure>
void Splits<RegisterPressure>::calculateSplitCosts(RegisterAllocator& registerAllocator)
{
Pool& pool = registerAllocator.pool;
Uint32 rangeCount = registerAllocator.rangeCount;
RegisterName* name2range = registerAllocator.name2range;
SplitCost* splitCost = new(pool) SplitCost[rangeCount];
memset(splitCost, '\0', rangeCount * sizeof(SplitCost));
SparseSet live(pool, rangeCount);
RegisterPressure::Set* liveIn = registerAllocator.liveness.liveIn;
RegisterPressure::Set* liveOut = registerAllocator.liveness.liveOut;
ControlGraph& controlGraph = registerAllocator.controlGraph;
ControlNode** nodes = controlGraph.dfsList;
Uint32 nNodes = controlGraph.nNodes;
for (Uint32 n = 0; n < nNodes; n++) {
ControlNode& node = *nodes[n];
double weight = doLog10(node.loopDepth);
live = liveOut[n];
ControlEdge* successorsEnd = node.getSuccessorsEnd();
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++) {
ControlNode& successor = successorsPtr->getTarget();
if (successor.getControlKind() != ckEnd) {
RegisterPressure::Set& successorLiveIn = liveIn[successor.dfsNum];
for (SparseSet::iterator i = live.begin(); !live.done(i); i = live.advance(i)) {
RegisterName name = RegisterName(live.get(i));
if (!successorLiveIn.test(name))
splitCost[name].loads += doLog10(successor.loopDepth);
}
}
}
InstructionList& instructions = node.getInstructions();
for (InstructionList::iterator i = instructions.end(); !instructions.done(i); i = instructions.retreat(i)) {
Instruction& instruction = instructions.get(i);
InstructionUse* useBegin = instruction.getInstructionUseBegin();
InstructionUse* useEnd = instruction.getInstructionUseEnd();
InstructionUse* usePtr;
InstructionDefine* defineBegin = instruction.getInstructionDefineBegin();
InstructionDefine* defineEnd = instruction.getInstructionDefineEnd();
InstructionDefine* definePtr;
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
splitCost[name2range[definePtr->getRegisterName()]].stores += weight;
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister()) {
RegisterName range = name2range[usePtr->getRegisterName()];
if (!live.test(range)) {
if (&instruction != &instructions.last())
splitCost[range].loads += weight;
else {
ControlEdge* successorsEnd = node.getSuccessorsEnd();
for (ControlEdge* successorsPtr = node.getSuccessorsBegin(); successorsPtr < successorsEnd; successorsPtr++)
splitCost[range].loads += doLog10(successorsPtr->getTarget().loopDepth);
}
}
}
for (definePtr = defineBegin; definePtr < defineEnd; definePtr++)
if (definePtr->isRegister())
live.clear(name2range[definePtr->getRegisterName()]);
for (usePtr = useBegin; usePtr < useEnd; usePtr++)
if (usePtr->isRegister())
live.set(name2range[usePtr->getRegisterName()]);
}
}
NameLinkedList** splitAround = new(pool) NameLinkedList*[rangeCount];
memset(splitAround, '\0', rangeCount * sizeof(NameLinkedList*));
registerAllocator.splitAround = splitAround;
registerAllocator.splitCost = splitCost;
registerAllocator.splitFound = false;
}
#endif // _SPLITS_H_

View File

@@ -0,0 +1,186 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "HashTable.h"
#include "Timer.h"
#include "Pool.h"
static Pool pool; // Pool for the Timer class.
static HashTable<TimerEntry*> timerEntries(pool); // Timers hashtable.
const nTimersInABlock = 128; // Number of timers in a block.
static PRTime *timers = new(pool) PRTime[nTimersInABlock]; // A block of timers.
static Uint8 nextTimer = 0; // nextAvailableTimer.
//
// Calibrate the call to PR_Now().
//
static PRTime calibrate()
{
PRTime t = PR_Now();
PRTime& a = *new(pool) PRTime();
// Call 10 times the PR_Now() function.
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now(); a = PR_Now();
t = (PR_Now() - t + 9) / 10;
return t;
}
static PRTime adjust = calibrate();
//
// Return the named timer..
//
TimerEntry& Timer::getTimerEntry(const char* name)
{
if (!timerEntries.exists(name)) {
TimerEntry* newEntry = new(pool) TimerEntry();
newEntry->accumulator = 0;
newEntry->running = false;
timerEntries.add(name, newEntry);
}
return *timerEntries[name];
}
//
// Return a reference to a new timer.
//
PRTime& Timer::getNewTimer()
{
if (nextTimer >= nTimersInABlock) {
timers = new(pool) PRTime[nTimersInABlock];
nextTimer = 0;
}
return timers[nextTimer++];
}
static Uint32 timersAreFrozen = 0;
//
// Start the named timer.
//
void Timer::start(const char* name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(!timer.running);
timer.accumulator = 0;
timer.running = true;
timer.done = false;
unfreezeTimers();
}
//
// Stop the named timer.
//
void Timer::stop(const char* name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(timer.running);
timer.running = false;
timer.done = true;
unfreezeTimers();
}
//
// Freeze all the running timers.
//
void Timer::freezeTimers()
{
PRTime when = PR_Now() - adjust;
if (timersAreFrozen == 0) {
Vector<TimerEntry*> entries = timerEntries;
Uint32 count = entries.size();
for (Uint32 i = 0; i < count; i++) {
TimerEntry& entry = *entries[i];
if (entry.running) {
entry.accumulator += (when - *entry.startTime);
}
}
}
timersAreFrozen++;
}
//
// Unfreeze all the running timers.
//
void Timer::unfreezeTimers()
{
PR_ASSERT(timersAreFrozen != 0);
timersAreFrozen--;
if (timersAreFrozen == 0) {
Vector<TimerEntry *> entries = timerEntries;
Uint32 count = entries.size();
PRTime& newStart = getNewTimer();
for (Uint32 i = 0; i < count; i++) {
TimerEntry& entry = *entries[i];
if (entry.running) {
entry.startTime = &newStart;
}
}
newStart = PR_Now();
}
}
//
// Print the named timer in the file f.
//
void Timer::print(FILE* f, const char *name)
{
if (timersAreFrozen)
return;
freezeTimers();
TimerEntry& timer = getTimerEntry(name);
PR_ASSERT(timer.done);
PRTime elapsed = timer.accumulator;
if (elapsed >> 32) {
fprintf(f, "[timer %s out of range]\n", name);
} else {
fprintf(f, "[%dus in %s]\n", Uint32(elapsed), name);
}
fflush(f);
unfreezeTimers();
}

View File

@@ -0,0 +1,80 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _TIMER_H_
#define _TIMER_H_
#include "Fundamentals.h"
#include "HashTable.h"
#include "prtime.h"
//
// Naming convention:
// As the class Timer contains only static methods, the timer's name should start with the
// module name. Otherwise starting 2 timers with the same name will assert.
//
#ifndef NO_TIMER
struct TimerEntry
{
PRTime *startTime; // Current time when we start the timer.
PRTime accumulator; // Time spent in this timer.
bool running; // True if the timer is running.
bool done; // True if the timer was running and was stopped.
};
class Timer
{
private:
// Return the named timer.
static TimerEntry& getTimerEntry(const char* name);
// Return a reference to a new Timer.
static PRTime& getNewTimer();
public:
// Start the timer.
static void start(const char* name);
// Stop the timer.
static void stop(const char* name);
// Freeze all the running timers.
static void freezeTimers();
// Unfreeze all the running timers.
static void unfreezeTimers();
// Print the timer.
static void print(FILE* f, const char *name);
};
inline void startTimer(const char* name) {Timer::start(name);}
inline void stopTimer(const char* name) {Timer::stop(name); Timer::print(stdout, name);}
#define START_TIMER_SAFE Timer::freezeTimers();
#define END_TIMER_SAFE Timer::unfreezeTimers();
#define TIMER_SAFE(x) START_TIMER_SAFE x; END_TIMER_SAFE
#else /* NO_TIMER */
inline void startTimer(const char* /*name*/) {}
inline void stopTimer(const char* /*name*/) {}
#define START_TIMER_SAFE
#define END_TIMER_SAFE
#define TIMER_SAFE(x) x;
#endif /* NO_TIMER */
#endif /* _TIMER_H_ */

View File

@@ -0,0 +1,40 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#include "Fundamentals.h"
#include "VirtualRegister.h"
#include "Instruction.h"
//------------------------------------------------------------------------------
// VirtualRegister -
#ifdef MANUAL_TEMPLATES
template class IndexedPool<VirtualRegister>;
#endif
// Set the defining instruction.
//
void VirtualRegister::setDefiningInstruction(Instruction& instruction)
{
if (definingInstruction != NULL) {
if ((instruction.getFlags() & ifCopy) && (definingInstruction->getFlags() & ifPhiNode))
return;
}
definingInstruction = &instruction;
}

View File

@@ -0,0 +1,116 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
#ifndef _VIRTUAL_REGISTER_H_
#define _VIRTUAL_REGISTER_H_
#include "Fundamentals.h"
#include "IndexedPool.h"
#include <string.h>
#include "RegisterTypes.h"
#include "RegisterClass.h"
//------------------------------------------------------------------------------
// VirtualRegister - 24b
class Instruction;
class VirtualRegister : public IndexedObject<VirtualRegister>
{
public:
Instruction* definingInstruction; // Instruction defining this VR.
// Initialize a VR of the given classKind.
VirtualRegister(RegisterClassKind /*classKind*/) : definingInstruction(NULL) {}
// Return the defining instruction for this VR.
Instruction* getDefiningInstruction() const {return definingInstruction;}
// Set the defining instruction.
void setDefiningInstruction(Instruction& insn);
};
// Return true if the VirtualRegisters are equals. The only way 2 VRs can be equal is if
// they have the same index. If they have the same index then they are at the same
// address in the indexed pool.
//
inline bool operator == (const VirtualRegister& regA, const VirtualRegister& regB) {return &regA == &regB;}
//------------------------------------------------------------------------------
// VirtualRegisterManager -
struct PreColoredRegister
{
RegisterID id;
RegisterName color;
};
class VirtualRegisterManager
{
private:
IndexedPool<VirtualRegister> registerPool;
PreColoredRegister machineRegister[6];
public:
VirtualRegisterManager()
{
for (Uint32 i = 0; i < 6; i++)
machineRegister[i].id = invalidID;
}
// Return the VirtualRegister at the given index.
VirtualRegister& getVirtualRegister(RegisterName name) const {return registerPool.get(name);}
// Return a new VirtualRegister.
RegisterID newVirtualRegister(RegisterClassKind classKind)
{
VirtualRegister& vReg = *new(registerPool) VirtualRegister(classKind);
RegisterID rid;
setName(rid, RegisterName(vReg.getIndex()));
setClass(rid, classKind);
return rid;
}
RegisterID newMachineRegister(RegisterName name, RegisterClassKind classKind)
{
RegisterID rid = machineRegister[name].id;
if (rid == invalidID) {
rid = newVirtualRegister(classKind);
DEBUG_ONLY(setMachineRegister(rid));
machineRegister[name].id = rid;
machineRegister[name].color = name;
}
return rid;
}
PreColoredRegister* getMachineRegistersBegin() const {return (PreColoredRegister*) machineRegister;} // FIX
PreColoredRegister* getMachineRegistersEnd() const {return (PreColoredRegister*) &machineRegister[6];} // FIX
// Return the VirtualRegister universe size.
Uint32 getSize() {return registerPool.getSize();}
void setSize(Uint32 size) {registerPool.setSize(size);}
};
#endif // _VIRTUAL_REGISTER_H_