Created
June 19, 2016 17:28
-
-
Save Constellation/b07896538f12bd16d34fabbc8d760ad4 to your computer and use it in GitHub Desktop.
ok
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/Source/JavaScriptCore/CMakeLists.txt b/Source/JavaScriptCore/CMakeLists.txt | |
index 4d68a73..8499e8e 100644 | |
--- a/Source/JavaScriptCore/CMakeLists.txt | |
+++ b/Source/JavaScriptCore/CMakeLists.txt | |
@@ -171,6 +171,7 @@ set(JavaScriptCore_SOURCES | |
bindings/ScriptObject.cpp | |
bindings/ScriptValue.cpp | |
+ builtins/StaticSymbols.cpp | |
builtins/BuiltinExecutables.cpp | |
builtins/BuiltinExecutableCreator.cpp | |
diff --git a/Source/JavaScriptCore/builtins/BuiltinNames.h b/Source/JavaScriptCore/builtins/BuiltinNames.h | |
index b6f4e38..f938ebb 100644 | |
--- a/Source/JavaScriptCore/builtins/BuiltinNames.h | |
+++ b/Source/JavaScriptCore/builtins/BuiltinNames.h | |
@@ -29,6 +29,7 @@ | |
#include "BuiltinUtils.h" | |
#include "CommonIdentifiers.h" | |
#include "JSCBuiltins.h" | |
+#include "StaticSymbols.h" | |
namespace JSC { | |
diff --git a/Source/JavaScriptCore/builtins/BuiltinUtils.h b/Source/JavaScriptCore/builtins/BuiltinUtils.h | |
index ceeac29..b5dda2a 100644 | |
--- a/Source/JavaScriptCore/builtins/BuiltinUtils.h | |
+++ b/Source/JavaScriptCore/builtins/BuiltinUtils.h | |
@@ -31,13 +31,13 @@ | |
namespace JSC { | |
-#define INITIALIZE_BUILTIN_NAMES(name) , m_##name(JSC::Identifier::fromString(vm, #name)), m_##name##PrivateName(JSC::Identifier::fromUid(JSC::PrivateName(JSC::PrivateName::Description, ASCIILiteral("PrivateSymbol." #name)))) | |
+#define INITIALIZE_BUILTIN_NAMES(name) , m_##name(JSC::Identifier::fromString(vm, #name)), m_##name##PrivateName(JSC::Identifier::fromUid(JSC::PrivateName(StaticSymbols::name##PrivateName()))) | |
#define DECLARE_BUILTIN_NAMES(name) const JSC::Identifier m_##name; const JSC::Identifier m_##name##PrivateName; | |
#define DECLARE_BUILTIN_IDENTIFIER_ACCESSOR(name) \ | |
const JSC::Identifier& name##PublicName() const { return m_##name; } \ | |
const JSC::Identifier& name##PrivateName() const { return m_##name##PrivateName; } | |
-#define INITIALIZE_BUILTIN_SYMBOLS(name) , m_##name##Symbol(JSC::Identifier::fromUid(JSC::PrivateName(JSC::PrivateName::Description, ASCIILiteral("Symbol." #name)))), m_##name##SymbolPrivateIdentifier(JSC::Identifier::fromString(vm, #name "Symbol")) | |
+#define INITIALIZE_BUILTIN_SYMBOLS(name) , m_##name##Symbol(JSC::Identifier::fromUid(JSC::PrivateName(StaticSymbols::name##Symbol()))), m_##name##SymbolPrivateIdentifier(JSC::Identifier::fromString(vm, #name "Symbol")) | |
#define DECLARE_BUILTIN_SYMBOLS(name) const JSC::Identifier m_##name##Symbol; const JSC::Identifier m_##name##SymbolPrivateIdentifier; | |
#define DECLARE_BUILTIN_SYMBOL_ACCESSOR(name) \ | |
const JSC::Identifier& name##Symbol() const { return m_##name##Symbol; } | |
diff --git a/Source/JavaScriptCore/builtins/StaticSymbols.cpp b/Source/JavaScriptCore/builtins/StaticSymbols.cpp | |
new file mode 100644 | |
index 0000000..c944c1d | |
--- /dev/null | |
+++ b/Source/JavaScriptCore/builtins/StaticSymbols.cpp | |
@@ -0,0 +1,64 @@ | |
+/* | |
+ * Copyright (C) 2016 Yusuke Suzuki <[email protected]>. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
+ */ | |
+ | |
+#include "config.h" | |
+#include "StaticSymbols.h" | |
+ | |
+#include <wtf/NeverDestroyed.h> | |
+#include <wtf/text/SymbolImpl.h> | |
+ | |
+namespace JSC { | |
+ | |
+#define DECLARE_STATIC_PRIVATE_NAMES(name)\ | |
+static StringImpl& name##PrivateNameDescription()\ | |
+{\ | |
+ static NeverDestroyed<StringImpl> description(StringImpl::ConstructStaticString, "PrivateSymbol." #name);\ | |
+ return description.get();\ | |
+}\ | |
+\ | |
+SymbolImpl& StaticSymbols::name##PrivateName()\ | |
+{\ | |
+ static NeverDestroyed<SymbolImpl> symbol(SymbolImpl::ConstructStaticString, name##PrivateNameDescription());\ | |
+ return symbol.get();\ | |
+} | |
+ | |
+#define DECLARE_STATIC_SYMBOLS(name)\ | |
+static StringImpl& name##SymbolDescription()\ | |
+{\ | |
+ static NeverDestroyed<StringImpl> description(StringImpl::ConstructStaticString, "Symbol." #name);\ | |
+ return description.get();\ | |
+}\ | |
+\ | |
+SymbolImpl& StaticSymbols::name##Symbol()\ | |
+{\ | |
+ static NeverDestroyed<SymbolImpl> symbol(SymbolImpl::ConstructStaticString, name##SymbolDescription());\ | |
+ return symbol.get();\ | |
+} | |
+ | |
+JSC_FOREACH_BUILTIN_FUNCTION_NAME(DECLARE_STATIC_PRIVATE_NAMES) | |
+JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_STATIC_PRIVATE_NAMES) | |
+JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_STATIC_SYMBOLS) | |
+ | |
+} // namespace JSC | |
diff --git a/Source/JavaScriptCore/builtins/StaticSymbols.h b/Source/JavaScriptCore/builtins/StaticSymbols.h | |
new file mode 100644 | |
index 0000000..4fd1448 | |
--- /dev/null | |
+++ b/Source/JavaScriptCore/builtins/StaticSymbols.h | |
@@ -0,0 +1,51 @@ | |
+/* | |
+ * Copyright (C) 2016 Yusuke Suzuki <[email protected]>. | |
+ * | |
+ * Redistribution and use in source and binary forms, with or without | |
+ * modification, are permitted provided that the following conditions | |
+ * are met: | |
+ * 1. Redistributions of source code must retain the above copyright | |
+ * notice, this list of conditions and the following disclaimer. | |
+ * 2. Redistributions in binary form must reproduce the above copyright | |
+ * notice, this list of conditions and the following disclaimer in the | |
+ * documentation and/or other materials provided with the distribution. | |
+ * | |
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY | |
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR | |
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY | |
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
+ */ | |
+ | |
+#pragma once | |
+ | |
+#include "CommonIdentifiers.h" | |
+#include "JSCBuiltins.h" | |
+ | |
+namespace JSC { | |
+ | |
+// Symbols are not registered in the atomic string table. It allows Symbols to be allocated | |
+// statically! StaticSymbols allocates and offers static StringImpls. The ref counts of | |
+// these static SymbolImpl and static description StringImpls are marked as static as | |
+// the same to empty StringImpl. Since this ensures that the ref count becomes meaningless, | |
+// SymbolImpls offered by this registry can be shared across the threads. | |
+// Furthermore, these SymbolImpls can be used from the other static variables, for example, | |
+// static hash tables for JS object properties. | |
+class StaticSymbols { | |
+public: | |
+#define DECLARE_STATIC_PRIVATE_NAMES(name) static SymbolImpl& name##PrivateName(); | |
+#define DECLARE_STATIC_SYMBOLS(name) static SymbolImpl& name##Symbol(); | |
+ JSC_FOREACH_BUILTIN_FUNCTION_NAME(DECLARE_STATIC_PRIVATE_NAMES) | |
+ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_PROPERTY_NAME(DECLARE_STATIC_PRIVATE_NAMES) | |
+ JSC_COMMON_PRIVATE_IDENTIFIERS_EACH_WELL_KNOWN_SYMBOL(DECLARE_STATIC_SYMBOLS) | |
+#undef DECLARE_STATIC_PRIVATE_NAMES | |
+#undef DECLARE_STATIC_SYMBOLS | |
+}; | |
+ | |
+} // namespace JSC | |
diff --git a/Source/JavaScriptCore/create_hash_table b/Source/JavaScriptCore/create_hash_table | |
old mode 100755 | |
new mode 100644 | |
index 1cb2e49..1ba7a24 | |
--- a/Source/JavaScriptCore/create_hash_table | |
+++ b/Source/JavaScriptCore/create_hash_table | |
@@ -1,11 +1,11 @@ | |
-#! /usr/bin/perl -w | |
-# | |
+#!/usr/bin/ruby | |
# Static Hashtable Generator | |
# | |
# (c) 2000-2002 by Harri Porten <[email protected]> and | |
# David Faure <[email protected]> | |
# Modified (c) 2004 by Nikolas Zimmermann <[email protected]> | |
# Copyright (C) 2007, 2008, 2009, 2015-2016 Apple Inc. All rights reserved. | |
+# Copyright (C) 2016 Yusuke Suzuki <[email protected]>. | |
# | |
# This library is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU Lesser General Public | |
@@ -20,324 +20,439 @@ | |
# You should have received a copy of the GNU Lesser General Public | |
# License along with this library; if not, write to the Free Software | |
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
-# | |
- | |
-use strict; | |
-use Getopt::Long qw(:config pass_through); | |
- | |
-my $file = shift @ARGV or die("Must provide source file as final argument."); | |
- | |
-open(IN, $file) or die "No such file $file"; | |
- | |
-my @keys = (); | |
-my @attrs = (); | |
-my @values = (); | |
-my @hashes = (); | |
-my @table = (); | |
-my @links = (); | |
- | |
-my $hasSetter = "false"; | |
- | |
-my $includeBuiltin = 0; | |
-my $inside = 0; | |
-my $name; | |
-my $pefectHashSize; | |
-my $compactSize; | |
-my $compactHashSizeMask; | |
-my $banner = 0; | |
-sub calcPerfectHashSize(); | |
-sub calcCompactHashSize(); | |
-sub output(); | |
-sub jsc_ucfirst($); | |
-sub hashValue($); | |
- | |
-while (<IN>) { | |
- chomp; | |
- s/^\s+//; | |
- next if /^\#|^$/; # Comment or blank line. Do nothing. | |
- if (/^\@begin/ && !$inside) { | |
- if (/^\@begin\s*([:_\w]+)\s*\d*\s*$/) { | |
- $inside = 1; | |
- $name = $1; | |
- } else { | |
- print STDERR "WARNING: \@begin without table name, skipping $_\n"; | |
- } | |
- } elsif (/^\@end\s*$/ && $inside) { | |
- calcPerfectHashSize(); | |
- calcCompactHashSize(); | |
- output(); | |
- | |
- @keys = (); | |
- @attrs = (); | |
- @values = (); | |
- @hashes = (); | |
- @table = (); | |
- @links = (); | |
- $includeBuiltin = 0; | |
- | |
- $inside = 0; | |
- } elsif (/^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*$/ && $inside) { | |
- my $key = $1; | |
- my $val = $2; | |
- my $att = $3; | |
- my $param = $4; | |
- | |
- push(@keys, $key); | |
- push(@attrs, length($att) > 0 ? $att : "0"); | |
- | |
- if ($val eq "JSBuiltin") { | |
- $includeBuiltin = 1; | |
- } | |
- | |
- if ($att =~ m/Function/) { | |
- push(@values, { "type" => "Function", "function" => $val, "params" => (length($param) ? $param : "") }); | |
- #printf STDERR "WARNING: Number of arguments missing for $key/$val\n" if (length($param) == 0); | |
- } elsif ($att =~ m/Accessor/) { | |
- my $get = $val; | |
- my $put = "nullptr"; | |
- $hasSetter = "true"; | |
- push(@values, { "type" => "Accessor", "get" => $get, "put" => $put }); | |
- } elsif ($att =~ m/CellProperty/) { | |
- my $property = $val; | |
- push(@values, { "type" => "CellProperty", "property" => $property }); | |
- } elsif ($att =~ m/ClassStructure/) { | |
- my $property = $val; | |
- push(@values, { "type" => "ClassStructure", "property" => $property }); | |
- } elsif ($att =~ m/PropertyCallback/) { | |
- my $cback = $val; | |
- push(@values, { "type" => "PropertyCallback", "cback" => $cback }); | |
- } elsif (length($att)) { | |
- my $get = $val; | |
- my $put = "0"; | |
- if (!($att =~ m/ReadOnly/)) { | |
- $put = "set" . jsc_ucfirst($val); | |
- } | |
- $hasSetter = "true"; | |
- push(@values, { "type" => "Property", "get" => $get, "put" => $put }); | |
- } else { | |
- push(@values, { "type" => "Lexer", "value" => $val }); | |
- } | |
- push(@hashes, hashValue($key)); | |
- } elsif ($inside) { | |
- die "invalid data {" . $_ . "}"; | |
- } | |
-} | |
- | |
-die "missing closing \@end" if ($inside); | |
- | |
-sub jsc_ucfirst($) | |
-{ | |
- my ($value) = @_; | |
- | |
- if ($value =~ /js/) { | |
- $value =~ s/js/JS/; | |
- return $value; | |
- } | |
- | |
- return ucfirst($value); | |
-} | |
- | |
- | |
-sub ceilingToPowerOf2 | |
-{ | |
- my ($pefectHashSize) = @_; | |
- | |
- my $powerOf2 = 1; | |
- while ($pefectHashSize > $powerOf2) { | |
- $powerOf2 <<= 1; | |
- } | |
- | |
- return $powerOf2; | |
-} | |
- | |
-sub calcPerfectHashSize() | |
-{ | |
-tableSizeLoop: | |
- for ($pefectHashSize = ceilingToPowerOf2(scalar @keys); ; $pefectHashSize += $pefectHashSize) { | |
- my @table = (); | |
- foreach my $key (@keys) { | |
- my $h = hashValue($key) % $pefectHashSize; | |
- next tableSizeLoop if $table[$h]; | |
- $table[$h] = 1; | |
- } | |
- last; | |
- } | |
-} | |
- | |
-sub leftShift($$) { | |
- my ($value, $distance) = @_; | |
- return (($value << $distance) & 0xFFFFFFFF); | |
-} | |
- | |
-sub calcCompactHashSize() | |
-{ | |
- my $compactHashSize = ceilingToPowerOf2(2 * @keys); | |
- $compactHashSizeMask = $compactHashSize - 1; | |
- $compactSize = $compactHashSize; | |
- my $collisions = 0; | |
- my $maxdepth = 0; | |
- my $i = 0; | |
- foreach my $key (@keys) { | |
- my $depth = 0; | |
- my $h = hashValue($key) % $compactHashSize; | |
- while (defined($table[$h])) { | |
- if (defined($links[$h])) { | |
- $h = $links[$h]; | |
- $depth++; | |
- } else { | |
- $collisions++; | |
- $links[$h] = $compactSize; | |
- $h = $compactSize; | |
- $compactSize++; | |
- } | |
- } | |
- $table[$h] = $i; | |
- $i++; | |
- $maxdepth = $depth if ( $depth > $maxdepth); | |
- } | |
-} | |
+ | |
+def upcaseFirst value | |
+ characters = value.split "" | |
+ unless characters.empty? | |
+ characters[0].upcase! | |
+ end | |
+ characters.join "" | |
+end | |
+ | |
+def jscUpcaseFirst value | |
+ if value =~ /js/ | |
+ value.sub /js/, "JS" | |
+ else | |
+ upcaseFirst value | |
+ end | |
+end | |
+ | |
+def leftShift value, distance | |
+ return ((value << distance) & 0xFFFFFFFF); | |
+end | |
# Paul Hsieh's SuperFastHash | |
# http://www.azillionmonkeys.com/qed/hash.html | |
-sub hashValue($) { | |
- my @chars = split(/ */, $_[0]); | |
- | |
- # This hash is designed to work on 16-bit chunks at a time. But since the normal case | |
- # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they | |
- # were 16-bit chunks, which should give matching results | |
- | |
- my $EXP2_32 = 4294967296; | |
- | |
- my $hash = 0x9e3779b9; | |
- my $l = scalar @chars; #I wish this was in Ruby --- Maks | |
- my $rem = $l & 1; | |
- $l = $l >> 1; | |
- | |
- my $s = 0; | |
- | |
- # Main loop | |
- for (; $l > 0; $l--) { | |
- $hash += ord($chars[$s]); | |
- my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash; | |
- $hash = (leftShift($hash, 16)% $EXP2_32) ^ $tmp; | |
- $s += 2; | |
- $hash += $hash >> 11; | |
- $hash %= $EXP2_32; | |
- } | |
- | |
- # Handle end case | |
- if ($rem != 0) { | |
- $hash += ord($chars[$s]); | |
- $hash ^= (leftShift($hash, 11)% $EXP2_32); | |
- $hash += $hash >> 17; | |
- } | |
- | |
- # Force "avalanching" of final 127 bits | |
- $hash ^= leftShift($hash, 3); | |
- $hash += ($hash >> 5); | |
- $hash = ($hash% $EXP2_32); | |
- $hash ^= (leftShift($hash, 2)% $EXP2_32); | |
- $hash += ($hash >> 15); | |
- $hash = $hash% $EXP2_32; | |
- $hash ^= (leftShift($hash, 10)% $EXP2_32); | |
- | |
- # Save 8 bits for StringImpl to use as flags. | |
- $hash &= 0xffffff; | |
- | |
- # This avoids ever returning a hash code of 0, since that is used to | |
- # signal "hash not computed yet". Setting the high bit maintains | |
- # reasonable fidelity to a hash code of 0 because it is likely to yield | |
- # exactly 0 when hash lookup masks out the high bits. | |
- $hash = (0x80000000 >> 8) if ($hash == 0); | |
- | |
- return $hash; | |
-} | |
- | |
-sub output() { | |
- if (!$banner) { | |
- $banner = 1; | |
- print "// Automatically generated from $file using $0. DO NOT EDIT!\n"; | |
- } | |
- | |
- my $nameEntries = "${name}Values"; | |
- $nameEntries =~ s/:/_/g; | |
- my $nameIndex = "${name}Index"; | |
- $nameIndex =~ s/:/_/g; | |
- | |
- print "\n"; | |
- print "#include \"JSCBuiltins.h\"\n" if ($includeBuiltin); | |
- print "#include \"Lookup.h\"\n"; | |
- print "\n"; | |
- print "namespace JSC {\n"; | |
- print "\n"; | |
- print "static const struct CompactHashIndex ${nameIndex}\[$compactSize\] = {\n"; | |
- for (my $i = 0; $i < $compactSize; $i++) { | |
- my $T = -1; | |
- if (defined($table[$i])) { $T = $table[$i]; } | |
- my $L = -1; | |
- if (defined($links[$i])) { $L = $links[$i]; } | |
- print " { $T, $L },\n"; | |
- } | |
- print "};\n"; | |
- print "\n"; | |
- | |
- my $packedSize = scalar @keys; | |
- print "static const struct HashTableValue ${nameEntries}\[$packedSize\] = {\n"; | |
- my $i = 0; | |
- foreach my $key (@keys) { | |
- my $firstValue = ""; | |
- my $secondValue = ""; | |
- my $firstCastStr = ""; | |
- my $secondCastStr = ""; | |
- | |
- if ($values[$i]{"type"} eq "Function") { | |
- $firstCastStr = "static_cast<NativeFunction>"; | |
- $firstValue = $values[$i]{"function"}; | |
- $secondValue = $values[$i]{"params"}; | |
- } elsif ($values[$i]{"type"} eq "Accessor") { | |
- $firstCastStr = "static_cast<NativeFunction>"; | |
- $secondCastStr = "static_cast<NativeFunction>"; | |
- $firstValue = $values[$i]{"get"}; | |
- $secondValue = $values[$i]{"put"}; | |
- } elsif ($values[$i]{"type"} eq "Property") { | |
- $firstCastStr = "static_cast<PropertySlot::GetValueFunc>"; | |
- $secondCastStr = "static_cast<PutPropertySlot::PutValueFunc>"; | |
- $firstValue = $values[$i]{"get"}; | |
- $secondValue = $values[$i]{"put"}; | |
- } elsif ($values[$i]{"type"} eq "Lexer") { | |
- $firstValue = $values[$i]{"value"}; | |
- $secondValue = "0"; | |
- } elsif ($values[$i]{"type"} eq "CellProperty" || $values[$i]{"type"} eq "ClassStructure") { | |
- $values[$i]{"property"} =~ /\A([a-zA-Z0-9_]+)::(.*)\Z/ or die; | |
- $firstValue = "OBJECT_OFFSETOF($1, $2)"; | |
- $secondValue = "0"; | |
- } elsif ($values[$i]{"type"} eq "PropertyCallback") { | |
- $firstCastStr = "static_cast<LazyPropertyCallback>"; | |
- $firstValue = $values[$i]{"cback"}; | |
- $secondValue = "0"; | |
- } | |
- | |
- my $intrinsic = "NoIntrinsic"; | |
- $intrinsic = "FromCharCodeIntrinsic" if ($key eq "fromCharCode"); | |
- if ($name eq "arrayPrototypeTable") { | |
- $intrinsic = "ArrayPushIntrinsic" if ($key eq "push"); | |
- $intrinsic = "ArrayPopIntrinsic" if ($key eq "pop"); | |
- } | |
- | |
- if ($values[$i]{"type"} eq "Function" && $firstValue eq "JSBuiltin") { | |
- my $tableHead = $name; | |
- $tableHead =~ s/Table$//; | |
- print " { \"$key\", (($attrs[$i]) & ~Function) | Builtin, $intrinsic, { (intptr_t)static_cast<BuiltinGenerator>(" . $tableHead . ucfirst($key) . "CodeGenerator), (intptr_t)$secondValue } },\n"; | |
- } | |
- else { | |
- print " { \"$key\", $attrs[$i], $intrinsic, { (intptr_t)" . $firstCastStr . "($firstValue), (intptr_t)" . $secondCastStr . "($secondValue) } },\n"; | |
- } | |
- $i++; | |
- } | |
- print "};\n"; | |
- print "\n"; | |
- print "static const struct HashTable $name =\n"; | |
- print " \{ $packedSize, $compactHashSizeMask, $hasSetter, $nameEntries, $nameIndex \};\n"; | |
- print "\n"; | |
- print "} // namespace JSC\n"; | |
-} | |
+EXP2_32 = 4294967296; | |
+def calcHashValue string | |
+ characters = string.split '' | |
+ | |
+ # This hash is designed to work on 16-bit chunks at a time. But since the normal case | |
+ # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they | |
+ # were 16-bit chunks, which should give matching results | |
+ | |
+ hash = 0x9e3779b9; | |
+ length = characters.size | |
+ rem = length & 1 | |
+ length = length >> 1 | |
+ | |
+ s = 0 | |
+ length.times do | |
+ hash += characters[s].ord | |
+ temp = leftShift(characters[s + 1].ord, 11) ^ hash | |
+ hash = (leftShift(hash, 16) % EXP2_32) ^ temp | |
+ s += 2 | |
+ hash += hash >> 11 | |
+ hash %= EXP2_32 | |
+ end | |
+ | |
+ if rem != 0 | |
+ hash += characters[s].ord | |
+ hash ^= (leftShift(hash, 11) % EXP2_32) | |
+ hash += hash >> 17 | |
+ end | |
+ | |
+ # Force "avalanching" of final 127 bits | |
+ hash ^= leftShift(hash, 3) | |
+ hash += (hash >> 5) | |
+ hash = (hash% EXP2_32) | |
+ hash ^= (leftShift(hash, 2) % EXP2_32) | |
+ hash += (hash >> 15) | |
+ hash = hash % EXP2_32 | |
+ hash ^= (leftShift(hash, 10) % EXP2_32) | |
+ | |
+ # Save 8 bits for StringImpl to use as flags. | |
+ hash &= 0xffffff | |
+ | |
+ # This avoids ever returning a hash code of 0, since that is used to | |
+ # signal "hash not computed yet". Setting the high bit maintains | |
+ # reasonable fidelity to a hash code of 0 because it is likely to yield | |
+ # exactly 0 when hash lookup masks out the high bits. | |
+ hash = (0x80000000 >> 8) if (hash == 0) | |
+ | |
+ return hash | |
+end | |
+ | |
+def ceilingToPowerOf2 perfectHashSize | |
+ powerOf2 = 1; | |
+ while perfectHashSize > powerOf2 | |
+ powerOf2 <<= 1; | |
+ end | |
+ powerOf2; | |
+end | |
+ | |
+def calcPerfectHashSize properties | |
+ perfectHashSize = ceilingToPowerOf2(properties.size) | |
+ begin | |
+ table = {} | |
+ properties.each do |property| | |
+ hashValue = property.hashValue % perfectHashSize | |
+ throw "Incorrect" unless table[hashValue].nil? | |
+ table[hashValue] = true | |
+ end | |
+ rescue | |
+ perfectHashSize += perfectHashSize | |
+ retry | |
+ end | |
+ perfectHashSize | |
+end | |
+ | |
+class CompactTable | |
+ attr_reader :size, :mask | |
+ def initialize table, links, size, mask | |
+ @table = table | |
+ @links = links | |
+ @size = size | |
+ @mask = mask | |
+ end | |
+ | |
+ def linkIndex index | |
+ if @links[index].nil? | |
+ -1 | |
+ else | |
+ @links[index] | |
+ end | |
+ end | |
+ | |
+ def tableIndex index | |
+ if @table[index].nil? | |
+ -1 | |
+ else | |
+ @table[index] | |
+ end | |
+ end | |
+end | |
+ | |
+def calcCompactHashSize properties | |
+ compactHashSize = ceilingToPowerOf2(2 * properties.size); | |
+ compactHashSizeMask = compactHashSize - 1; | |
+ compactSize = compactHashSize; | |
+ table = {} | |
+ links = {} | |
+ | |
+ collisions = 0; | |
+ maxDepth = 0; | |
+ | |
+ properties.each.with_index do |property, index| | |
+ depth = 0 | |
+ hashValue = property.hashValue % compactHashSize | |
+ while !table[hashValue].nil? | |
+ if !links[hashValue].nil? | |
+ hashValue = links[hashValue] | |
+ depth += 1 | |
+ else | |
+ collisions += 1 | |
+ links[hashValue] = compactSize | |
+ hashValue = compactSize | |
+ compactSize += 1 | |
+ end | |
+ end | |
+ table[hashValue] = index | |
+ maxDepth = [depth, maxDepth].max | |
+ end | |
+ | |
+ CompactTable.new(table, links, compactSize, compactHashSizeMask) | |
+end | |
+ | |
+class Property | |
+ attr_reader :hashValue | |
+ def initialize key, value, attributes, param, intrinsic | |
+ @key = key | |
+ @propertyName = @key | |
+ @attributes = attributes | |
+ @param = param | |
+ @intrinsic = intrinsic.empty? ? "NoIntrinsic" : intrinsic | |
+ @type = nil | |
+ @hasSetter = false | |
+ @builtin = value == "JSBuiltin" | |
+ @symbolKeyed = false | |
+ @privateSymbolKeyed = false | |
+ | |
+ if @key =~ /^@@(.+)/ | |
+ @symbolKeyed = true | |
+ @key = "Symbol.#{$1}" | |
+ @propertyName = $1 | |
+ elsif @key =~ /^@(.+)/ | |
+ @symbolKeyed = true | |
+ @privateSymbolKeyed = true | |
+ @key = "PrivateSymbol.#{$1}" | |
+ @propertyName = $1 | |
+ end | |
+ | |
+ case @attributes | |
+ when /Function/m | |
+ @type = :Function | |
+ @value = { "function" => value, "params" => (param.empty? ? "" : param) } | |
+ when /Accessor/m | |
+ @hasSetter = true | |
+ @type = :Accessor | |
+ @value = { "get" => value, "put" => "nullptr" } | |
+ when /CellProperty/m | |
+ @type = :CellProperty | |
+ @value = { "property" => value } | |
+ when /ClassStructure/m | |
+ @type = :ClassStructure | |
+ @value = { "property" => value } | |
+ when /PropertyCallback/m | |
+ @type = :PropertyCallback | |
+ @value = { "cback" => value } | |
+ else | |
+ if @attributes.empty? | |
+ @type = :Lexer | |
+ @attributes = "0" | |
+ @value = { "value" => value } | |
+ else | |
+ @type = :Property | |
+ get = value | |
+ put = "nullptr" | |
+ unless @attributes =~ /ReadOnly/m | |
+ put = "set" + jscUpcaseFirst(value) | |
+ end | |
+ @hasSetter = true | |
+ @value = { "get" => get, "put" => put } | |
+ end | |
+ end | |
+ | |
+ @hashValue = calcHashValue(@key) | |
+ end | |
+ | |
+ def builtin? | |
+ @builtin | |
+ end | |
+ | |
+ def hasSetter? | |
+ @hasSetter | |
+ end | |
+ | |
+ def symbolKeyed? | |
+ @symbolKeyed | |
+ end | |
+ | |
+ def privateSymbolKeyed? | |
+ @privateSymbolKeyed | |
+ end | |
+ | |
+ def stringKeyed? | |
+ !symbolKeyed? | |
+ end | |
+ | |
+ def output tableName | |
+ firstValue = ""; | |
+ secondValue = ""; | |
+ firstCastStr = ""; | |
+ secondCastStr = ""; | |
+ | |
+ case @type | |
+ when :Function | |
+ firstCastStr = "static_cast<NativeFunction>" | |
+ firstValue = @value["function"] | |
+ secondValue = @value["params"] | |
+ when :Accessor | |
+ firstCastStr = "static_cast<NativeFunction>" | |
+ secondCastStr = "static_cast<NativeFunction>" | |
+ firstValue = @value["get"] | |
+ secondValue = @value["put"] | |
+ when :Property | |
+ firstCastStr = "static_cast<PropertySlot::GetValueFunc>" | |
+ secondCastStr = "static_cast<PutPropertySlot::PutValueFunc>" | |
+ firstValue = @value["get"] | |
+ secondValue = @value["put"] | |
+ when :Lexer | |
+ firstValue = @value["value"] | |
+ secondValue = "0" | |
+ when :CellProperty, :ClassStructure | |
+ abort unless @value["property"] =~ /\A([a-zA-Z0-9_]+)::(.*)\Z/ | |
+ firstValue = "OBJECT_OFFSETOF(#{$1}, #{$2})" | |
+ secondValue = "0" | |
+ when :PropertyCallback | |
+ firstCastStr = "static_cast<LazyPropertyCallback>" | |
+ firstValue = @value["cback"] | |
+ secondValue = "0" | |
+ end | |
+ | |
+ propertyNameInSource = "\"#{@key}\"" | |
+ if symbolKeyed? | |
+ if privateSymbolKeyed? | |
+ propertyNameInSource = "reinterpret_cast<const char*>(&StaticSymbols::#{@propertyName}PrivateName())" | |
+ else | |
+ propertyNameInSource = "reinterpret_cast<const char*>(&StaticSymbols::#{@propertyName}Symbol())" | |
+ end | |
+ @attributes += '|HoldingSymbolKey' | |
+ end | |
+ | |
+ if @type == :Function && firstValue == "JSBuiltin" | |
+ tableHead = tableName.sub(/Table$/, "") | |
+ "{ #{propertyNameInSource}, ((#{@attributes}) & ~Function) | Builtin, #{@intrinsic}, { (intptr_t)static_cast<BuiltinGenerator>(" + tableHead + upcaseFirst(@propertyName) + "CodeGenerator), (intptr_t)#{secondValue} } }," | |
+ | |
+ else | |
+ "{ #{propertyNameInSource}, #{@attributes}, #{@intrinsic}, { (intptr_t)" + firstCastStr + "(#{firstValue}), (intptr_t)" + secondCastStr + "(#{secondValue}) } }," | |
+ end | |
+ end | |
+ | |
+ def inspect | |
+ "#{@key} = #{@value},hash:(#{@hashValue})" | |
+ end | |
+end | |
+ | |
+class PropertyTable | |
+ attr_reader :name | |
+ | |
+ def initialize name | |
+ @name = name | |
+ @includeBuiltin = false | |
+ @includeSymbolKeyed = false | |
+ @hasSetter = false | |
+ @properties = [] | |
+ end | |
+ | |
+ def push property | |
+ @properties.push(property) | |
+ @includeBuiltin = true if property.builtin? | |
+ @includeSymbolKeyed = true if property.symbolKeyed? | |
+ @hasSetter = true if property.hasSetter? | |
+ end | |
+ | |
+ def includeBuiltin? | |
+ @includeBuiltin | |
+ end | |
+ | |
+ def includeSymbolKeyed? | |
+ @includeSymbolKeyed | |
+ end | |
+ | |
+ def hasSetter? | |
+ @hasSetter | |
+ end | |
+ | |
+ def inspect | |
+ <<-EOS | |
+#{@name} includeBuiltin:(#{@includeBuiltin}) | |
+#{allProperties.map {|property| " " + property.inspect }.join("\n")} | |
+ EOS | |
+ end | |
+ | |
+ def stringProperties | |
+ @properties.select {|property| property.stringKeyed? } | |
+ end | |
+ | |
+ def symbolProperties | |
+ @properties.select {|property| property.symbolKeyed? } | |
+ end | |
+ | |
+ def allProperties | |
+ stringProperties + symbolProperties | |
+ end | |
+end | |
+ | |
+def outputCompactTable compactTable, nameIndex | |
+ puts "static const struct CompactHashIndex #{nameIndex}\[#{compactTable.size}\] = {" | |
+ compactTable.size.times do |index| | |
+ puts " { #{compactTable.tableIndex(index)}, #{compactTable.linkIndex(index)} }," | |
+ end | |
+ puts "};" | |
+ puts "" | |
+end | |
+ | |
+def output tables, filename | |
+ puts "// Automatically generated from #{filename} using #{__FILE__}. DO NOT EDIT!" | |
+ tables.each do |table| | |
+ nameEntries = "#{table.name}Values"; | |
+ nameEntries.gsub!(/:/, "_") | |
+ | |
+ stringNameIndex = "#{table.name}Index"; | |
+ stringNameIndex.gsub!(/:/, "_") | |
+ | |
+ puts "" | |
+ puts "#include \"JSCBuiltins.h\"" if table.includeBuiltin? | |
+ puts "#include \"Lookup.h\"" | |
+ puts "#include \"StaticSymbols.h\"" if table.includeSymbolKeyed? | |
+ puts "" | |
+ puts "namespace JSC {" | |
+ puts "" | |
+ | |
+ stringCompactTable = calcCompactHashSize(table.stringProperties) | |
+ outputCompactTable(stringCompactTable, stringNameIndex) | |
+ | |
+ symbolNameIndex = "nullptr" | |
+ symbolCompactTableMask = "0" | |
+ if table.includeSymbolKeyed? | |
+ symbolNameIndex = "#{table.name}SymbolIndex"; | |
+ symbolNameIndex.gsub!(/:/, "_") | |
+ symbolCompactTable = calcCompactHashSize(table.symbolProperties) | |
+ outputCompactTable(symbolCompactTable, symbolNameIndex) | |
+ symbolCompactTableMask = symbolCompactTable.mask | |
+ end | |
+ | |
+ allProperties = table.allProperties | |
+ puts "static const struct HashTableValue #{nameEntries}\[#{allProperties.size}\] = {" | |
+ allProperties.each do |property| | |
+ puts " #{property.output(table.name)}" | |
+ end | |
+ | |
+ puts "};" | |
+ puts "" | |
+ puts "static const struct HashTable #{table.name} =" | |
+ puts " \{ #{allProperties.size}, #{table.stringProperties.size}, #{stringCompactTable.mask}, #{symbolCompactTableMask}, #{table.hasSetter?}, #{nameEntries}, #{stringNameIndex}, #{symbolNameIndex} \};" | |
+ puts "" | |
+ puts "} // namespace JSC" | |
+ end | |
+end | |
+ | |
+def parse(file) | |
+ tables = [] | |
+ table = nil | |
+ | |
+ file.each do |line| | |
+ line.strip! | |
+ next if line =~ /^\#|^$/ # Comment or blank line. Do nothing. | |
+ | |
+ if line =~ /^\@begin/ && !table | |
+ if line =~ /^\@begin\s*([:_\w]+)\s*\d*\s*$/ | |
+ table = PropertyTable.new($1) | |
+ else | |
+ STDERR.puts "WARNING: \@begin without table name, skipping \"#{line}\""; | |
+ end | |
+ elsif line =~ /^\@end\s*$/ && table | |
+ tables.push table | |
+ table = nil | |
+ elsif line =~ /^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*(\w*)\s*$/ && table | |
+ key = $1 | |
+ value = $2 | |
+ attributes = $3 | |
+ param = $4 | |
+ intrinsic = $5 | |
+ table.push(Property.new(key, value, attributes, param, intrinsic)) | |
+ elsif table | |
+ abort "invalid data \"#{line}\"" | |
+ end | |
+ end | |
+ | |
+ abort "missing closing \@end" if table | |
+ | |
+ tables | |
+end | |
+ | |
+$filename = ARGV.first | |
+File.open($filename) do |file| | |
+ output(parse(file), $filename) | |
+end | |
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp | |
index 8b33731..ba9dc59 100644 | |
--- a/Source/JavaScriptCore/runtime/JSObject.cpp | |
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp | |
@@ -81,9 +81,17 @@ static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* class | |
if (!table) | |
continue; | |
- for (auto iter = table->begin(); iter != table->end(); ++iter) { | |
- if (!(iter->attributes() & DontEnum) || mode.includeDontEnumProperties()) | |
- propertyNames.add(Identifier::fromString(&vm, iter.key())); | |
+ for (const HashTableValue& value : *table) { | |
+ if (!(value.attributes() & DontEnum) || mode.includeDontEnumProperties()) { | |
+ if (value.isSymbolKeyed()) { | |
+ if (propertyNames.includeSymbolProperties()) | |
+ propertyNames.add(Identifier::fromUid(&vm, value.symbolKey())); | |
+ continue; | |
+ } | |
+ | |
+ if (propertyNames.includeStringProperties()) | |
+ propertyNames.add(Identifier::fromString(&vm, value.stringKey())); | |
+ } | |
} | |
} | |
} | |
@@ -1987,7 +1995,7 @@ void JSObject::reifyAllStaticProperties(ExecState* exec) | |
for (auto& value : *hashTable) { | |
unsigned attributes; | |
- auto key = Identifier::fromString(&vm, value.m_key); | |
+ Identifier key(value.isSymbolKeyed() ? Identifier::fromUid(&vm, value.symbolKey()) : Identifier::fromString(&vm, value.stringKey())); | |
PropertyOffset offset = getDirectOffset(vm, key, attributes); | |
if (!isValidOffset(offset)) | |
reifyStaticProperty(vm, key, value, *this); | |
diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h | |
index 5b2c4a4..df2f2a5 100644 | |
--- a/Source/JavaScriptCore/runtime/Lookup.h | |
+++ b/Source/JavaScriptCore/runtime/Lookup.h | |
@@ -50,7 +50,7 @@ typedef JSValue (*LazyPropertyCallback)(VM&, JSObject*); | |
// Hash table generated by the create_hash_table script. | |
struct HashTableValue { | |
- const char* m_key; // property name | |
+ const char* m_propertyName; // property name | |
unsigned m_attributes; // JSObject attributes | |
Intrinsic m_intrinsic; | |
union ValueStorage { | |
@@ -70,6 +70,11 @@ struct HashTableValue { | |
} m_values; | |
unsigned attributes() const { return m_attributes; } | |
+ const char* stringKey() const { return m_propertyName; } | |
+ SymbolImpl* symbolKey() const { return const_cast<SymbolImpl*>(reinterpret_cast<const SymbolImpl*>(m_propertyName)); } | |
+ bool isEmpty() const { return m_propertyName == nullptr; } | |
+ bool isStringKeyed() const { return !isSymbolKeyed(); } | |
+ bool isSymbolKeyed() const { return m_attributes & HoldingSymbolKey; } | |
Intrinsic intrinsic() const { ASSERT(m_attributes & Function); return m_intrinsic; } | |
BuiltinGenerator builtinGenerator() const { ASSERT(m_attributes & Builtin); return reinterpret_cast<BuiltinGenerator>(m_values.value1); } | |
@@ -94,30 +99,25 @@ struct HashTableValue { | |
}; | |
struct HashTable { | |
- int numberOfValues; | |
- int indexMask; | |
+ int numberOfAllValues; | |
+ int numberOfStringKeyedValues; | |
+ int stringKeyedIndexMask; | |
+ int symbolKeyedIndexMask; | |
bool hasSetterOrReadonlyProperties; | |
const HashTableValue* values; // Fixed values generated by script. | |
- const CompactHashIndex* index; | |
+ const CompactHashIndex* stringKeyedIndex; | |
+ const CompactHashIndex* symbolKeyedIndex; | |
- // Find an entry in the table, and return the entry. | |
- ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const | |
+ template<typename EqualPredicate> | |
+ static ALWAYS_INLINE const HashTableValue* searchInTable(int indexEntry, const CompactHashIndex* index, const HashTableValue* values, EqualPredicate predicate) | |
{ | |
- if (propertyName.isSymbol()) | |
- return nullptr; | |
- | |
- auto uid = propertyName.uid(); | |
- if (!uid) | |
- return nullptr; | |
- | |
- int indexEntry = IdentifierRepHash::hash(uid) & indexMask; | |
int valueIndex = index[indexEntry].value; | |
if (valueIndex == -1) | |
return nullptr; | |
while (true) { | |
- if (WTF::equal(uid, values[valueIndex].m_key)) | |
+ if (predicate(values[valueIndex])) | |
return &values[valueIndex]; | |
indexEntry = index[indexEntry].next; | |
@@ -128,6 +128,30 @@ struct HashTable { | |
}; | |
} | |
+ // Find an entry in the table, and return the entry. | |
+ ALWAYS_INLINE const HashTableValue* entry(PropertyName propertyName) const | |
+ { | |
+ auto uid = propertyName.uid(); | |
+ if (!uid) | |
+ return nullptr; | |
+ | |
+ if (uid->isSymbol()) { | |
+ if (!symbolKeyedIndex) | |
+ return nullptr; | |
+ // Call StringImpl::hash() explicitly since we would not like to retrieve symbolAwareHash() here. | |
+ int indexEntry = uid->hash() & symbolKeyedIndexMask; | |
+ return searchInTable(indexEntry, symbolKeyedIndex, values + numberOfStringKeyedValues, [&] (const HashTableValue& value) { | |
+ return uid == value.symbolKey(); | |
+ }); | |
+ } | |
+ | |
+ ASSERT_WITH_MESSAGE(numberOfStringKeyedValues, "Currently, all the static hash table should hold string keyed properties"); | |
+ int indexEntry = IdentifierRepHash::hash(uid) & stringKeyedIndexMask; | |
+ return searchInTable(indexEntry, stringKeyedIndex, values, [&] (const HashTableValue& value) { | |
+ return WTF::equal(uid, value.stringKey()); | |
+ }); | |
+ } | |
+ | |
class ConstIterator { | |
public: | |
ConstIterator(const HashTable* table, int position) | |
@@ -144,11 +168,6 @@ struct HashTable { | |
const HashTableValue& operator*() const { return *value(); } | |
- const char* key() const | |
- { | |
- return m_table->values[m_position].m_key; | |
- } | |
- | |
const HashTableValue* operator->() const | |
{ | |
return value(); | |
@@ -162,7 +181,7 @@ struct HashTable { | |
ConstIterator& operator++() | |
{ | |
- ASSERT(m_position < m_table->numberOfValues); | |
+ ASSERT(m_position < m_table->numberOfAllValues); | |
++m_position; | |
skipInvalidKeys(); | |
return *this; | |
@@ -171,10 +190,10 @@ struct HashTable { | |
private: | |
void skipInvalidKeys() | |
{ | |
- ASSERT(m_position <= m_table->numberOfValues); | |
- while (m_position < m_table->numberOfValues && !m_table->values[m_position].m_key) | |
+ ASSERT(m_position <= m_table->numberOfAllValues); | |
+ while (m_position < m_table->numberOfAllValues && m_table->values[m_position].isEmpty()) | |
++m_position; | |
- ASSERT(m_position <= m_table->numberOfValues); | |
+ ASSERT(m_position <= m_table->numberOfAllValues); | |
} | |
const HashTable* m_table; | |
@@ -187,7 +206,7 @@ struct HashTable { | |
} | |
ConstIterator end() const | |
{ | |
- return ConstIterator(this, numberOfValues); | |
+ return ConstIterator(this, numberOfAllValues); | |
} | |
}; | |
@@ -346,9 +365,9 @@ inline void reifyStaticProperties(VM& vm, const HashTableValue (&values)[numberO | |
{ | |
BatchedTransitionOptimizer transitionOptimizer(vm, &thisObj); | |
for (auto& value : values) { | |
- if (!value.m_key) | |
+ if (value.isEmpty()) | |
continue; | |
- auto key = Identifier::fromString(&vm, reinterpret_cast<const LChar*>(value.m_key), strlen(value.m_key)); | |
+ Identifier key(value.isSymbolKeyed() ? Identifier::fromUid(&vm, value.symbolKey()) : Identifier::fromString(&vm, reinterpret_cast<const LChar*>(value.stringKey()), strlen(value.stringKey()))); | |
reifyStaticProperty(vm, key, value, thisObj); | |
} | |
} | |
diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h | |
index d7d76c7..28632fc 100644 | |
--- a/Source/JavaScriptCore/runtime/PropertySlot.h | |
+++ b/Source/JavaScriptCore/runtime/PropertySlot.h | |
@@ -49,6 +49,7 @@ enum Attribute { | |
CellProperty = 1 << 11, // property is a lazy property - only used by static hashtables | |
ClassStructure = 1 << 12, // property is a lazy class structure - only used by static hashtables | |
PropertyCallback = 1 << 13, // property that is a lazy property callback - only used by static hashtables | |
+ HoldingSymbolKey = 1 << 14, // property that key is symbol - only used by static hashtables | |
BuiltinOrFunction = Builtin | Function, // helper only used by static hashtables | |
BuiltinOrFunctionOrLazyProperty = Builtin | Function | CellProperty | ClassStructure | PropertyCallback, // helper only used by static hashtables | |
BuiltinOrFunctionOrAccessorOrLazyProperty = Builtin | Function | Accessor | CellProperty | ClassStructure | PropertyCallback, // helper only used by static hashtables | |
diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp | |
index db564bb..ef1becd 100644 | |
--- a/Source/JavaScriptCore/runtime/StringConstructor.cpp | |
+++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp | |
@@ -45,7 +45,7 @@ const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_i | |
/* Source for StringConstructor.lut.h | |
@begin stringConstructorTable | |
fromCharCode stringFromCharCode DontEnum|Function 1 | |
- fromCodePoint stringFromCodePoint DontEnum|Function 1 | |
+ fromCodePoint stringFromCodePoint DontEnum|Function 1 FromCharCodeIntrinsic | |
raw JSBuiltin DontEnum|Function 1 | |
@end | |
*/ | |
diff --git a/Source/WTF/wtf/StdLibExtras.h b/Source/WTF/wtf/StdLibExtras.h | |
index 4457ba2..746aa06 100644 | |
--- a/Source/WTF/wtf/StdLibExtras.h | |
+++ b/Source/WTF/wtf/StdLibExtras.h | |
@@ -184,10 +184,11 @@ inline size_t roundUpToMultipleOf(size_t divisor, size_t x) | |
return (x + remainderMask) & ~remainderMask; | |
} | |
-template<size_t divisor> inline size_t roundUpToMultipleOf(size_t x) | |
+template<size_t divisor> inline constexpr size_t roundUpToMultipleOf(size_t x) | |
{ | |
static_assert(divisor && !(divisor & (divisor - 1)), "divisor must be a power of two!"); | |
- return roundUpToMultipleOf(divisor, x); | |
+ constexpr size_t remainderMask = divisor - 1; | |
+ return (x + remainderMask) & ~remainderMask; | |
} | |
enum BinarySearchMode { | |
diff --git a/Source/WTF/wtf/text/AtomicStringImpl.cpp b/Source/WTF/wtf/text/AtomicStringImpl.cpp | |
index ac60b63..5d20a94 100644 | |
--- a/Source/WTF/wtf/text/AtomicStringImpl.cpp | |
+++ b/Source/WTF/wtf/text/AtomicStringImpl.cpp | |
@@ -401,7 +401,7 @@ Ref<AtomicStringImpl> AtomicStringImpl::addSlowCase(StringImpl& string) | |
if (!string.length()) | |
return *static_cast<AtomicStringImpl*>(StringImpl::empty()); | |
- if (string.isSymbol()) { | |
+ if (string.isSymbol() || string.isStatic()) { | |
if (string.is8Bit()) | |
return *add(string.characters8(), string.length()); | |
return *add(string.characters16(), string.length()); | |
@@ -425,7 +425,7 @@ Ref<AtomicStringImpl> AtomicStringImpl::addSlowCase(AtomicStringTable& stringTab | |
if (!string.length()) | |
return *static_cast<AtomicStringImpl*>(StringImpl::empty()); | |
- if (string.isSymbol()) { | |
+ if (string.isSymbol() || string.isStatic()) { | |
if (string.is8Bit()) | |
return *add(string.characters8(), string.length()); | |
return *add(string.characters16(), string.length()); | |
@@ -461,7 +461,7 @@ RefPtr<AtomicStringImpl> AtomicStringImpl::lookUpSlowCase(StringImpl& string) | |
if (!string.length()) | |
return static_cast<AtomicStringImpl*>(StringImpl::empty()); | |
- if (string.isSymbol()) { | |
+ if (string.isSymbol() || string.isStatic()) { | |
if (string.is8Bit()) | |
return lookUpInternal(string.characters8(), string.length()); | |
return lookUpInternal(string.characters16(), string.length()); | |
diff --git a/Source/WTF/wtf/text/StringImpl.cpp b/Source/WTF/wtf/text/StringImpl.cpp | |
index 2d0da35..61cd24d 100644 | |
--- a/Source/WTF/wtf/text/StringImpl.cpp | |
+++ b/Source/WTF/wtf/text/StringImpl.cpp | |
@@ -294,13 +294,7 @@ Ref<StringImpl> StringImpl::create(const LChar* string) | |
Ref<SymbolImpl> StringImpl::createSymbol(StringImpl& rep) | |
{ | |
auto* ownerRep = (rep.bufferOwnership() == BufferSubstring) ? rep.substringBuffer() : &rep; | |
- | |
- // We allocate a buffer that contains | |
- // 1. the StringImpl struct | |
- // 2. the pointer to the owner string | |
- // 3. the pointer to the symbol registry | |
- // 4. the placeholder for symbol aware hash value (allocated size is pointer size, but only 4 bytes are used) | |
- auto* stringImpl = static_cast<StringImpl*>(fastMalloc(allocationSize<StringImpl*>(3))); | |
+ auto* stringImpl = static_cast<StringImpl*>(fastMalloc(SymbolImpl::allocationSize())); | |
if (rep.is8Bit()) | |
return adoptRef(static_cast<SymbolImpl&>(*new (NotNull, stringImpl) StringImpl(CreateSymbol, rep.m_data8, rep.length(), *ownerRep))); | |
return adoptRef(static_cast<SymbolImpl&>(*new (NotNull, stringImpl) StringImpl(CreateSymbol, rep.m_data16, rep.length(), *ownerRep))); | |
diff --git a/Source/WTF/wtf/text/StringImpl.h b/Source/WTF/wtf/text/StringImpl.h | |
index 53484fe..2c6e5a3 100644 | |
--- a/Source/WTF/wtf/text/StringImpl.h | |
+++ b/Source/WTF/wtf/text/StringImpl.h | |
@@ -140,6 +140,10 @@ class StringImpl { | |
friend class JSC::LLInt::Data; | |
friend class JSC::LLIntOffsetsExtractor; | |
+public: | |
+ enum ConstructStaticStringTag { ConstructStaticString }; | |
+ enum CreateSymbolTag { CreateSymbol }; | |
+ | |
private: | |
enum BufferOwnership { | |
BufferInternal, | |
@@ -298,7 +302,6 @@ class StringImpl { | |
STRING_STATS_ADD_16BIT_STRING2(m_length, true); | |
} | |
- enum CreateSymbolTag { CreateSymbol }; | |
// Used to create new symbol strings that holds existing 8-bit [[Description]] string as a substring buffer (BufferSubstring). | |
StringImpl(CreateSymbolTag, const LChar* characters, unsigned length, Ref<StringImpl>&& base) | |
: m_refCount(s_refCountIncrement) | |
@@ -335,6 +338,45 @@ class StringImpl { | |
STRING_STATS_ADD_16BIT_STRING2(m_length, true); | |
} | |
+protected: | |
+ // Static StringImpl will be constructed with NeverDestroyed. And all its members are initialized and not changed (logically), | |
+ // and it is never destroyed. Thus it can be shared across the threads (as the same to StringImpl::empty()). | |
+ template<unsigned charactersCount> | |
+ StringImpl(ConstructStaticStringTag, const char (&characters)[charactersCount]) | |
+ : m_refCount(s_refCountFlagIsStaticString) | |
+ , m_length(charactersCount - 1) | |
+ , m_data8(reinterpret_cast<const LChar*>(characters)) | |
+ , m_hashAndFlags(s_hashFlag8BitBuffer | StringNormal | BufferInternal) | |
+ { | |
+ // Ensure that the hash is computed so that AtomicStringHash can call existingHash() with impunity. | |
+ STRING_STATS_ADD_8BIT_STRING(m_length); | |
+ | |
+ hash(); | |
+ } | |
+ | |
+ // Used to create a new static symbol strings derived from the static string. | |
+ StringImpl(CreateSymbolTag, ConstructStaticStringTag, Ref<StringImpl>&& base) | |
+ : m_refCount(s_refCountFlagIsStaticString) | |
+ , m_length(base->length()) | |
+ , m_data8(base->characters8()) | |
+ , m_hashAndFlags(s_hashFlag8BitBuffer | StringSymbol | BufferSubstring) | |
+ { | |
+ ASSERT(is8Bit()); | |
+ ASSERT(isStatic()); | |
+ ASSERT(m_data8); | |
+ ASSERT(base->bufferOwnership() != BufferSubstring); | |
+ ASSERT(base->isStatic()); | |
+ ASSERT(base->is8Bit()); | |
+ | |
+ // Ensure all its members are initialized in the constructor. | |
+ substringBuffer() = &base.leakRef(); | |
+ symbolRegistry() = nullptr; | |
+ hashForSymbol() = nextHashForSymbol(); | |
+ hash(); | |
+ | |
+ STRING_STATS_ADD_8BIT_STRING2(m_length, true); | |
+ } | |
+ | |
public: | |
WTF_EXPORT_STRING_API static void destroy(StringImpl*); | |
@@ -793,6 +835,12 @@ class StringImpl { | |
protected: | |
~StringImpl(); | |
+ template<typename T> | |
+ static constexpr size_t allocationSize(unsigned tailElementCount) | |
+ { | |
+ return tailOffset<T>() + tailElementCount * sizeof(T); | |
+ } | |
+ | |
private: | |
bool requiresCopy() const | |
{ | |
@@ -805,13 +853,7 @@ class StringImpl { | |
} | |
template<typename T> | |
- static size_t allocationSize(unsigned tailElementCount) | |
- { | |
- return tailOffset<T>() + tailElementCount * sizeof(T); | |
- } | |
- | |
- template<typename T> | |
- static ptrdiff_t tailOffset() | |
+ static constexpr ptrdiff_t tailOffset() | |
{ | |
#if COMPILER(MSVC) | |
// MSVC doesn't support alignof yet. | |
diff --git a/Source/WTF/wtf/text/SymbolImpl.h b/Source/WTF/wtf/text/SymbolImpl.h | |
index 4043bf4..b162b1a 100644 | |
--- a/Source/WTF/wtf/text/SymbolImpl.h | |
+++ b/Source/WTF/wtf/text/SymbolImpl.h | |
@@ -33,9 +33,33 @@ namespace WTF { | |
// SymbolImpl is used to represent the symbol string impl. | |
// It is uniqued string impl, but is not registered in Atomic String tables, so it's not atomic. | |
class SymbolImpl : public UniquedStringImpl { | |
+public: | |
+ static constexpr size_t allocationSize() | |
+ { | |
+ // We allocate a buffer that contains | |
+ // 1. the StringImpl struct | |
+ // 2. the pointer to the owner string | |
+ // 3. the pointer to the symbol registry | |
+ // 4. the placeholder for symbol aware hash value (allocated size is pointer size, but only 4 bytes are used) | |
+ return StringImpl::allocationSize<StringImpl*>(3); | |
+ } | |
+ | |
private: | |
SymbolImpl() = delete; | |
+ | |
+ // Called from NeverDestroyed. | |
+ friend class NeverDestroyed<SymbolImpl>; | |
+ SymbolImpl(ConstructStaticStringTag, StringImpl& staticStringImpl) | |
+ : UniquedStringImpl(CreateSymbol, ConstructStaticString, staticStringImpl) | |
+ { | |
+ } | |
+ | |
+ StringImpl* m_owner; | |
+ SymbolRegistry* m_symbolRegistry; | |
+ void* m_symbolAwareHash; | |
}; | |
+static_assert(SymbolImpl::allocationSize() == sizeof(SymbolImpl), "sizeof(SymbolImpl) should contain 3 tail pointers."); | |
+ | |
#if !ASSERT_DISABLED | |
// SymbolImpls created from StaticASCIILiteral will ASSERT | |
diff --git a/Source/WTF/wtf/text/UniquedStringImpl.h b/Source/WTF/wtf/text/UniquedStringImpl.h | |
index 554e533..3bdc329 100644 | |
--- a/Source/WTF/wtf/text/UniquedStringImpl.h | |
+++ b/Source/WTF/wtf/text/UniquedStringImpl.h | |
@@ -35,6 +35,12 @@ namespace WTF { | |
class UniquedStringImpl : public StringImpl { | |
private: | |
UniquedStringImpl() = delete; | |
+ | |
+protected: | |
+ UniquedStringImpl(CreateSymbolTag, ConstructStaticStringTag, StringImpl& staticStringImpl) | |
+ : StringImpl(CreateSymbol, ConstructStaticString, staticStringImpl) | |
+ { | |
+ } | |
}; | |
#if !ASSERT_DISABLED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment