2019-01-29 12:50:53 +00:00
|
|
|
// Copyright 2019 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.
|
|
|
|
|
|
|
|
// Serializer tests don't make sense in lite mode, as it doesn't gather
|
|
|
|
// IC feedback.
|
|
|
|
#ifndef V8_LITE_MODE
|
|
|
|
|
|
|
|
#include "test/cctest/compiler/serializer-tester.h"
|
|
|
|
|
2019-05-17 12:13:44 +00:00
|
|
|
#include "src/api/api-inl.h"
|
2019-05-21 09:30:15 +00:00
|
|
|
#include "src/codegen/optimized-compilation-info.h"
|
2019-01-29 12:50:53 +00:00
|
|
|
#include "src/compiler/serializer-for-background-compilation.h"
|
|
|
|
#include "src/compiler/zone-stats.h"
|
|
|
|
#include "src/zone/zone.h"
|
|
|
|
|
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace compiler {
|
|
|
|
|
|
|
|
SerializerTester::SerializerTester(const char* source)
|
|
|
|
: canonical_(main_isolate()) {
|
2019-01-30 09:09:04 +00:00
|
|
|
// The tests only make sense in the context of concurrent compilation.
|
2019-01-29 12:50:53 +00:00
|
|
|
FLAG_concurrent_inlining = true;
|
2019-01-30 09:09:04 +00:00
|
|
|
// The tests don't make sense when optimizations are turned off.
|
2019-01-29 12:50:53 +00:00
|
|
|
FLAG_opt = true;
|
2019-01-30 09:09:04 +00:00
|
|
|
// We need the IC to feed it to the serializer.
|
2019-01-29 12:50:53 +00:00
|
|
|
FLAG_use_ic = true;
|
2019-01-30 09:09:04 +00:00
|
|
|
// We need manual control over when a given function is optimized.
|
|
|
|
FLAG_always_opt = false;
|
2019-02-12 13:56:26 +00:00
|
|
|
// We need allocation of executable memory for the compilation.
|
|
|
|
FLAG_jitless = false;
|
2019-05-09 09:32:00 +00:00
|
|
|
FLAG_allow_natives_syntax = true;
|
2019-01-29 12:50:53 +00:00
|
|
|
|
2019-01-30 09:09:04 +00:00
|
|
|
std::string function_string = "(function() { ";
|
|
|
|
function_string += source;
|
|
|
|
function_string += " })();";
|
2019-01-29 12:50:53 +00:00
|
|
|
Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
|
2019-01-30 09:09:04 +00:00
|
|
|
*v8::Local<v8::Function>::Cast(CompileRun(function_string.c_str()))));
|
2019-01-30 13:37:25 +00:00
|
|
|
uint32_t flags = i::OptimizedCompilationInfo::kInliningEnabled |
|
|
|
|
i::OptimizedCompilationInfo::kFunctionContextSpecializing |
|
|
|
|
i::OptimizedCompilationInfo::kAccessorInliningEnabled |
|
|
|
|
i::OptimizedCompilationInfo::kLoopPeelingEnabled |
|
|
|
|
i::OptimizedCompilationInfo::kBailoutOnUninitialized |
|
|
|
|
i::OptimizedCompilationInfo::kAllocationFoldingEnabled |
|
|
|
|
i::OptimizedCompilationInfo::kSplittingEnabled |
|
|
|
|
i::OptimizedCompilationInfo::kAnalyzeEnvironmentLiveness;
|
|
|
|
Optimize(function, main_zone(), main_isolate(), flags, &broker_);
|
2019-05-02 12:17:06 +00:00
|
|
|
function_ = JSFunctionRef(broker(), function);
|
2019-01-29 12:50:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeEmptyFunction) {
|
2019-05-09 09:32:00 +00:00
|
|
|
SerializerTester tester(
|
|
|
|
"function f() {}; %EnsureFeedbackVectorForFunction(f); return f;");
|
2019-01-30 09:09:04 +00:00
|
|
|
CHECK(tester.function().IsSerializedForCompilation());
|
|
|
|
}
|
|
|
|
|
|
|
|
// This helper function allows for testing weather an inlinee candidate
|
|
|
|
// was properly serialized. It expects that the top-level function (that is
|
|
|
|
// run through the SerializerTester) will return its inlinee candidate.
|
2019-01-30 13:37:25 +00:00
|
|
|
void CheckForSerializedInlinee(const char* source, int argc = 0,
|
|
|
|
Handle<Object> argv[] = {}) {
|
2019-01-30 09:09:04 +00:00
|
|
|
SerializerTester tester(source);
|
|
|
|
JSFunctionRef f = tester.function();
|
|
|
|
CHECK(f.IsSerializedForCompilation());
|
|
|
|
|
|
|
|
MaybeHandle<Object> g_obj = Execution::Call(
|
|
|
|
tester.isolate(), tester.function().object(),
|
2019-01-30 13:37:25 +00:00
|
|
|
tester.isolate()->factory()->undefined_value(), argc, argv);
|
2019-01-30 09:09:04 +00:00
|
|
|
Handle<Object> g;
|
|
|
|
CHECK(g_obj.ToHandle(&g));
|
|
|
|
|
2019-08-01 07:53:47 +00:00
|
|
|
CHECK_WITH_MSG(
|
|
|
|
g->IsJSFunction(),
|
|
|
|
"The return value of the outer function must be a function too");
|
2019-01-30 09:09:04 +00:00
|
|
|
Handle<JSFunction> g_func = Handle<JSFunction>::cast(g);
|
2019-08-01 07:53:47 +00:00
|
|
|
|
2019-01-30 09:09:04 +00:00
|
|
|
SharedFunctionInfoRef g_sfi(tester.broker(),
|
|
|
|
handle(g_func->shared(), tester.isolate()));
|
|
|
|
FeedbackVectorRef g_fv(tester.broker(),
|
|
|
|
handle(g_func->feedback_vector(), tester.isolate()));
|
|
|
|
CHECK(g_sfi.IsSerializedForCompilation(g_fv));
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeInlinedClosure) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function f() {"
|
2019-05-09 09:32:00 +00:00
|
|
|
" function g(){ return g; }"
|
|
|
|
" %EnsureFeedbackVectorForFunction(g);"
|
|
|
|
" return g();"
|
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 09:09:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeInlinedFunction) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g() {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-01-30 09:09:04 +00:00
|
|
|
"function f() {"
|
|
|
|
" g(); return g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-29 12:50:53 +00:00
|
|
|
}
|
2019-01-30 13:37:25 +00:00
|
|
|
|
|
|
|
TEST(SerializeCallUndefinedReceiver) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g(a,b,c) {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"function f() {"
|
|
|
|
" g(1,2,3); return g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 13:37:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeCallUndefinedReceiver2) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g(a,b) {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"function f() {"
|
|
|
|
" g(1,2); return g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 13:37:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeCallProperty) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"let obj = {"
|
|
|
|
" g: function g(a,b,c) {}"
|
|
|
|
"};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(obj.g);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"function f() {"
|
|
|
|
" obj.g(1,2,3); return obj.g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 13:37:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeCallProperty2) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"let obj = {"
|
|
|
|
" g: function g(a,b) {}"
|
|
|
|
"};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(obj.g);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"function f() {"
|
|
|
|
" obj.g(1,2); return obj.g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 13:37:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeCallAnyReceiver) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"let obj = {"
|
|
|
|
" g: function g() {}"
|
|
|
|
"};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(obj.g);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"function f() {"
|
|
|
|
" with(obj) {"
|
|
|
|
" g(); return g;"
|
|
|
|
" };"
|
|
|
|
"};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"f(); return f;");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeCallWithSpread) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g(args) {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"const arr = [1,2,3];"
|
|
|
|
"function f() {"
|
|
|
|
" g(...arr); return g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 13:37:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The following test causes the CallIC of `g` to turn megamorphic,
|
|
|
|
// thus allowing us to test if we forward arguments hints (`callee` in this
|
|
|
|
// example) and correctly serialize the inlining candidate `j`.
|
|
|
|
TEST(SerializeCallArguments) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g(callee) { callee(); };"
|
|
|
|
"function h() {};"
|
|
|
|
"function i() {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-01-30 13:37:25 +00:00
|
|
|
"g(h); g(i);"
|
|
|
|
"function f() {"
|
|
|
|
" function j() {};"
|
|
|
|
" g(j);"
|
|
|
|
" return j;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"var j = f();"
|
|
|
|
"%EnsureFeedbackVectorForFunction(j);"
|
|
|
|
"f(); return f;");
|
2019-01-30 13:37:25 +00:00
|
|
|
}
|
2019-01-30 14:57:55 +00:00
|
|
|
|
|
|
|
TEST(SerializeConstruct) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g() {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-01-30 14:57:55 +00:00
|
|
|
"function f() {"
|
|
|
|
" new g(); return g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 14:57:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeConstructWithSpread) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g(a, b, c) {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-01-30 14:57:55 +00:00
|
|
|
"const arr = [1, 2];"
|
|
|
|
"function f() {"
|
|
|
|
" new g(0, ...arr); return g;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-01-30 14:57:55 +00:00
|
|
|
}
|
|
|
|
|
2019-03-22 12:12:24 +00:00
|
|
|
TEST(SerializeConstructSuper) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"class A {};"
|
|
|
|
"class B extends A { constructor() { super(); } };"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(A);"
|
|
|
|
"%EnsureFeedbackVectorForFunction(B);"
|
2019-03-22 12:12:24 +00:00
|
|
|
"function f() {"
|
|
|
|
" new B(); return A;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"f(); return f;");
|
2019-03-22 12:12:24 +00:00
|
|
|
}
|
|
|
|
|
2019-02-12 13:56:26 +00:00
|
|
|
TEST(SerializeConditionalJump) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g(callee) { callee(); };"
|
|
|
|
"function h() {};"
|
|
|
|
"function i() {};"
|
2019-05-13 13:20:06 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
2019-02-12 13:56:26 +00:00
|
|
|
"let a = true;"
|
|
|
|
"g(h); g(i);"
|
|
|
|
"function f() {"
|
|
|
|
" function q() {};"
|
|
|
|
" if (a) g(q);"
|
|
|
|
" return q;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"var q = f();"
|
|
|
|
"%EnsureFeedbackVectorForFunction(q);"
|
|
|
|
"f(); return f;");
|
2019-02-12 13:56:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(SerializeUnconditionalJump) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function g(callee) { callee(); };"
|
|
|
|
"function h() {};"
|
|
|
|
"function i() {};"
|
2019-05-09 09:32:00 +00:00
|
|
|
"%EnsureFeedbackVectorForFunction(g);"
|
|
|
|
"%EnsureFeedbackVectorForFunction(h);"
|
|
|
|
"%EnsureFeedbackVectorForFunction(i);"
|
2019-02-12 13:56:26 +00:00
|
|
|
"let a = false;"
|
|
|
|
"g(h); g(i);"
|
|
|
|
"function f() {"
|
|
|
|
" function p() {};"
|
|
|
|
" function q() {};"
|
2019-06-26 07:41:57 +00:00
|
|
|
" if (a) q();"
|
2019-02-12 13:56:26 +00:00
|
|
|
" else g(p);"
|
|
|
|
" return p;"
|
2019-05-09 09:32:00 +00:00
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"var p = f();"
|
|
|
|
"%EnsureFeedbackVectorForFunction(p);"
|
|
|
|
"f(); return f;");
|
2019-02-12 13:56:26 +00:00
|
|
|
}
|
|
|
|
|
2019-05-29 01:13:32 +00:00
|
|
|
TEST(MergeJumpTargetEnvironment) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function f() {"
|
|
|
|
" let g;"
|
|
|
|
" while (true) {"
|
|
|
|
" if (g === undefined) {g = ()=>1; break;} else {g = ()=>2; break};"
|
|
|
|
" };"
|
|
|
|
" g(); return g;"
|
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f);"
|
|
|
|
"%EnsureFeedbackVectorForFunction(f());"
|
|
|
|
"f(); return f;"); // Two calls to f to make g() megamorhpic.
|
|
|
|
}
|
|
|
|
|
2019-08-01 07:53:47 +00:00
|
|
|
TEST(BoundFunctionTarget) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function apply(foo, arg) { return foo(arg); };"
|
|
|
|
"%EnsureFeedbackVectorForFunction(apply);"
|
|
|
|
"function test() {"
|
|
|
|
" const lambda = (a) => a;"
|
|
|
|
" %EnsureFeedbackVectorForFunction(lambda);"
|
|
|
|
" let bound = apply.bind(null, lambda).bind(null, 42);"
|
|
|
|
" %TurbofanStaticAssert(bound() == 42); return apply;"
|
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(test);"
|
|
|
|
"test(); return test;");
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST(BoundFunctionArguments) {
|
|
|
|
CheckForSerializedInlinee(
|
|
|
|
"function apply(foo, arg) { return foo(arg); };"
|
|
|
|
"%EnsureFeedbackVectorForFunction(apply);"
|
|
|
|
"function test() {"
|
|
|
|
" const lambda = (a) => a;"
|
|
|
|
" %EnsureFeedbackVectorForFunction(lambda);"
|
|
|
|
" let bound = apply.bind(null, lambda).bind(null, 42);"
|
|
|
|
" %TurbofanStaticAssert(bound() == 42); return lambda;"
|
|
|
|
"};"
|
|
|
|
"%EnsureFeedbackVectorForFunction(test);"
|
|
|
|
"test(); return test;");
|
|
|
|
}
|
|
|
|
|
2019-01-29 12:50:53 +00:00
|
|
|
} // namespace compiler
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|
|
|
|
|
|
|
|
#endif // V8_LITE_MODE
|