Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebKit upgrade #12246

Merged
merged 54 commits into from
Jul 2, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
3c9719c
Replace ZigString.toValue, ZigString.toValueAuto, ZigString.toValueGC…
Jarred-Sumner Jun 29, 2024
880b394
Update bindings.zig
Jarred-Sumner Jun 29, 2024
6b012ab
Update bindings.zig
Jarred-Sumner Jun 29, 2024
a1d49f9
WIP
Jarred-Sumner Jun 29, 2024
30288e3
so many changes
Jarred-Sumner Jun 29, 2024
7d2ab05
Almost odne
Jarred-Sumner Jun 29, 2024
dd53d29
alright it ocmpiled
Jarred-Sumner Jun 29, 2024
9f6d785
Fixup
Jarred-Sumner Jun 29, 2024
9ee7b3b
Bump
Jarred-Sumner Jun 29, 2024
44f8330
wip
Jarred-Sumner Jun 29, 2024
44ae3bb
Merge branch 'main' into jarred/zig-upgrade
Jarred-Sumner Jun 29, 2024
8b45d0d
Apply formatting changes
Jarred-Sumner Jun 29, 2024
43f416b
Update CMakeLists.txt
Jarred-Sumner Jun 29, 2024
352a15f
Bump
Jarred-Sumner Jun 30, 2024
cd71b5b
Apply formatting changes
Jarred-Sumner Jun 30, 2024
84d2380
Redo Asymmetric matchers
Jarred-Sumner Jun 30, 2024
4fdf03e
Add `bun run zig-check-windows` to check if windows passes sema
Jarred-Sumner Jun 30, 2024
01e423f
Mark more JSC.conv
Jarred-Sumner Jun 30, 2024
d744ce1
wrap everything
Jarred-Sumner Jun 30, 2024
368ccde
more
Jarred-Sumner Jun 30, 2024
074c84a
more conv
Jarred-Sumner Jun 30, 2024
72c933c
Update BunObject+exports.h
Jarred-Sumner Jun 30, 2024
6f0d912
Update base.zig
Jarred-Sumner Jun 30, 2024
d5419f9
move some files
Jarred-Sumner Jun 30, 2024
fa1c315
wip
Jarred-Sumner Jun 30, 2024
6461c4b
wip
Jarred-Sumner Jun 30, 2024
ab6601e
Move path into its own file
Jarred-Sumner Jun 30, 2024
697e9b7
It successfully compiled on Windows!
Jarred-Sumner Jun 30, 2024
e877d2d
wip
Jarred-Sumner Jul 1, 2024
53e3ce0
hm
Jarred-Sumner Jul 1, 2024
bed7243
wip
Jarred-Sumner Jul 1, 2024
1897e0f
Cmake
Jarred-Sumner Jul 1, 2024
0c7bfd4
Remove flag
Jarred-Sumner Jul 1, 2024
08c4b4e
cmake
Jarred-Sumner Jul 1, 2024
bf5872d
Some fixes
Jarred-Sumner Jul 1, 2024
59724ef
Update
Jarred-Sumner Jul 1, 2024
e003a90
Apply formatting changes
Jarred-Sumner Jul 1, 2024
fb9f7a5
Deflake fetch-gzip test on Windows
Jarred-Sumner Jul 1, 2024
5ddd623
Fix various things
Jarred-Sumner Jul 1, 2024
47e40f3
bump
Jarred-Sumner Jul 1, 2024
7aa72a7
Apply formatting changes
Jarred-Sumner Jul 1, 2024
05e3b9a
Remove the callconvs in most cases
Jarred-Sumner Jul 1, 2024
bfde2af
lots
Jarred-Sumner Jul 1, 2024
ed382e5
many
Jarred-Sumner Jul 1, 2024
3576965
Fix more tests
Jarred-Sumner Jul 1, 2024
e6cd552
increase timeout
Jarred-Sumner Jul 1, 2024
05e1f77
Get FFI to work again
Jarred-Sumner Jul 1, 2024
42f1fc3
Prettier logs
Jarred-Sumner Jul 2, 2024
89747d4
Fix rare race condition when starting HTTP thread
Jarred-Sumner Jul 2, 2024
3f8597b
Fix rare race condition when calling `Bun.file().{text,arrayBuffer,*}()`
Jarred-Sumner Jul 2, 2024
78bbf5b
Attempt to workaround https://github.com/ziglang/zig/issues/20472
Jarred-Sumner Jul 2, 2024
71ec236
Remove unnecessary callconv usages
Jarred-Sumner Jul 2, 2024
ec426f7
fixups
Jarred-Sumner Jul 2, 2024
3172062
1 more
Jarred-Sumner Jul 2, 2024
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
Prev Previous commit
Next Next commit
Redo Asymmetric matchers
  • Loading branch information
