blob: 397976b06c7a9b5836332900a6ebb93ec68b7486 [file] [log] [blame]
mjs6f821c82002-03-22 00:31:57 +00001#! /usr/bin/perl -w
2#
3# Static Hashtable Generator
4#
5# (c) 2000-2002 by Harri Porten <porten@kde.org> and
6# David Faure <faure@kde.org>
eseidel1abee9d2005-07-01 09:48:20 +00007# Modified (c) 2004 by Nikolas Zimmermann <wildfox@kde.org>
ddkilzer@apple.comf9f6bbd2009-01-02 20:59:17 +00008# Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
darin170ca982006-01-29 04:18:56 +00009#
10# This library is free software; you can redistribute it and/or
11# modify it under the terms of the GNU Lesser General Public
12# License as published by the Free Software Foundation; either
13# version 2 of the License, or (at your option) any later version.
14#
15# This library is distributed in the hope that it will be useful,
16# but WITHOUT ANY WARRANTY; without even the implied warranty of
17# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18# Lesser General Public License for more details.
19#
20# You should have received a copy of the GNU Lesser General Public
21# License along with this library; if not, write to the Free Software
22# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
23#
mjs6f821c82002-03-22 00:31:57 +000024
staikos44432f42006-01-22 06:20:06 +000025use strict;
26
27my $file = $ARGV[0];
mjs6f821c82002-03-22 00:31:57 +000028shift;
mjs6f821c82002-03-22 00:31:57 +000029my $includelookup = 0;
darin170ca982006-01-29 04:18:56 +000030
cwzwarich@webkit.org0b51a732008-11-05 23:21:32 +000031# Use -i as second argument to make it include "Lookup.h"
mjs6f821c82002-03-22 00:31:57 +000032$includelookup = 1 if (defined($ARGV[0]) && $ARGV[0] eq "-i");
darin170ca982006-01-29 04:18:56 +000033
34# Use -n as second argument to make it use the third argument as namespace parameter ie. -n KDOM
staikos44432f42006-01-22 06:20:06 +000035my $useNameSpace = $ARGV[1] if (defined($ARGV[0]) && $ARGV[0] eq "-n");
eseidel1abee9d2005-07-01 09:48:20 +000036
mitz@apple.com6cf57f02011-10-26 16:30:50 +000037print STDERR "Creating hashtable for $file\n";
mjs6f821c82002-03-22 00:31:57 +000038open(IN, $file) or die "No such file $file";
39
staikos44432f42006-01-22 06:20:06 +000040my @keys = ();
staikos44432f42006-01-22 06:20:06 +000041my @attrs = ();
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +000042my @values = ();
staikos44432f42006-01-22 06:20:06 +000043my @hashes = ();
mjs6f821c82002-03-22 00:31:57 +000044
oliver@apple.com10825da2014-01-25 01:03:40 +000045my $hasSetter = "false";
46
mjs6f821c82002-03-22 00:31:57 +000047my $inside = 0;
48my $name;
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +000049my $pefectHashSize;
50my $compactSize;
51my $compactHashSizeMask;
mjs6f821c82002-03-22 00:31:57 +000052my $banner = 0;
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +000053sub calcPerfectHashSize();
54sub calcCompactHashSize();
mjs6f821c82002-03-22 00:31:57 +000055sub output();
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +000056sub jsc_ucfirst($);
mjs6f821c82002-03-22 00:31:57 +000057sub hashValue($);
58
59while (<IN>) {
darin@apple.com8a1c16e2008-03-19 04:23:21 +000060 chomp;
61 s/^\s+//;
62 next if /^\#|^$/; # Comment or blank line. Do nothing.
63 if (/^\@begin/ && !$inside) {
64 if (/^\@begin\s*([:_\w]+)\s*\d*\s*$/) {
65 $inside = 1;
66 $name = $1;
67 } else {
68 print STDERR "WARNING: \@begin without table name, skipping $_\n";
69 }
mjs6f821c82002-03-22 00:31:57 +000070 } elsif (/^\@end\s*$/ && $inside) {
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +000071 calcPerfectHashSize();
72 calcCompactHashSize();
darin@apple.com8a1c16e2008-03-19 04:23:21 +000073 output();
mjs6f821c82002-03-22 00:31:57 +000074
darin@apple.com8a1c16e2008-03-19 04:23:21 +000075 @keys = ();
darin@apple.com8a1c16e2008-03-19 04:23:21 +000076 @attrs = ();
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +000077 @values = ();
darin@apple.com8a1c16e2008-03-19 04:23:21 +000078 @hashes = ();
mjs6f821c82002-03-22 00:31:57 +000079
darin@apple.com8a1c16e2008-03-19 04:23:21 +000080 $inside = 0;
ggaren91f03742005-10-11 20:43:49 +000081 } elsif (/^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*$/ && $inside) {
darin@apple.com8a1c16e2008-03-19 04:23:21 +000082 my $key = $1;
83 my $val = $2;
84 my $att = $3;
85 my $param = $4;
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +000086
darin@apple.com8a1c16e2008-03-19 04:23:21 +000087 push(@keys, $key);
darin@apple.com8a1c16e2008-03-19 04:23:21 +000088 push(@attrs, length($att) > 0 ? $att : "0");
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +000089
90 if ($att =~ m/Function/) {
91 push(@values, { "type" => "Function", "function" => $val, "params" => (length($param) ? $param : "") });
92 #printf STDERR "WARNING: Number of arguments missing for $key/$val\n" if (length($param) == 0);
93 } elsif (length($att)) {
94 my $get = $val;
oliver@apple.com10825da2014-01-25 01:03:40 +000095 my $put = "0";
96 if (!($att =~ m/ReadOnly/)) {
97 $put = "set" . jsc_ucfirst($val);
98 }
99 $hasSetter = "true";
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +0000100 push(@values, { "type" => "Property", "get" => $get, "put" => $put });
101 } else {
102 push(@values, { "type" => "Lexer", "value" => $val });
103 }
104 push(@hashes, hashValue($key));
mjs6f821c82002-03-22 00:31:57 +0000105 } elsif ($inside) {
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000106 die "invalid data {" . $_ . "}";
mjs6f821c82002-03-22 00:31:57 +0000107 }
108}
109
110die "missing closing \@end" if ($inside);
111
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +0000112sub jsc_ucfirst($)
113{
114 my ($value) = @_;
115
116 if ($value =~ /js/) {
117 $value =~ s/js/JS/;
118 return $value;
119 }
120
121 return ucfirst($value);
122}
123
124
darin41d3d9c2007-10-24 08:03:02 +0000125sub ceilingToPowerOf2
126{
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +0000127 my ($pefectHashSize) = @_;
darin41d3d9c2007-10-24 08:03:02 +0000128
129 my $powerOf2 = 1;
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +0000130 while ($pefectHashSize > $powerOf2) {
darin41d3d9c2007-10-24 08:03:02 +0000131 $powerOf2 <<= 1;
132 }
133
134 return $powerOf2;
135}
136
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +0000137sub calcPerfectHashSize()
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000138{
139tableSizeLoop:
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +0000140 for ($pefectHashSize = ceilingToPowerOf2(scalar @keys); ; $pefectHashSize += $pefectHashSize) {
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000141 my @table = ();
142 foreach my $key (@keys) {
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +0000143 my $h = hashValue($key) % $pefectHashSize;
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000144 next tableSizeLoop if $table[$h];
145 $table[$h] = 1;
146 }
147 last;
mjs6f821c82002-03-22 00:31:57 +0000148 }
mjs6f821c82002-03-22 00:31:57 +0000149}
150
eseidel0d428262006-03-08 10:59:34 +0000151sub leftShift($$) {
152 my ($value, $distance) = @_;
153 return (($value << $distance) & 0xFFFFFFFF);
154}
155
ddkilzer@apple.comaff2b202008-12-06 01:05:06 +0000156sub calcCompactHashSize()
157{
158 my @table = ();
159 my @links = ();
160 my $compactHashSize = ceilingToPowerOf2(2 * @keys);
161 $compactHashSizeMask = $compactHashSize - 1;
162 $compactSize = $compactHashSize;
163 my $collisions = 0;
164 my $maxdepth = 0;
165 my $i = 0;
166 foreach my $key (@keys) {
167 my $depth = 0;
168 my $h = hashValue($key) % $compactHashSize;
169 while (defined($table[$h])) {
170 if (defined($links[$h])) {
171 $h = $links[$h];
172 $depth++;
173 } else {
174 $collisions++;
175 $links[$h] = $compactSize;
176 $h = $compactSize;
177 $compactSize++;
178 }
179 }
180 $table[$h] = $i;
181 $i++;
182 $maxdepth = $depth if ( $depth > $maxdepth);
183 }
184}
185
mjs768fcac2006-01-06 23:51:00 +0000186# Paul Hsieh's SuperFastHash
187# http://www.azillionmonkeys.com/qed/hash.html
mjs6f821c82002-03-22 00:31:57 +0000188sub hashValue($) {
staikos44432f42006-01-22 06:20:06 +0000189 my @chars = split(/ */, $_[0]);
mjs768fcac2006-01-06 23:51:00 +0000190
191 # This hash is designed to work on 16-bit chunks at a time. But since the normal case
192 # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
193 # were 16-bit chunks, which should give matching results
194
195 my $EXP2_32 = 4294967296;
196
197 my $hash = 0x9e3779b9;
198 my $l = scalar @chars; #I wish this was in Ruby --- Maks
199 my $rem = $l & 1;
200 $l = $l >> 1;
201
202 my $s = 0;
203
204 # Main loop
205 for (; $l > 0; $l--) {
206 $hash += ord($chars[$s]);
eseidel0d428262006-03-08 10:59:34 +0000207 my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
208 $hash = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
mjs768fcac2006-01-06 23:51:00 +0000209 $s += 2;
210 $hash += $hash >> 11;
zimmermann7305d1c2007-07-11 12:56:05 +0000211 $hash %= $EXP2_32;
mjs6f821c82002-03-22 00:31:57 +0000212 }
mjs768fcac2006-01-06 23:51:00 +0000213
214 # Handle end case
ggaren@apple.com94ba3302011-10-23 07:21:19 +0000215 if ($rem != 0) {
mjs768fcac2006-01-06 23:51:00 +0000216 $hash += ord($chars[$s]);
eseidel0d428262006-03-08 10:59:34 +0000217 $hash ^= (leftShift($hash, 11)% $EXP2_32);
mjs768fcac2006-01-06 23:51:00 +0000218 $hash += $hash >> 17;
219 }
220
221 # Force "avalanching" of final 127 bits
eseidel0d428262006-03-08 10:59:34 +0000222 $hash ^= leftShift($hash, 3);
mjs768fcac2006-01-06 23:51:00 +0000223 $hash += ($hash >> 5);
224 $hash = ($hash% $EXP2_32);
eseidel0d428262006-03-08 10:59:34 +0000225 $hash ^= (leftShift($hash, 2)% $EXP2_32);
mjs768fcac2006-01-06 23:51:00 +0000226 $hash += ($hash >> 15);
227 $hash = $hash% $EXP2_32;
eseidel0d428262006-03-08 10:59:34 +0000228 $hash ^= (leftShift($hash, 10)% $EXP2_32);
ggaren@apple.com94ba3302011-10-23 07:21:19 +0000229
msaboff@apple.com7ef29ea2011-10-26 17:12:13 +0000230 # Save 8 bits for StringImpl to use as flags.
231 $hash &= 0xffffff;
ggaren@apple.com94ba3302011-10-23 07:21:19 +0000232
233 # This avoids ever returning a hash code of 0, since that is used to
234 # signal "hash not computed yet". Setting the high bit maintains
235 # reasonable fidelity to a hash code of 0 because it is likely to yield
236 # exactly 0 when hash lookup masks out the high bits.
msaboff@apple.com7ef29ea2011-10-26 17:12:13 +0000237 $hash = (0x80000000 >> 8) if ($hash == 0);
mjs768fcac2006-01-06 23:51:00 +0000238
239 return $hash;
mjs6f821c82002-03-22 00:31:57 +0000240}
241
242sub output() {
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000243 if (!$banner) {
244 $banner = 1;
245 print "// Automatically generated from $file using $0. DO NOT EDIT!\n";
mjs6f821c82002-03-22 00:31:57 +0000246 }
darin41d3d9c2007-10-24 08:03:02 +0000247
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000248 my $nameEntries = "${name}Values";
249 $nameEntries =~ s/:/_/g;
250
cwzwarich@webkit.org3e348672008-11-06 00:00:05 +0000251 print "\n#include \"Lookup.h\"\n" if ($includelookup);
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000252 if ($useNameSpace) {
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +0000253 print "\nnamespace ${useNameSpace} {\n";
254 print "\nusing namespace JSC;\n";
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000255 } else {
cwzwarich@webkit.org3f782f62008-09-08 01:28:33 +0000256 print "\nnamespace JSC {\n";
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000257 }
258 my $count = scalar @keys + 1;
ddkilzer@apple.com763c4ef2008-10-23 19:24:48 +0000259 print "\nstatic const struct HashTableValue ${nameEntries}\[$count\] = {\n";
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000260 my $i = 0;
261 foreach my $key (@keys) {
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +0000262 my $firstValue = "";
263 my $secondValue = "";
oliver@apple.com2b5f3732014-01-25 01:26:49 +0000264 my $firstCastStr = "";
265 my $secondCastStr = "";
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +0000266
267 if ($values[$i]{"type"} eq "Function") {
oliver@apple.com2b5f3732014-01-25 01:26:49 +0000268 $firstCastStr = "static_cast<NativeFunction>";
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +0000269 $firstValue = $values[$i]{"function"};
270 $secondValue = $values[$i]{"params"};
271 } elsif ($values[$i]{"type"} eq "Property") {
oliver@apple.com2b5f3732014-01-25 01:26:49 +0000272 $firstCastStr = "static_cast<PropertySlot::GetValueFunc>";
273 $secondCastStr = "static_cast<PutPropertySlot::PutValueFunc>";
weinig@apple.comcaf5e3b2008-09-27 02:36:15 +0000274 $firstValue = $values[$i]{"get"};
275 $secondValue = $values[$i]{"put"};
276 } elsif ($values[$i]{"type"} eq "Lexer") {
277 $firstValue = $values[$i]{"value"};
278 $secondValue = "0";
279 }
barraclough@apple.com6d2ad992011-12-06 20:46:07 +0000280
281 my $intrinsic = "NoIntrinsic";
barraclough@apple.com6d2ad992011-12-06 20:46:07 +0000282 $intrinsic = "FromCharCodeIntrinsic" if ($key eq "fromCharCode");
fpizlo@apple.com24d24e52011-10-04 02:55:54 +0000283 if ($name eq "arrayPrototypeTable") {
barraclough@apple.com6d2ad992011-12-06 20:46:07 +0000284 $intrinsic = "ArrayPushIntrinsic" if ($key eq "push");
285 $intrinsic = "ArrayPopIntrinsic" if ($key eq "pop");
fpizlo@apple.com24d24e52011-10-04 02:55:54 +0000286 }
barraclough@apple.com077fdd42012-03-18 01:08:16 +0000287 if ($name eq "regExpPrototypeTable") {
288 $intrinsic = "RegExpExecIntrinsic" if ($key eq "exec");
289 $intrinsic = "RegExpTestIntrinsic" if ($key eq "test");
290 }
barraclough@apple.com6d2ad992011-12-06 20:46:07 +0000291
oliver@apple.com2b5f3732014-01-25 01:26:49 +0000292 print " { \"$key\", $attrs[$i], $intrinsic, (intptr_t)" . $firstCastStr . "($firstValue), (intptr_t)" . $secondCastStr . "($secondValue) },\n";
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000293 $i++;
294 }
akling@apple.com9b26e5d2013-09-17 22:32:31 +0000295 print " { 0, 0, NoIntrinsic, 0, 0 }\n";
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000296 print "};\n\n";
laszlo.1.gombos@nokia.comae659222011-11-13 04:37:43 +0000297 print "extern const struct HashTable $name =\n";
oliver@apple.com10825da2014-01-25 01:03:40 +0000298 print " \{ $compactSize, $compactHashSizeMask, $hasSetter, $nameEntries, 0 \};\n";
darin@apple.com8a1c16e2008-03-19 04:23:21 +0000299 print "} // namespace\n";
mjs6f821c82002-03-22 00:31:57 +0000300}