Commit 1617f242 authored by Feng Yu's avatar Feng Yu Committed by V8 LUCI CQ

[test] Migrate cctest/test-run-deopt to unittests/

Bug: v8:12781
Change-Id: I649318b653d62ba484d6b2d96ee66e8fb30ad6b5
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3829324Reviewed-by: 's avatarCamillo Bruni <cbruni@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/main@{#82645}
parent 0389c613
......@@ -118,7 +118,6 @@ v8_source_set("cctest_sources") {
"compiler/test-representation-change.cc",
"compiler/test-run-bytecode-graph-builder.cc",
"compiler/test-run-calls-to-external-references.cc",
"compiler/test-run-deopt.cc",
"compiler/test-run-jsbranches.cc",
"compiler/test-run-jscalls.cc",
"compiler/test-run-jsexceptions.cc",
......
// Copyright 2014 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.
#include "include/v8-function.h"
#include "src/execution/frames-inl.h"
#include "test/cctest/cctest.h"
#include "test/cctest/compiler/function-tester.h"
namespace v8 {
namespace internal {
namespace compiler {
static void IsOptimized(const v8::FunctionCallbackInfo<v8::Value>& args) {
JavaScriptFrameIterator it(CcTest::i_isolate());
JavaScriptFrame* frame = it.frame();
return args.GetReturnValue().Set(frame->is_turbofan());
}
static void InstallIsOptimizedHelper(v8::Isolate* isolate) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::FunctionTemplate> t =
v8::FunctionTemplate::New(isolate, IsOptimized);
CHECK(context->Global()
->Set(context, v8_str("IsOptimized"),
t->GetFunction(context).ToLocalChecked())
.FromJust());
}
TEST(DeoptSimple) {
FLAG_allow_natives_syntax = true;
FunctionTester T(
"(function f(a) {"
" var b = 1;"
" if (!IsOptimized()) return 0;"
" %DeoptimizeFunction(f);"
" if (IsOptimized()) return 0;"
" return a + b;"
"})");
InstallIsOptimizedHelper(CcTest::isolate());
T.CheckCall(T.Val(2), T.Val(1));
}
TEST(DeoptSimpleInExpr) {
FLAG_allow_natives_syntax = true;
FunctionTester T(
"(function f(a) {"
" var b = 1;"
" var c = 2;"
" if (!IsOptimized()) return 0;"
" var d = b + (%DeoptimizeFunction(f), c);"
" if (IsOptimized()) return 0;"
" return d + a;"
"})");
InstallIsOptimizedHelper(CcTest::isolate());
T.CheckCall(T.Val(6), T.Val(3));
}
TEST(DeoptExceptionHandlerCatch) {
FLAG_allow_natives_syntax = true;
FunctionTester T(
"(function f() {"
" var is_opt = IsOptimized;"
" try {"
" DeoptAndThrow(f);"
" } catch (e) {"
" return is_opt();"
" }"
"})");
CompileRun("function DeoptAndThrow(f) { %DeoptimizeFunction(f); throw 0; }");
InstallIsOptimizedHelper(CcTest::isolate());
T.CheckCall(T.false_value());
}
TEST(DeoptExceptionHandlerFinally) {
FLAG_allow_natives_syntax = true;
FunctionTester T(
"(function f() {"
" var is_opt = IsOptimized;"
" try {"
" DeoptAndThrow(f);"
" } finally {"
" return is_opt();"
" }"
"})");
CompileRun("function DeoptAndThrow(f) { %DeoptimizeFunction(f); throw 0; }");
InstallIsOptimizedHelper(CcTest::isolate());
T.CheckCall(T.false_value());
}
TEST(DeoptTrivial) {
FLAG_allow_natives_syntax = true;
FunctionTester T(
"(function foo() {"
" %DeoptimizeFunction(foo);"
" return 1;"
"})");
T.CheckCall(T.Val(1));
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -308,6 +308,8 @@ v8_source_set("unittests_sources") {
"compiler/diamond-unittest.cc",
"compiler/effect-control-linearizer-unittest.cc",
"compiler/frame-unittest.cc",
"compiler/function-tester.cc",
"compiler/function-tester.h",
"compiler/graph-reducer-unittest.cc",
"compiler/graph-reducer-unittest.h",
"compiler/graph-trimmer-unittest.cc",
......@@ -337,6 +339,7 @@ v8_source_set("unittests_sources") {
"compiler/regalloc/mid-tier-register-allocator-unittest.cc",
"compiler/regalloc/move-optimizer-unittest.cc",
"compiler/regalloc/register-allocator-unittest.cc",
"compiler/run-deopt-unittest.cc",
"compiler/schedule-unittest.cc",
"compiler/scheduler-rpo-unittest.cc",
"compiler/scheduler-unittest.cc",
......
// Copyright 2014 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.
#include "test/unittests/compiler/function-tester.h"
#include "include/v8-function.h"
#include "src/codegen/assembler.h"
#include "src/codegen/compiler.h"
#include "src/codegen/optimized-compilation-info.h"
#include "src/compiler/graph.h"
#include "src/compiler/js-heap-broker.h"
#include "src/compiler/linkage.h"
#include "src/compiler/pipeline.h"
#include "src/execution/execution.h"
#include "src/handles/handles.h"
#include "src/objects/objects-inl.h"
#include "src/parsing/parse-info.h"
namespace v8 {
namespace internal {
namespace compiler {
namespace {
v8::Local<v8::Value> CompileRun(Isolate* isolate, const char* source) {
v8::Isolate* v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
v8::Local<v8::Context> context = v8_isolate->GetCurrentContext();
v8::Local<v8::Script> script =
v8::Script::Compile(
context, v8::String::NewFromUtf8(v8_isolate, source).ToLocalChecked())
.ToLocalChecked();
return script->Run(context).ToLocalChecked();
}
} // namespace
FunctionTester::FunctionTester(Isolate* isolate, const char* source,
uint32_t flags)
: isolate(isolate),
canonical(isolate),
function((FLAG_allow_natives_syntax = true, NewFunction(source))),
flags_(flags) {
Compile(function);
const uint32_t supported_flags = OptimizedCompilationInfo::kInlining;
CHECK_EQ(0u, flags_ & ~supported_flags);
}
FunctionTester::FunctionTester(Isolate* isolate, Graph* graph, int param_count)
: isolate(isolate),
canonical(isolate),
function(NewFunction(BuildFunction(param_count).c_str())),
flags_(0) {
CompileGraph(graph);
}
FunctionTester::FunctionTester(Isolate* isolate, Handle<Code> code,
int param_count)
: isolate(isolate),
canonical(isolate),
function((FLAG_allow_natives_syntax = true,
NewFunction(BuildFunction(param_count).c_str()))),
flags_(0) {
CHECK(!code.is_null());
Compile(function);
function->set_code(ToCodeT(*code), kReleaseStore);
}
FunctionTester::FunctionTester(Isolate* isolate, Handle<Code> code)
: FunctionTester(isolate, code, 0) {}
void FunctionTester::CheckThrows(Handle<Object> a) {
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
MaybeHandle<Object> no_result = Call(a);
CHECK(isolate->has_pending_exception());
CHECK(try_catch.HasCaught());
CHECK(no_result.is_null());
isolate->OptionalRescheduleException(true);
}
void FunctionTester::CheckThrows(Handle<Object> a, Handle<Object> b) {
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
MaybeHandle<Object> no_result = Call(a, b);
CHECK(isolate->has_pending_exception());
CHECK(try_catch.HasCaught());
CHECK(no_result.is_null());
isolate->OptionalRescheduleException(true);
}
v8::Local<v8::Message> FunctionTester::CheckThrowsReturnMessage(
Handle<Object> a, Handle<Object> b) {
TryCatch try_catch(reinterpret_cast<v8::Isolate*>(isolate));
MaybeHandle<Object> no_result = Call(a, b);
CHECK(isolate->has_pending_exception());
CHECK(try_catch.HasCaught());
CHECK(no_result.is_null());
isolate->OptionalRescheduleException(true);
CHECK(!try_catch.Message().IsEmpty());
return try_catch.Message();
}
void FunctionTester::CheckCall(Handle<Object> expected, Handle<Object> a,
Handle<Object> b, Handle<Object> c,
Handle<Object> d) {
Handle<Object> result = Call(a, b, c, d).ToHandleChecked();
CHECK(expected->SameValue(*result));
}
Handle<JSFunction> FunctionTester::NewFunction(const char* source) {
return Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(isolate, source))));
}
Handle<JSObject> FunctionTester::NewObject(const char* source) {
return Handle<JSObject>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Object>::Cast(CompileRun(isolate, source))));
}
Handle<String> FunctionTester::NewString(const char* string) {
return isolate->factory()->InternalizeUtf8String(string);
}
Handle<Object> FunctionTester::NewNumber(double value) {
return isolate->factory()->NewNumber(value);
}
Handle<Object> FunctionTester::infinity() {
return isolate->factory()->infinity_value();
}
Handle<Object> FunctionTester::minus_infinity() {
return NewNumber(-V8_INFINITY);
}
Handle<Object> FunctionTester::nan() { return isolate->factory()->nan_value(); }
Handle<Object> FunctionTester::undefined() {
return isolate->factory()->undefined_value();
}
Handle<Object> FunctionTester::null() {
return isolate->factory()->null_value();
}
Handle<Object> FunctionTester::true_value() {
return isolate->factory()->true_value();
}
Handle<Object> FunctionTester::false_value() {
return isolate->factory()->false_value();
}
Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> f) {
Zone zone(isolate->allocator(), ZONE_NAME);
return Optimize(f, &zone, flags_);
}
// Compile the given machine graph instead of the source of the function
// and replace the JSFunction's code with the result.
Handle<JSFunction> FunctionTester::CompileGraph(Graph* graph) {
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
Zone zone(isolate->allocator(), ZONE_NAME);
OptimizedCompilationInfo info(&zone, isolate, shared, function,
CodeKind::TURBOFAN);
auto call_descriptor = Linkage::ComputeIncoming(&zone, &info);
Handle<Code> code =
Pipeline::GenerateCodeForTesting(&info, isolate, call_descriptor, graph,
AssemblerOptions::Default(isolate))
.ToHandleChecked();
function->set_code(*code, kReleaseStore);
return function;
}
Handle<JSFunction> FunctionTester::Optimize(
Handle<JSFunction> function, Zone* zone, uint32_t flags,
std::unique_ptr<compiler::JSHeapBroker>* out_broker) {
Handle<SharedFunctionInfo> shared(function->shared(), isolate);
IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
CHECK(is_compiled_scope.is_compiled() ||
Compiler::Compile(isolate, function, Compiler::CLEAR_EXCEPTION,
&is_compiled_scope));
CHECK_NOT_NULL(zone);
OptimizedCompilationInfo info(zone, isolate, shared, function,
CodeKind::TURBOFAN);
if (flags & ~OptimizedCompilationInfo::kInlining) UNIMPLEMENTED();
if (flags & OptimizedCompilationInfo::kInlining) {
info.set_inlining();
}
CHECK(info.shared_info()->HasBytecodeArray());
JSFunction::EnsureFeedbackVector(isolate, function, &is_compiled_scope);
Handle<CodeT> code = ToCodeT(
compiler::Pipeline::GenerateCodeForTesting(&info, isolate, out_broker)
.ToHandleChecked(),
isolate);
info.native_context().AddOptimizedCode(*code);
function->set_code(*code, v8::kReleaseStore);
return function;
}
} // namespace compiler
} // namespace internal
} // namespace v8
// Copyright 2014 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.
#ifndef V8_UNITTESTS_COMPILER_FUNCTION_TESTER_H_
#define V8_UNITTESTS_COMPILER_FUNCTION_TESTER_H_
#include "src/compiler/graph.h"
#include "src/compiler/js-heap-broker.h"
#include "src/execution/execution.h"
#include "src/handles/handles.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace compiler {
class FunctionTester {
public:
explicit FunctionTester(Isolate* i_isolate, const char* source,
uint32_t flags = 0);
FunctionTester(Isolate* i_isolate, Graph* graph, int param_count);
FunctionTester(Isolate* i_isolate, Handle<Code> code, int param_count);
// Assumes VoidDescriptor call interface.
explicit FunctionTester(Isolate* i_isolate, Handle<Code> code);
Isolate* isolate;
CanonicalHandleScope canonical;
Handle<JSFunction> function;
MaybeHandle<Object> Call() {
return Execution::Call(isolate, function, undefined(), 0, nullptr);
}
template <typename Arg1, typename... Args>
MaybeHandle<Object> Call(Arg1 arg1, Args... args) {
const int nof_args = sizeof...(Args) + 1;
Handle<Object> call_args[] = {arg1, args...};
return Execution::Call(isolate, function, undefined(), nof_args, call_args);
}
template <typename T, typename... Args>
Handle<T> CallChecked(Args... args) {
Handle<Object> result = Call(args...).ToHandleChecked();
return Handle<T>::cast(result);
}
void CheckThrows(Handle<Object> a);
void CheckThrows(Handle<Object> a, Handle<Object> b);
v8::Local<v8::Message> CheckThrowsReturnMessage(Handle<Object> a,
Handle<Object> b);
void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b,
Handle<Object> c, Handle<Object> d);
void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b,
Handle<Object> c) {
return CheckCall(expected, a, b, c, undefined());
}
void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
return CheckCall(expected, a, b, undefined());
}
void CheckCall(Handle<Object> expected, Handle<Object> a) {
CheckCall(expected, a, undefined());
}
void CheckCall(Handle<Object> expected) { CheckCall(expected, undefined()); }
void CheckCall(double expected, double a, double b) {
CheckCall(NewNumber(expected), NewNumber(a), NewNumber(b));
}
void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a); }
void CheckTrue(Handle<Object> a, Handle<Object> b) {
CheckCall(true_value(), a, b);
}
void CheckTrue(Handle<Object> a, Handle<Object> b, Handle<Object> c) {
CheckCall(true_value(), a, b, c);
}
void CheckTrue(Handle<Object> a, Handle<Object> b, Handle<Object> c,
Handle<Object> d) {
CheckCall(true_value(), a, b, c, d);
}
void CheckTrue(double a, double b) {
CheckCall(true_value(), NewNumber(a), NewNumber(b));
}
void CheckFalse(Handle<Object> a) { CheckCall(false_value(), a); }
void CheckFalse(Handle<Object> a, Handle<Object> b) {
CheckCall(false_value(), a, b);
}
void CheckFalse(double a, double b) {
CheckCall(false_value(), NewNumber(a), NewNumber(b));
}
Handle<JSFunction> NewFunction(const char* source);
Handle<JSObject> NewObject(const char* source);
Handle<String> NewString(const char* string);
Handle<Object> NewNumber(double value);
Handle<Object> infinity();
Handle<Object> minus_infinity();
Handle<Object> nan();
Handle<Object> undefined();
Handle<Object> null();
Handle<Object> true_value();
Handle<Object> false_value();
private:
uint32_t flags_;
Handle<JSFunction> Compile(Handle<JSFunction> function);
std::string BuildFunction(int param_count) {
std::string function_string = "(function(";
if (param_count > 0) {
function_string += 'a';
for (int i = 1; i < param_count; i++) {
function_string += ',';
function_string += static_cast<char>('a' + i);
}
}
function_string += "){})";
return function_string;
}
// Compile the given machine graph instead of the source of the function
// and replace the JSFunction's code with the result.
Handle<JSFunction> CompileGraph(Graph* graph);
// Takes a JSFunction and runs it through the test version of the optimizing
// pipeline, allocating the temporary compilation artifacts in a given Zone.
// For possible {flags} values, look at OptimizedCompilationInfo::Flag. If
// {out_broker} is not nullptr, returns the JSHeapBroker via that
// (transferring ownership to the caller).
Handle<JSFunction> Optimize(
Handle<JSFunction> function, Zone* zone, uint32_t flags,
std::unique_ptr<compiler::JSHeapBroker>* out_broker = nullptr);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_UNITTESTS_COMPILER_FUNCTION_TESTER_H_
// Copyright 2014 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.
#include "include/v8-function.h"
#include "src/execution/frames-inl.h"
#include "test/unittests/compiler/function-tester.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
namespace compiler {
static void IsOptimized(const v8::FunctionCallbackInfo<v8::Value>& args) {
JavaScriptFrameIterator it(reinterpret_cast<Isolate*>(args.GetIsolate()));
JavaScriptFrame* frame = it.frame();
return args.GetReturnValue().Set(frame->is_turbofan());
}
class RunDeoptTest : public TestWithContext {
protected:
void InstallIsOptimizedHelper(v8::Isolate* isolate) {
v8::Local<v8::Context> context = isolate->GetCurrentContext();
v8::Local<v8::FunctionTemplate> t =
v8::FunctionTemplate::New(isolate, IsOptimized);
CHECK(context->Global()
->Set(context, NewString("IsOptimized"),
t->GetFunction(context).ToLocalChecked())
.FromJust());
}
};
TEST_F(RunDeoptTest, DeoptSimple) {
FLAG_allow_natives_syntax = true;
FunctionTester T(i_isolate(),
"(function f(a) {"
" var b = 1;"
" if (!IsOptimized()) return 0;"
" %DeoptimizeFunction(f);"
" if (IsOptimized()) return 0;"
" return a + b;"
"})");
InstallIsOptimizedHelper(v8_isolate());
T.CheckCall(T.NewNumber(2), T.NewNumber(1));
}
TEST_F(RunDeoptTest, DeoptSimpleInExpr) {
FLAG_allow_natives_syntax = true;
FunctionTester T(i_isolate(),
"(function f(a) {"
" var b = 1;"
" var c = 2;"
" if (!IsOptimized()) return 0;"
" var d = b + (%DeoptimizeFunction(f), c);"
" if (IsOptimized()) return 0;"
" return d + a;"
"})");
InstallIsOptimizedHelper(v8_isolate());
T.CheckCall(T.NewNumber(6), T.NewNumber(3));
}
TEST_F(RunDeoptTest, DeoptExceptionHandlerCatch) {
FLAG_allow_natives_syntax = true;
FunctionTester T(i_isolate(),
"(function f() {"
" var is_opt = IsOptimized;"
" try {"
" DeoptAndThrow(f);"
" } catch (e) {"
" return is_opt();"
" }"
"})");
TryRunJS("function DeoptAndThrow(f) { %DeoptimizeFunction(f); throw 0; }");
InstallIsOptimizedHelper(v8_isolate());
T.CheckCall(T.false_value());
}
TEST_F(RunDeoptTest, DeoptExceptionHandlerFinally) {
FLAG_allow_natives_syntax = true;
FunctionTester T(i_isolate(),
"(function f() {"
" var is_opt = IsOptimized;"
" try {"
" DeoptAndThrow(f);"
" } finally {"
" return is_opt();"
" }"
"})");
TryRunJS("function DeoptAndThrow(f) { %DeoptimizeFunction(f); throw 0; }");
InstallIsOptimizedHelper(v8_isolate());
T.CheckCall(T.false_value());
}
TEST_F(RunDeoptTest, DeoptTrivial) {
FLAG_allow_natives_syntax = true;
FunctionTester T(i_isolate(),
"(function foo() {"
" %DeoptimizeFunction(foo);"
" return 1;"
"})");
T.CheckCall(T.NewNumber(1));
}
} // namespace compiler
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment