Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion scripts/build/deps/webkit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
* for local mode. Override via `--webkit-version=<hash>` to test a branch.
* From https://github.com/oven-sh/WebKit releases.
*/
export const WEBKIT_VERSION = "5488984d20e0dbfe4be2c3ba8fb18eb81a5e0e8b";
export const WEBKIT_VERSION = "3167a44fb92c268c83f09b232b38a9f3e7f9655a";

/**
* WebKit (JavaScriptCore) — the JS engine.
Expand Down
177 changes: 75 additions & 102 deletions src/codegen/create_hash_table
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,14 @@ while (<IN>) {
chomp;
s/^\s+//;
next if /^\#|^$/; # Comment or blank line. Do nothing.
if (/^\@begin/ && !$inside) {
if (!$inside && /^\@begin/) {
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) {
} elsif ($inside && /^\@end\s*$/) {
output();

@keys = ();
Expand All @@ -74,7 +74,7 @@ while (<IN>) {
$includeBuiltin = 0;

$inside = 0;
} elsif (/^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*(\w*)\s*$/ && $inside) {
} elsif ($inside && /^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*(\w*)\s*$/) {
my $key = $1;
my $val = $2;
my $att = $3;
Expand Down Expand Up @@ -106,15 +106,11 @@ while (<IN>) {
} elsif (length($att)) {
my $get = $val;
my $put = "0";
my $type = "PropertyAttribute::Property";
if ($att =~ m/Builtin/) {
$type = "PropertyAttribute::BuiltinAccessor";
}
if (!($att =~ m/ReadOnly/)) {
$put = "set" . jsc_ucfirst($val);
}
$hasSetter = "true";
push(@values, { "type" => $type, "get" => $get, "put" => $put });
push(@values, { "type" => "PropertyAttribute::Property", "get" => $get, "put" => $put });
} else {
push(@values, { "type" => "Lexer", "value" => $val });
}
Expand Down Expand Up @@ -230,7 +226,7 @@ sub uint64_multi($$) {
return $product & $mask64;
}

sub wymum($$) {
sub rapid_mul128($$) {
my ($A, $B) = @_;

my $ha = $A >> 32;
Expand All @@ -253,114 +249,106 @@ sub wymum($$) {
return ($lo, $hi);
};

sub wymix($$) {
sub rapid_mix($$) {
my ($A, $B) = @_;
($A, $B) = wymum($A, $B);
($A, $B) = rapid_mul128($A, $B);
return $A ^ $B;
}

sub convert32BitTo64Bit($) {
my ($v) = @_;
my ($mask1) = 281470681808895; # 0x0000_ffff_0000_ffff
$v = ($v | ($v << 16)) & $mask1;
my ($mask2) = 71777214294589695; # 0x00ff_00ff_00ff_00ff
return ($v | ($v << 8)) & $mask2;
}

sub convert16BitTo32Bit($) {
my ($v) = @_;
return ($v | ($v << 8)) & 0x00ff_00ff;
}

sub wyhash {
# https://github.com/wangyi-fudan/wyhash
sub rapidhash {
# https://github.com/Nicoshev/rapidhash
# Hashes raw ASCII bytes (1 byte per character).
my @chars = @_;
my $charCount = scalar @chars;
my $byteCount = $charCount << 1;
my $charIndex = 0;
my $seed = 0;
my @secret = ( 11562461410679940143, 16646288086500911323, 10285213230658275043, 6384245875588680899 );
my $move1 = (($byteCount >> 3) << 2) >> 1;

$seed ^= wymix($seed ^ $secret[0], $secret[1]);
my $len = scalar @chars;
my @secret = ( 3257665815644502181, 10067880064238660809, 5418857496715711651 );

my $seed = rapid_mix(0 ^ $secret[0], $secret[1]) ^ $len;
my $a = 0;
my $b = 0;

local *c2i = sub {
local *read64 = sub {
my ($i) = @_;
return ord($chars[$i]);
return ord($chars[$i])
| (ord($chars[$i + 1]) << 8)
| (ord($chars[$i + 2]) << 16)
| (ord($chars[$i + 3]) << 24)
| (ord($chars[$i + 4]) << 32)
| (ord($chars[$i + 5]) << 40)
| (ord($chars[$i + 6]) << 48)
| (ord($chars[$i + 7]) << 56);
};

local *wyr8 = sub {
local *read32 = sub {
my ($i) = @_;
my $v = c2i($i) | (c2i($i + 1) << 8) | (c2i($i + 2) << 16) | (c2i($i + 3) << 24);
return convert32BitTo64Bit($v);
return ord($chars[$i])
| (ord($chars[$i + 1]) << 8)
| (ord($chars[$i + 2]) << 16)
| (ord($chars[$i + 3]) << 24);
};

local *wyr4 = sub {
my ($i) = @_;
my $v = c2i($i) | (c2i($i + 1) << 8);
return convert16BitTo32Bit($v);
local *readSmall = sub {
my ($i, $k) = @_;
return (ord($chars[$i]) << 56)
| (ord($chars[$i + ($k >> 1)]) << 32)
| ord($chars[$i + $k - 1]);
};

local *wyr2 = sub {
my ($i) = @_;
return c2i($i) << 16;
};

if ($byteCount <= 16) {
if ($byteCount >= 4) {
$a = (wyr4($charIndex) << 32) | wyr4($charIndex + $move1);
$charIndex = $charIndex + $charCount - 2;
$b = (wyr4($charIndex) << 32) | wyr4($charIndex - $move1);
} elsif ($byteCount > 0) {
$a = wyr2($charIndex);
if ($len <= 16) {
if ($len >= 4) {
my $delta = ($len >= 8) ? 4 : 0;
$a = (read32(0) << 32) | read32($len - 4);
$b = (read32($delta) << 32) | read32($len - 4 - $delta);
} elsif ($len > 0) {
$a = readSmall(0, $len);
$b = 0;
} else {
$a = $b = 0;
}
} else {
my $i = $byteCount;
my $i = $len;
my $off = 0;
if ($i > 48) {
my $see1 = $seed;
my $see2 = $seed;
do {
$seed = wymix(wyr8($charIndex) ^ $secret[1], wyr8($charIndex + 4) ^ $seed);
$see1 = wymix(wyr8($charIndex + 8) ^ $secret[2], wyr8($charIndex + 12) ^ $see1);
$see2 = wymix(wyr8($charIndex + 16) ^ $secret[3], wyr8($charIndex + 20) ^ $see2);
$charIndex += 24;
$seed = rapid_mix(read64($off) ^ $secret[0], read64($off + 8) ^ $seed);
$see1 = rapid_mix(read64($off + 16) ^ $secret[1], read64($off + 24) ^ $see1);
$see2 = rapid_mix(read64($off + 32) ^ $secret[2], read64($off + 40) ^ $see2);
$off += 48;
$i -= 48;
} while ($i > 48);
} while ($i >= 48);
$seed ^= $see1 ^ $see2;
}
while ($i > 16) {
$seed = wymix(wyr8($charIndex) ^ $secret[1], wyr8($charIndex + 4) ^ $seed);
$i -= 16;
$charIndex += 8;
if ($i > 16) {
$seed = rapid_mix(read64($off) ^ $secret[2], read64($off + 8) ^ $seed ^ $secret[1]);
if ($i > 32) {
$seed = rapid_mix(read64($off + 16) ^ $secret[2], read64($off + 24) ^ $seed);
}
}
my $move2 = $i >> 1;
$a = wyr8($charIndex + $move2 - 8);
$b = wyr8($charIndex + $move2 - 4);
$a = read64($off + $i - 16);
$b = read64($off + $i - 8);
}
$a ^= $secret[1];
$b ^= $seed;

($a, $b) = wymum($a, $b);
my $hash = wymix($a ^ $secret[0] ^ $byteCount, $b ^ $secret[1]) & $mask32;
($a, $b) = rapid_mul128($a, $b);
my $hash = rapid_mix($a ^ $secret[0] ^ $len, $b ^ $secret[1]) & $mask32;

return maskTop8BitsAndAvoidZero($hash);
}

sub hashValue($) {
my ($string) = @_;
my @chars = split(/ */, $string);
return wyhash(@chars);
return rapidhash(@chars);
}

