5540fbfce5
This is a reland of 6124a534b2
It fixes a UAF issue in the d8 test by moving the test API object
constructor to PerIsolateData. It also fixes a crash in Chromium
caused by current usage of v8::ApiObject, which should be migrated
to v8::Value*.
Original change's description:
> [fastcall] Add support for leaf interface type checks
>
> This CL adds an IsTemplateForApiObject method to FunctionTemplate
> allowing the embedder to check whether a given API object was
> instantiated by this template without including parent templates
> in the search. It also replaces the v8::ApiObject in the fast API
> with a raw v8::Value pointer to allow use of standard C++ casts.
>
> Bug: chromium:1052746
> Change-Id: I0812ec8b4daaa5f5005aabf10b63e1e84e0b8f03
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2595310
> Commit-Queue: Maya Lekova <mslekova@chromium.org>
> Reviewed-by: Georg Neis <neis@chromium.org>
> Reviewed-by: Camillo Bruni <cbruni@chromium.org>
> Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#73999}
Bug: chromium:1052746, chromium:1199900
Change-Id: I4b7f0c9e9152919dde4a1d0c48fbf5ac8c5b13d8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2835711
Reviewed-by: Georg Neis <neis@chromium.org>
Reviewed-by: Sathya Gunasekaran <gsathya@chromium.org>
Reviewed-by: Camillo Bruni <cbruni@chromium.org>
Commit-Queue: Maya Lekova <mslekova@chromium.org>
Cr-Commit-Position: refs/heads/master@{#74064}
181 lines
6.7 KiB
JavaScript
181 lines
6.7 KiB
JavaScript
// Copyright 2021 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 --allow-natives-syntax --opt
|
|
// --always-opt is disabled because we rely on particular feedback for
|
|
// optimizing to the fastest path.
|
|
// Flags: --no-always-opt
|
|
// 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();
|
|
|
|
// ----------- add_all -----------
|
|
// `add_all` has the following signature:
|
|
// double add_all(bool /*should_fallback*/, int32_t, uint32_t,
|
|
// int64_t, uint64_t, float, double)
|
|
|
|
const max_safe_float = 2**24 - 1;
|
|
const add_all_result = -42 + 45 + Number.MIN_SAFE_INTEGER + Number.MAX_SAFE_INTEGER +
|
|
max_safe_float * 0.5 + Math.PI;
|
|
|
|
function add_all(should_fallback = false) {
|
|
return fast_c_api.add_all(should_fallback,
|
|
-42, 45, Number.MIN_SAFE_INTEGER, Number.MAX_SAFE_INTEGER,
|
|
max_safe_float * 0.5, Math.PI);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(add_all);
|
|
assertEquals(add_all_result, add_all());
|
|
%OptimizeFunctionOnNextCall(add_all);
|
|
|
|
if (fast_c_api.supports_fp_params) {
|
|
// Test that regular call hits the fast path.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_all_result, add_all());
|
|
assertOptimized(add_all);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(0, fast_c_api.slow_call_count());
|
|
|
|
// Test fallback to slow path.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_all_result, add_all(true));
|
|
assertOptimized(add_all);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(1, fast_c_api.slow_call_count());
|
|
|
|
// Test that no fallback hits the fast path again.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_all_result, add_all());
|
|
assertOptimized(add_all);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(0, fast_c_api.slow_call_count());
|
|
} else {
|
|
// Test that calling with unsupported types hits the slow path.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_all_result, add_all());
|
|
assertOptimized(add_all);
|
|
assertEquals(0, fast_c_api.fast_call_count());
|
|
assertEquals(1, fast_c_api.slow_call_count());
|
|
}
|
|
|
|
// ----------- Test add_all signature mismatche -----------
|
|
function add_all_mismatch() {
|
|
return fast_c_api.add_all(false /*should_fallback*/,
|
|
45, -42, Number.MAX_SAFE_INTEGER, max_safe_float * 0.5,
|
|
Number.MIN_SAFE_INTEGER, Math.PI);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(add_all_mismatch);
|
|
const add_all_mismatch_result = add_all_mismatch();
|
|
%OptimizeFunctionOnNextCall(add_all_mismatch);
|
|
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_all_mismatch_result, add_all_mismatch());
|
|
// If the function was ever optimized to the fast path, it should
|
|
// have been deoptimized due to the argument types mismatch. If it
|
|
// wasn't optimized due to lack of support for FP params, it will
|
|
// stay optimized.
|
|
if (fast_c_api.supports_fp_params) {
|
|
assertUnoptimized(add_all_mismatch);
|
|
} else {
|
|
assertOptimized(add_all_mismatch);
|
|
}
|
|
assertEquals(0, fast_c_api.fast_call_count());
|
|
assertEquals(1, fast_c_api.slow_call_count());
|
|
|
|
// ----------- add_32bit_int -----------
|
|
// `add_32bit_int` has the following signature:
|
|
// int add_32bit_int(bool /*should_fallback*/, int32_t, uint32_t)
|
|
|
|
const add_32bit_int_result = -42 + 45;
|
|
|
|
function add_32bit_int(should_fallback = false) {
|
|
return fast_c_api.add_32bit_int(should_fallback, -42, 45);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(add_32bit_int);
|
|
assertEquals(add_32bit_int_result, add_32bit_int());
|
|
%OptimizeFunctionOnNextCall(add_32bit_int);
|
|
|
|
// Test that regular call hits the fast path.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_32bit_int_result, add_32bit_int());
|
|
assertOptimized(add_32bit_int);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(0, fast_c_api.slow_call_count());
|
|
|
|
// Test fallback to slow path.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_32bit_int_result, add_32bit_int(true));
|
|
assertOptimized(add_32bit_int);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(1, fast_c_api.slow_call_count());
|
|
|
|
// Test that no fallback hits the fast path again.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_32bit_int_result, add_32bit_int());
|
|
assertOptimized(add_32bit_int);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(0, fast_c_api.slow_call_count());
|
|
|
|
// ----------- Test various signature mismatches -----------
|
|
function add_32bit_int_mismatch(arg0, arg1, arg2, arg3) {
|
|
return fast_c_api.add_32bit_int(arg0, arg1, arg2, arg3);
|
|
}
|
|
|
|
%PrepareFunctionForOptimization(add_32bit_int_mismatch);
|
|
assertEquals(add_32bit_int_result, add_32bit_int_mismatch(false, -42, 45));
|
|
%OptimizeFunctionOnNextCall(add_32bit_int_mismatch);
|
|
|
|
// Test that passing extra argument stays on the fast path.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_32bit_int_result, add_32bit_int_mismatch(false, -42, 45, -42));
|
|
assertOptimized(add_32bit_int_mismatch);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(0, fast_c_api.slow_call_count());
|
|
%PrepareFunctionForOptimization(add_32bit_int_mismatch);
|
|
|
|
// Test that passing wrong argument types stays on the fast path.
|
|
fast_c_api.reset_counts();
|
|
let mismatch_result = add_32bit_int_mismatch(false, -42, 3.14);
|
|
assertOptimized(add_32bit_int_mismatch);
|
|
assertEquals(Math.round(-42 + 3.14), mismatch_result);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(0, fast_c_api.slow_call_count());
|
|
|
|
// Test that passing arguments non-convertible to number falls down the slow path.
|
|
fast_c_api.reset_counts();
|
|
assertEquals(0, add_32bit_int_mismatch(false, -4294967296, Symbol()));
|
|
assertUnoptimized(add_32bit_int_mismatch);
|
|
assertEquals(0, fast_c_api.fast_call_count());
|
|
assertEquals(1, fast_c_api.slow_call_count());
|
|
|
|
// Optimize again.
|
|
%OptimizeFunctionOnNextCall(add_32bit_int_mismatch);
|
|
assertEquals(add_32bit_int_result, add_32bit_int_mismatch(false, -42, 45));
|
|
assertOptimized(add_32bit_int_mismatch);
|
|
|
|
// Test that passing too few argument falls down the slow path,
|
|
// because it's an argument type mismatch (undefined vs. int).
|
|
fast_c_api.reset_counts();
|
|
assertEquals(-42, add_32bit_int_mismatch(false, -42));
|
|
assertUnoptimized(add_32bit_int_mismatch);
|
|
assertEquals(0, fast_c_api.fast_call_count());
|
|
assertEquals(1, fast_c_api.slow_call_count());
|
|
|
|
// Test that the function can be optimized again.
|
|
%PrepareFunctionForOptimization(add_32bit_int_mismatch);
|
|
%OptimizeFunctionOnNextCall(add_32bit_int_mismatch);
|
|
fast_c_api.reset_counts();
|
|
assertEquals(add_32bit_int_result, add_32bit_int_mismatch(false, -42, 45));
|
|
assertOptimized(add_32bit_int_mismatch);
|
|
assertEquals(1, fast_c_api.fast_call_count());
|
|
assertEquals(0, fast_c_api.slow_call_count());
|