8d5630c7d6
Bug: chromium:1395617, chromium:1395521 Change-Id: I23355e14c879532c699084fff7d9d1fcf6489941 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/4075578 Commit-Queue: Maya Lekova <mslekova@chromium.org> Reviewed-by: Camillo Bruni <cbruni@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/main@{#84677}
141 lines
5.1 KiB
JavaScript
141 lines
5.1 KiB
JavaScript
// Copyright 2022 the V8 project authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
// This file excercises basic fast API calls and enables fuzzing of this
|
|
// functionality.
|
|
|
|
// Flags: --turbo-fast-api-calls --expose-fast-api --allow-natives-syntax --turbofan
|
|
// --always-turbofan is disabled because we rely on particular feedback for
|
|
// optimizing to the fastest path.
|
|
// Flags: --no-always-turbofan
|
|
// The test relies on optimizing/deoptimizing at predictable moments, so
|
|
// it's not suitable for deoptimization fuzzing.
|
|
// Flags: --deopt-every-n-times=0
|
|
|
|
assertThrows(() => d8.test.FastCAPI());
|
|
const fast_c_api = new d8.test.FastCAPI();
|
|
|
|
// ---------- Test external pointer passing -----------
|
|
|
|
function reset_counts() {
|
|
return fast_c_api.reset_counts();
|
|
}
|
|
|
|
function fast_call_count() {
|
|
return fast_c_api.fast_call_count();
|
|
}
|
|
|
|
function slow_call_count() {
|
|
return fast_c_api.slow_call_count();
|
|
}
|
|
|
|
function assertIsExternal(pointer) {
|
|
return fast_c_api.assert_is_external(pointer);
|
|
}
|
|
|
|
function get_pointer_a() {
|
|
return fast_c_api.get_pointer();
|
|
}
|
|
|
|
function get_pointer_b() {
|
|
return fast_c_api.get_null_pointer();
|
|
}
|
|
|
|
function pass_pointer(pointer) {
|
|
return fast_c_api.pass_pointer(pointer);
|
|
}
|
|
|
|
function compare_pointers(pointer_a, pointer_b) {
|
|
return fast_c_api.compare_pointers(pointer_a, pointer_b);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(get_pointer_a);
|
|
reset_counts();
|
|
const external_a_slow = get_pointer_a();
|
|
const external_a_slow_clone = get_pointer_a();
|
|
assertEquals(slow_call_count(), 2);
|
|
assertEquals(fast_call_count(), 0);
|
|
assertIsExternal(external_a_slow);
|
|
assertIsExternal(external_a_slow_clone);
|
|
|
|
// Slow call that returns the same pointer from a new `External::New()`
|
|
// will still create a new / different object.
|
|
// Note that we cannot use `assertEquals(external_a_slow, external_a_slow_clone)`
|
|
// as it's a deep equality comparison and will return true for all empty object comparsions.
|
|
assertFalse(external_a_slow === external_a_slow_clone);
|
|
|
|
%PrepareFunctionForOptimization(pass_pointer);
|
|
reset_counts();
|
|
const external_a_slow_passed = pass_pointer(external_a_slow);
|
|
// If slow call returns the same External object, then object identity is
|
|
// preserved.
|
|
assertEquals(slow_call_count(), 1);
|
|
assertEquals(fast_call_count(), 0);
|
|
assertTrue(external_a_slow_passed === external_a_slow, true);
|
|
%OptimizeFunctionOnNextCall(pass_pointer);
|
|
const external_a_fast_passed = pass_pointer(external_a_slow);
|
|
assertEquals(slow_call_count(), 1);
|
|
assertEquals(fast_call_count(), 1);
|
|
assertIsExternal(external_a_slow);
|
|
assertIsExternal(external_a_fast_passed);
|
|
// Fast call always creates a new External object, as they cannot
|
|
// return the same External object given that they do not see it.
|
|
assertFalse(external_a_fast_passed === external_a_slow);
|
|
|
|
// An object that looks like an External is still not an External.
|
|
const emptyObject = Object.create(null);
|
|
// An object that internally carries a pointer is still not an External.
|
|
const alsoInternallyPointer = new Uint8Array();
|
|
assertThrows(() => pass_pointer(emptyObject));
|
|
assertThrows(() => pass_pointer(alsoInternallyPointer));
|
|
|
|
// Show off deep equality comparsions between various External objects and
|
|
// the empty object to show that all Externals work properly as objects.
|
|
assertEquals(external_a_slow, external_a_fast_passed);
|
|
assertEquals(external_a_fast_passed, emptyObject);
|
|
|
|
%OptimizeFunctionOnNextCall(get_pointer_a);
|
|
reset_counts();
|
|
const external_a_fast = get_pointer_a();
|
|
assertEquals(slow_call_count(), 0);
|
|
assertEquals(fast_call_count(), 1);
|
|
assertIsExternal(external_a_fast);
|
|
assertFalse(external_a_fast === external_a_slow);
|
|
|
|
%PrepareFunctionForOptimization(get_pointer_b);
|
|
fast_c_api.reset_counts();
|
|
const external_b_slow = get_pointer_b();
|
|
assertEquals(slow_call_count(), 1);
|
|
assertEquals(fast_call_count(), 0);
|
|
assertEquals(external_b_slow, null);
|
|
%OptimizeFunctionOnNextCall(get_pointer_b);
|
|
const external_b_fast = get_pointer_b();
|
|
assertEquals(slow_call_count(), 1);
|
|
assertEquals(fast_call_count(), 1);
|
|
assertEquals(external_b_fast, null);
|
|
|
|
const external_b_fast_passed = pass_pointer(external_b_slow);
|
|
assertEquals(external_b_fast_passed, null);
|
|
assertTrue(external_b_fast_passed === external_b_slow, true);
|
|
|
|
%PrepareFunctionForOptimization(compare_pointers);
|
|
assertUnoptimized(compare_pointers);
|
|
reset_counts();
|
|
assertFalse(compare_pointers(external_a_slow, external_b_slow));
|
|
assertEquals(slow_call_count(), 1);
|
|
assertEquals(fast_call_count(), 0);
|
|
%OptimizeFunctionOnNextCall(compare_pointers);
|
|
assertFalse(compare_pointers(external_a_slow, external_b_slow));
|
|
assertEquals(slow_call_count(), 1);
|
|
assertEquals(fast_call_count(), 1);
|
|
assertTrue(compare_pointers(external_a_slow, external_a_slow), true);
|
|
assertTrue(compare_pointers(external_a_slow, external_a_fast), true);
|
|
assertTrue(compare_pointers(external_b_slow, external_b_slow), true);
|
|
assertTrue(compare_pointers(external_b_slow, external_b_fast), true);
|
|
assertTrue(compare_pointers(external_b_slow, external_b_fast_passed), true);
|
|
|
|
// Assert that the ComparePointers call can safely be called with non-Externals
|
|
// and that it will throw an error instead of crashing.
|
|
assertThrows(() => compare_pointers(123, "foo"));
|