sub output() {
if (!$banner) {
$banner = 1;
print "// Automatically generated from $file using $0. DO NOT EDIT!\n";
my ($srcName) = $file =~ m|([^/]+)$|;
my ($selfName) = $0 =~ m|([^/]+)$|;
print "// Automatically generated from $srcName using $selfName. DO NOT EDIT!\n";
}

my $nameEntries = "${name}Values";
Expand All @@ -376,36 +364,24 @@ sub output() {
print "\n";

local *generateHashTableHelper = sub {
calcPerfectHashSize();
calcCompactHashSize();

my $hashTableString = "";

if ($compactSize != 0) {
$hashTableString .= "static constinit 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]; }
$hashTableString .= " { $T, $L },\n";
}
} else {
# MSVC dislikes empty arrays.
$hashTableString .= "static constinit const struct CompactHashIndex ${nameIndex}\[1\] = {\n";
$hashTableString .= " { 0, 0 }\n";
$hashTableString .= "static constinit 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]; }
$hashTableString .= " { $T, $L },\n";
}

$hashTableString .= "};\n";
$hashTableString .= "\n";

my $packedSize = scalar @keys;
if ($packedSize != 0) {
$hashTableString .= "static constinit const struct HashTableValue ${nameEntries}\[$packedSize\] = {\n";
} else {
# MSVC dislikes empty arrays.
$hashTableString .= "static constinit const struct HashTableValue ${nameEntries}\[1\] = {\n";
$hashTableString .= " { { }, 0, NoIntrinsic, { HashTableValue::End } }\n";
}
$hashTableString .= "static constinit const struct HashTableValue ${nameEntries}\[$packedSize\] = {\n";

my $i = 0;
foreach my $key (@keys) {
Expand All @@ -420,14 +396,6 @@ sub output() {
$firstValue = $values[$i]{"function"};
$secondValue = $values[$i]{"params"};
$intrinsic = $values[$i]{"intrinsic"};
} elsif ($values[$i]{"type"} eq "PropertyAttribute::BuiltinAccessor") {
$typeTag = "BuiltinAccessor";
$firstValue = $values[$i]{"get"};
$secondValue = $values[$i]{"put"};
} elsif ($values[$i]{"type"} eq "PropertyAttribute::ConstantInteger") {
$typeTag = "Constant";
$firstValue = $values[$i]{"value"};
$hasSecondValue = 0;
} elsif ($values[$i]{"type"} eq "PropertyAttribute::Property") {
$typeTag = "GetterSetter";
$firstValue = $values[$i]{"get"};
Expand All @@ -445,6 +413,10 @@ sub output() {
$typeTag = "LazyProperty";
$firstValue = $values[$i]{"cback"};
$hasSecondValue = 0;
} elsif ($values[$i]{"type"} eq "PropertyAttribute::ConstantInteger") {
$typeTag = "Constant";
$firstValue = $values[$i]{"value"};
$hasSecondValue = 0;
}

my $attributes = "PropertyAttribute::" . $attrs[$i];
Expand Down Expand Up @@ -472,7 +444,8 @@ sub output() {
return $hashTableString;
};

print generateHashTableHelper();
my $hashTableToWrite = generateHashTableHelper();
print $hashTableToWrite;

print "} // namespace JSC\n";
}
28 changes: 5 additions & 23 deletions src/codegen/replacements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -256,34 +256,16 @@ export function applyReplacements(src: string, length: number) {
const id = registerNativeCall(kind, args[0], args[1], is_create_fn ? args[2] : null);

return [slice.slice(0, match.index) + "__intrinsic__lazy(" + id + ")", inner.rest, true];
} else if (name === "isPromiseFulfilled") {
} else if (name === "isPromiseFulfilled" || name === "isPromiseRejected" || name === "isPromisePending") {
const inner = sliceSourceCode(rest, true);
// JSC::JSPromise::Status: Pending = 0, Fulfilled = 1, Rejected = 2.
const status = name === "isPromisePending" ? 0 : name === "isPromiseFulfilled" ? 1 : 2;
let args;
if (debug) {
// use a property on @lazy as a temporary holder for the expression. only in debug!
args = `($assert(__intrinsic__isPromise(__intrinsic__lazy.temp=${inner.result.slice(0, -1)}))),(__intrinsic__getPromiseInternalField(__intrinsic__lazy.temp, __intrinsic__promiseFieldFlags) & __intrinsic__promiseStateMask) === (__intrinsic__lazy.temp = undefined, __intrinsic__promiseStateFulfilled))`;
args = `($assert(__intrinsic__isPromise(__intrinsic__lazy.temp=${inner.result.slice(0, -1)}))),__intrinsic__peekPromiseStatus(__intrinsic__lazy.temp) === (__intrinsic__lazy.temp = undefined, ${status}))`;
} else {
args = `((__intrinsic__getPromiseInternalField(${inner.result.slice(0, -1)}), __intrinsic__promiseFieldFlags) & __intrinsic__promiseStateMask) === __intrinsic__promiseStateFulfilled)`;
}
return [slice.slice(0, match.index) + args, inner.rest, true];
} else if (name === "isPromiseRejected") {
const inner = sliceSourceCode(rest, true);
let args;
if (debug) {
// use a property on @lazy as a temporary holder for the expression. only in debug!
args = `($assert(__intrinsic__isPromise(__intrinsic__lazy.temp=${inner.result.slice(0, -1)}))),(__intrinsic__getPromiseInternalField(__intrinsic__lazy.temp, __intrinsic__promiseFieldFlags) & __intrinsic__promiseStateMask) === (__intrinsic__lazy.temp = undefined, __intrinsic__promiseStateRejected))`;
} else {
args = `((__intrinsic__getPromiseInternalField(${inner.result.slice(0, -1)}), __intrinsic__promiseFieldFlags) & __intrinsic__promiseStateMask) === __intrinsic__promiseStateRejected)`;
}
return [slice.slice(0, match.index) + args, inner.rest, true];
} else if (name === "isPromisePending") {
const inner = sliceSourceCode(rest, true);
let args;
if (debug) {
// use a property on @lazy as a temporary holder for the expression. only in debug!
args = `($assert(__intrinsic__isPromise(__intrinsic__lazy.temp=${inner.result.slice(0, -1)}))),(__intrinsic__getPromiseInternalField(__intrinsic__lazy.temp, __intrinsic__promiseFieldFlags) & __intrinsic__promiseStateMask) === (__intrinsic__lazy.temp = undefined, __intrinsic__promiseStatePending))`;
} else {
args = `((__intrinsic__getPromiseInternalField(${inner.result.slice(0, -1)}), __intrinsic__promiseFieldFlags) & __intrinsic__promiseStateMask) === __intrinsic__promiseStatePending)`;
args = `(__intrinsic__peekPromiseStatus${inner.result} === ${status})`;
}
return [slice.slice(0, match.index) + args, inner.rest, true];
} else if (name === "bindgenFn") {
Expand Down
Loading
Loading