Jarred-Sumner committed Jun 30, 2024
commit 84d2380da74069801e15025ac563a38019362800
212 changes: 169 additions & 43 deletions src/bun.js/bindings/bindings.cpp
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
#include "root.h"

#include "JavaScriptCore/JSCast.h"
#include "JavaScriptCore/JSType.h"
#include "JavaScriptCore/NumberObject.h"
#include "JavaScriptCore/JSCJSValue.h"
#include "JavaScriptCore/JSGlobalObject.h"
#include "JavaScriptCore/JSPromiseConstructor.h"
#include "JavaScriptCore/DeleteAllCodeEffort.h"

#include "JavaScriptCore/BooleanObject.h"
#include "headers.h"

#include "BunClientData.h"
Expand Down Expand Up @@ -195,7 +198,6 @@ static constexpr int FLAG_NOT = (1 << 2);

#pragma clang diagnostic pop

extern "C" bool Expect_readFlagsAndProcessPromise(JSC__JSValue instanceValue, JSC__JSGlobalObject* globalObject, ExpectFlags* flags, JSC__JSValue* value);
extern "C" bool ExpectCustomAsymmetricMatcher__execute(void* self, JSC__JSValue thisValue, JSC__JSGlobalObject* globalObject, JSC__JSValue leftValue);

enum class AsymmetricMatcherResult : uint8_t {
Expand All @@ -204,10 +206,85 @@ enum class AsymmetricMatcherResult : uint8_t {
NOT_MATCHER,
};

bool readFlagsAndProcessPromise(JSValue& instanceValue, ExpectFlags& flags, JSGlobalObject* globalObject, JSValue& value)
enum class AsymmetricMatcherConstructorType : uint8_t {
none = 0,
Symbol = 1,
String = 2,
Object = 3,
Array = 4,
BigInt = 5,
Boolean = 6,
Number = 7,
Promise = 8,
InstanceOf = 9,
};

extern "C" bool Expect_readFlagsAndProcessPromise(JSC__JSValue instanceValue, JSC__JSGlobalObject* globalObject, ExpectFlags* flags, JSC__JSValue* value, AsymmetricMatcherConstructorType* constructorType);

extern "C" uint8_t AsymmetricMatcherConstructorType__fromJS(JSC__JSGlobalObject* globalObject, JSC__JSValue encodedValue)
{
JSValue value = JSValue::decode(encodedValue);
if (value.isObject()) {
JSObject* object = value.getObject();
JSC::VM& vm = globalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
if (globalObject->numberObjectConstructor() == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::Number);
}

if (globalObject->booleanObjectConstructor() == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::Boolean);
}

auto stringConstructorValue = globalObject->stringPrototype()->getIfPropertyExists(globalObject, vm.propertyNames->constructor);
RETURN_IF_EXCEPTION(scope, static_cast<uint8_t>(AsymmetricMatcherConstructorType::none));

if (stringConstructorValue == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::String);
}

auto symbolConstructorValue = globalObject->symbolPrototype()->getIfPropertyExists(globalObject, vm.propertyNames->constructor);
RETURN_IF_EXCEPTION(scope, static_cast<uint8_t>(AsymmetricMatcherConstructorType::none));

if (symbolConstructorValue == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::Symbol);
}

auto bigIntConstructorValue = globalObject->bigIntPrototype()->getIfPropertyExists(globalObject, vm.propertyNames->constructor);
RETURN_IF_EXCEPTION(scope, static_cast<uint8_t>(AsymmetricMatcherConstructorType::none));

if (bigIntConstructorValue == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::BigInt);
}

JSObject* promiseConstructor = globalObject->promiseConstructor();

if (promiseConstructor == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::Promise);
}

JSObject* array = globalObject->arrayConstructor();

if (array == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::Array);
}

JSObject* obj = globalObject->objectConstructor();

if (obj == object) {
return static_cast<uint8_t>(AsymmetricMatcherConstructorType::Object);
}

return static_cast<uint8_t>(AsymmetricMatcherConstructorType::InstanceOf);
}

return static_cast<uint8_t>(AsymmetricMatcherConstructorType::none);
}

