Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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