bool readFlagsAndProcessPromise(JSValue& instanceValue, ExpectFlags& flags, JSGlobalObject* globalObject, JSValue& value, AsymmetricMatcherConstructorType& constructorType)
{
JSC::EncodedJSValue valueEncoded = JSValue::encode(value);
if (Expect_readFlagsAndProcessPromise(JSValue::encode(instanceValue), globalObject, &flags, &valueEncoded)) {
if (Expect_readFlagsAndProcessPromise(JSValue::encode(instanceValue), globalObject, &flags, &valueEncoded, &constructorType)) {
value = JSValue::decode(valueEncoded);
return true;
}
Expand All @@ -216,11 +293,11 @@ bool readFlagsAndProcessPromise(JSValue& instanceValue, ExpectFlags& flags, JSGl

AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* globalObject, JSValue matcherProp, JSValue otherProp, ThrowScope* throwScope, ExpectFlags& flags)
{
VM& vm = globalObject->vm();
JSCell* matcherPropCell = matcherProp.asCell();
AsymmetricMatcherConstructorType constructorType = AsymmetricMatcherConstructorType::none;

if (auto* expectAnything = jsDynamicCast<JSExpectAnything*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

if (otherProp.isUndefinedOrNull()) {
Expand All @@ -229,46 +306,95 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global

return AsymmetricMatcherResult::PASS;
} else if (auto* expectAny = jsDynamicCast<JSExpectAny*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

JSValue constructorValue = expectAny->m_constructorValue.get();
JSObject* constructorObject = constructorValue.getObject();

if (otherProp.isPrimitive()) {
if (otherProp.isNumber() && globalObject->numberObjectConstructor() == constructorObject) {
switch (constructorType) {
case AsymmetricMatcherConstructorType::Symbol: {
if (otherProp.isSymbol()) {
return AsymmetricMatcherResult::PASS;
} else if (otherProp.isBoolean() && globalObject->booleanObjectConstructor() == constructorObject) {
return AsymmetricMatcherResult::PASS;
} else if (otherProp.isSymbol() && globalObject->symbolObjectStructure() == constructorObject->structure()) {
return AsymmetricMatcherResult::PASS;
} else if (otherProp.isString()) {
if (auto* constructorFunction = jsDynamicCast<JSFunction*>(constructorObject)) {
String name = constructorFunction->name(vm);
if (name == "String"_s) {
return AsymmetricMatcherResult::PASS;
}
} else if (auto* internalConstructorFunction = jsDynamicCast<InternalFunction*>(constructorObject)) {
String name = internalConstructorFunction->name();
if (name == "String"_s) {
return AsymmetricMatcherResult::PASS;
}
}
break;
}
case AsymmetricMatcherConstructorType::String: {
if (otherProp.isCell()) {
JSCell* cell = otherProp.asCell();
switch (cell->type()) {
case JSC::StringType:
case JSC::StringObjectType:
case JSC::DerivedStringObjectType: {
return AsymmetricMatcherResult::PASS;
}
default: {
break;
}
} else if (otherProp.isBigInt()) {
if (auto* constructorFunction = jsDynamicCast<JSFunction*>(constructorObject)) {
String name = constructorFunction->name(vm);
if (name == "BigInt"_s) {
return AsymmetricMatcherResult::PASS;
}
} else if (auto* internalConstructorFunction = jsDynamicCast<InternalFunction*>(constructorObject)) {
String name = internalConstructorFunction->name();
if (name == "BigInt"_s) {
return AsymmetricMatcherResult::PASS;
}
}
}
break;
}

return AsymmetricMatcherResult::FAIL;
case AsymmetricMatcherConstructorType::BigInt: {
if (otherProp.isBigInt()) {
return AsymmetricMatcherResult::PASS;
}
break;
}

case AsymmetricMatcherConstructorType::Boolean: {
if (otherProp.isBoolean()) {
return AsymmetricMatcherResult::PASS;
}

if (auto* booleanObject = jsDynamicCast<BooleanObject*>(otherProp)) {
return AsymmetricMatcherResult::PASS;
}

break;
}

case AsymmetricMatcherConstructorType::Number: {
if (otherProp.isNumber()) {
return AsymmetricMatcherResult::PASS;
}

if (auto* numberObject = jsDynamicCast<NumberObject*>(otherProp)) {
return AsymmetricMatcherResult::PASS;
}

break;
}

case AsymmetricMatcherConstructorType::Promise: {
if (otherProp.isCell() && otherProp.asCell()->type() == JSPromiseType) {
return AsymmetricMatcherResult::PASS;
}
break;
}

case AsymmetricMatcherConstructorType::Array: {
if (JSC::isArray(globalObject, otherProp)) {
return AsymmetricMatcherResult::PASS;
}
break;
}

case AsymmetricMatcherConstructorType::Object: {
if (otherProp.isObject()) {
return AsymmetricMatcherResult::PASS;
}
break;
}

case AsymmetricMatcherConstructorType::InstanceOf: {
break;
}
case AsymmetricMatcherConstructorType::none: {
ASSERT_NOT_REACHED_WITH_MESSAGE("Invalid constructor type");
break;
}
}

if (constructorObject->hasInstance(globalObject, otherProp)) {
Expand All @@ -277,7 +403,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global

return AsymmetricMatcherResult::FAIL;
} else if (auto* expectStringContaining = jsDynamicCast<JSExpectStringContaining*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

JSValue expectedSubstring = expectStringContaining->m_stringValue.get();
Expand All @@ -296,7 +422,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global

return AsymmetricMatcherResult::FAIL;
} else if (auto* expectStringMatching = jsDynamicCast<JSExpectStringMatching*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

JSValue expectedTestValue = expectStringMatching->m_testValue.get();
Expand Down Expand Up @@ -324,7 +450,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global

return AsymmetricMatcherResult::FAIL;
} else if (auto* expectArrayContaining = jsDynamicCast<JSExpectArrayContaining*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

JSValue expectedArrayValue = expectArrayContaining->m_arrayValue.get();
Expand Down Expand Up @@ -369,7 +495,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global

return AsymmetricMatcherResult::FAIL;
} else if (auto* expectObjectContaining = jsDynamicCast<JSExpectObjectContaining*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

JSValue patternObject = expectObjectContaining->m_objectValue.get();
Expand All @@ -384,7 +510,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global

return AsymmetricMatcherResult::FAIL;
} else if (auto* expectCloseTo = jsDynamicCast<JSExpectCloseTo*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

if (!otherProp.isNumber()) {
Expand Down Expand Up @@ -412,7 +538,7 @@ AsymmetricMatcherResult matchAsymmetricMatcherAndGetFlags(JSGlobalObject* global
return isClose ? AsymmetricMatcherResult::PASS : AsymmetricMatcherResult::FAIL;
}
} else if (auto* customMatcher = jsDynamicCast<JSExpectCustomAsymmetricMatcher*>(matcherPropCell)) {
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp))
if (!readFlagsAndProcessPromise(matcherProp, flags, globalObject, otherProp, constructorType))
return AsymmetricMatcherResult::FAIL;

// ignore the "not" flag here, because the custom matchers handle it themselves (accessing this.isNot)
Expand Down
38 changes: 35 additions & 3 deletions src/bun.js/test/expect.zig
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,27 @@ pub const Expect = struct {

not: bool = false,

_: u5 = undefined, // padding
// This was originally padding.
// We don't use all the bits in the u5, so if you need to reuse this elsewhere, you could.
asymmetric_matcher_constructor_type: AsymmetricMatcherConstructorType = .none,

pub const AsymmetricMatcherConstructorType = enum(u5) {
none = 0,
Symbol = 1,
String = 2,
Object = 3,
Array = 4,
BigInt = 5,
Boolean = 6,
Number = 7,
Promise = 8,
InstanceOf = 9,

extern fn AsymmetricMatcherConstructorType__fromJS(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) u8;
pub fn fromJS(globalObject: *JSC.JSGlobalObject, value: JSC.JSValue) AsymmetricMatcherConstructorType {
return @enumFromInt(AsymmetricMatcherConstructorType__fromJS(globalObject, value));
}
};

pub const FlagsCppType = u8;
comptime {
Expand Down Expand Up @@ -247,11 +267,12 @@ pub const Expect = struct {
}

/// Called by C++ when matching with asymmetric matchers
fn readFlagsAndProcessPromise(instanceValue: JSValue, globalThis: *JSGlobalObject, outFlags: *Expect.Flags.FlagsCppType, value: *JSValue) callconv(.C) bool {
fn readFlagsAndProcessPromise(instanceValue: JSValue, globalThis: *JSGlobalObject, outFlags: *Expect.Flags.FlagsCppType, value: *JSValue, any_constructor_type: *u8) callconv(.C) bool {
const flags: Expect.Flags = flags: {
if (ExpectCustomAsymmetricMatcher.fromJS(instanceValue)) |instance| {
break :flags instance.flags;
} else if (ExpectAny.fromJS(instanceValue)) |instance| {
any_constructor_type.* = @intFromEnum(instance.flags.asymmetric_matcher_constructor_type);
break :flags instance.flags;
} else if (ExpectAnything.fromJS(instanceValue)) |instance| {
break :flags instance.flags;
Expand Down Expand Up @@ -5159,11 +5180,22 @@ pub const ExpectAny = struct {
return .zero;
}

const asymmetric_matcher_constructor_type = Expect.Flags.AsymmetricMatcherConstructorType.fromJS(globalThis, constructor);

// I don't think this case is possible, but just in case!
if (globalThis.hasException()) {
return .zero;
}

var any = globalThis.bunVM().allocator.create(ExpectAny) catch {
globalThis.throwOutOfMemory();
return .zero;
};
any.* = .{};
any.* = .{
.flags = .{
.asymmetric_matcher_constructor_type = asymmetric_matcher_constructor_type,
},
};

const any_js_value = any.toJS(globalThis);
any_js_value.ensureStillAlive();
Expand Down
Loading