Commit 4c41299d authored by Georg Neis's avatar Georg Neis Committed by V8 LUCI CQ

[compiler] Fix serialization for Function#bind

It was not in sync with the optimization, which relies on
inspecting up the length and name fields even for bound
functions.

To make a now meaningful serializer test actually pass, I have
to to make some changes to the test setup.

I'm also moving the function name and length index constants
from JSFunction to JSFunctionOrBoundFunction for clarity.

TBR=marja@chromium.org

Bug: v8:7790
Change-Id: I36dd3c80996ccb53810c7ea9bfceb5c84ffd60ab
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2972919
Commit-Queue: Georg Neis <neis@chromium.org>
Reviewed-by: 's avatarSantiago Aboy Solanes <solanes@chromium.org>
Reviewed-by: 's avatarDominik Inführ <dinfuehr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75299}
parent 332d6c11
...@@ -16,10 +16,10 @@ extern transitioning builtin ...@@ -16,10 +16,10 @@ extern transitioning builtin
FunctionPrototypeBind(implicit context: Context)( FunctionPrototypeBind(implicit context: Context)(
JSFunction, JSAny, int32): JSAny; JSFunction, JSAny, int32): JSAny;
const kLengthDescriptorIndex: const kLengthDescriptorIndex: constexpr int32
constexpr int32 generates 'JSFunction::kLengthDescriptorIndex'; generates 'JSFunctionOrBoundFunction::kLengthDescriptorIndex';
const kNameDescriptorIndex: const kNameDescriptorIndex: constexpr int32
constexpr int32 generates 'JSFunction::kNameDescriptorIndex'; generates 'JSFunctionOrBoundFunction::kNameDescriptorIndex';
const kMinDescriptorsForFastBind: const kMinDescriptorsForFastBind:
constexpr int31 generates 'JSFunction::kMinDescriptorsForFastBind'; constexpr int31 generates 'JSFunction::kMinDescriptorsForFastBind';
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "src/objects/feedback-vector-inl.h" #include "src/objects/feedback-vector-inl.h"
#include "src/objects/js-array-buffer-inl.h" #include "src/objects/js-array-buffer-inl.h"
#include "src/objects/js-array-inl.h" #include "src/objects/js-array-inl.h"
#include "src/objects/js-objects.h" #include "src/objects/js-function.h"
#include "src/objects/objects-inl.h" #include "src/objects/objects-inl.h"
#include "src/objects/ordered-hash-table.h" #include "src/objects/ordered-hash-table.h"
...@@ -2633,14 +2633,17 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) { ...@@ -2633,14 +2633,17 @@ Reduction JSCallReducer::ReduceFunctionPrototypeBind(Node* node) {
// recomputed even if the actual value of the object changes. // recomputed even if the actual value of the object changes.
// This mirrors the checks done in builtins-function-gen.cc at // This mirrors the checks done in builtins-function-gen.cc at
// runtime otherwise. // runtime otherwise.
int minimum_nof_descriptors = std::max({JSFunction::kLengthDescriptorIndex, int minimum_nof_descriptors =
JSFunction::kNameDescriptorIndex}) + std::max({JSFunctionOrBoundFunction::kLengthDescriptorIndex,
JSFunctionOrBoundFunction::kNameDescriptorIndex}) +
1; 1;
if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) { if (receiver_map.NumberOfOwnDescriptors() < minimum_nof_descriptors) {
return inference.NoChange(); return inference.NoChange();
} }
const InternalIndex kLengthIndex(JSFunction::kLengthDescriptorIndex); const InternalIndex kLengthIndex(
const InternalIndex kNameIndex(JSFunction::kNameDescriptorIndex); JSFunctionOrBoundFunction::kLengthDescriptorIndex);
const InternalIndex kNameIndex(
JSFunctionOrBoundFunction::kNameDescriptorIndex);
if (!receiver_map.serialized_own_descriptor(kLengthIndex) || if (!receiver_map.serialized_own_descriptor(kLengthIndex) ||
!receiver_map.serialized_own_descriptor(kNameIndex)) { !receiver_map.serialized_own_descriptor(kNameIndex)) {
TRACE_BROKER_MISSING(broker(), TRACE_BROKER_MISSING(broker(),
......
...@@ -2716,8 +2716,9 @@ void ProcessMapForFunctionBind(MapRef map) { ...@@ -2716,8 +2716,9 @@ void ProcessMapForFunctionBind(MapRef map) {
1; 1;
if (map.NumberOfOwnDescriptors() >= min_nof_descriptors) { if (map.NumberOfOwnDescriptors() >= min_nof_descriptors) {
map.SerializeOwnDescriptor( map.SerializeOwnDescriptor(
InternalIndex(JSFunction::kLengthDescriptorIndex)); InternalIndex(JSFunctionOrBoundFunction::kLengthDescriptorIndex));
map.SerializeOwnDescriptor(InternalIndex(JSFunction::kNameDescriptorIndex)); map.SerializeOwnDescriptor(
InternalIndex(JSFunctionOrBoundFunction::kNameDescriptorIndex));
} }
} }
} // namespace } // namespace
...@@ -2725,17 +2726,22 @@ void ProcessMapForFunctionBind(MapRef map) { ...@@ -2725,17 +2726,22 @@ void ProcessMapForFunctionBind(MapRef map) {
void SerializerForBackgroundCompilation::ProcessHintsForFunctionBind( void SerializerForBackgroundCompilation::ProcessHintsForFunctionBind(
Hints const& receiver_hints) { Hints const& receiver_hints) {
for (auto constant : receiver_hints.constants()) { for (auto constant : receiver_hints.constants()) {
if (!constant->IsJSFunction()) continue; if (constant->IsJSFunction()) {
JSFunctionRef function = JSFunctionRef function =
MakeRef(broker(), Handle<JSFunction>::cast(constant)); MakeRef(broker(), Handle<JSFunction>::cast(constant));
function.Serialize(); function.Serialize();
ProcessMapForFunctionBind(function.map()); ProcessMapForFunctionBind(function.map());
} else if (constant->IsJSBoundFunction()) {
JSBoundFunctionRef function =
MakeRef(broker(), Handle<JSBoundFunction>::cast(constant));
function.Serialize();
ProcessMapForFunctionBind(function.map());
}
} }
for (auto map : receiver_hints.maps()) { for (auto map : receiver_hints.maps()) {
if (!map->IsJSFunctionMap()) continue; if (!map->IsJSFunctionMap() && !map->IsJSBoundFunctionMap()) continue;
MapRef map_ref = MakeRef(broker(), map); ProcessMapForFunctionBind(MakeRef(broker(), map));
ProcessMapForFunctionBind(map_ref);
} }
} }
......
...@@ -3572,14 +3572,14 @@ Handle<Map> Factory::CreateSloppyFunctionMap( ...@@ -3572,14 +3572,14 @@ Handle<Map> Factory::CreateSloppyFunctionMap(
static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY); static_cast<PropertyAttributes>(DONT_ENUM | READ_ONLY);
int field_index = 0; int field_index = 0;
STATIC_ASSERT(JSFunction::kLengthDescriptorIndex == 0); STATIC_ASSERT(JSFunctionOrBoundFunction::kLengthDescriptorIndex == 0);
{ // Add length accessor. { // Add length accessor.
Descriptor d = Descriptor::AccessorConstant( Descriptor d = Descriptor::AccessorConstant(
length_string(), function_length_accessor(), roc_attribs); length_string(), function_length_accessor(), roc_attribs);
map->AppendDescriptor(isolate(), &d); map->AppendDescriptor(isolate(), &d);
} }
STATIC_ASSERT(JSFunction::kNameDescriptorIndex == 1); STATIC_ASSERT(JSFunctionOrBoundFunction::kNameDescriptorIndex == 1);
if (IsFunctionModeWithName(function_mode)) { if (IsFunctionModeWithName(function_mode)) {
// Add name field. // Add name field.
Handle<Name> name = isolate()->factory()->name_string(); Handle<Name> name = isolate()->factory()->name_string();
......
...@@ -3871,6 +3871,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -3871,6 +3871,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
Map::EnsureDescriptorSlack(isolate_, map, 2); Map::EnsureDescriptorSlack(isolate_, map, 2);
{ // length { // length
STATIC_ASSERT(JSFunctionOrBoundFunction::kLengthDescriptorIndex == 0);
Descriptor d = Descriptor::AccessorConstant( Descriptor d = Descriptor::AccessorConstant(
factory->length_string(), factory->bound_function_length_accessor(), factory->length_string(), factory->bound_function_length_accessor(),
roc_attribs); roc_attribs);
...@@ -3878,6 +3879,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object, ...@@ -3878,6 +3879,7 @@ void Genesis::InitializeGlobal(Handle<JSGlobalObject> global_object,
} }
{ // name { // name
STATIC_ASSERT(JSFunctionOrBoundFunction::kNameDescriptorIndex == 1);
Descriptor d = Descriptor::AccessorConstant( Descriptor d = Descriptor::AccessorConstant(
factory->name_string(), factory->bound_function_name_accessor(), factory->name_string(), factory->bound_function_name_accessor(),
roc_attribs); roc_attribs);
......
...@@ -24,6 +24,9 @@ class JSFunctionOrBoundFunction ...@@ -24,6 +24,9 @@ class JSFunctionOrBoundFunction
: public TorqueGeneratedJSFunctionOrBoundFunction<JSFunctionOrBoundFunction, : public TorqueGeneratedJSFunctionOrBoundFunction<JSFunctionOrBoundFunction,
JSObject> { JSObject> {
public: public:
static const int kLengthDescriptorIndex = 0;
static const int kNameDescriptorIndex = 1;
STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize); STATIC_ASSERT(kHeaderSize == JSObject::kHeaderSize);
TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction) TQ_OBJECT_CONSTRUCTORS(JSFunctionOrBoundFunction)
}; };
...@@ -59,9 +62,6 @@ class JSFunction : public JSFunctionOrBoundFunction { ...@@ -59,9 +62,6 @@ class JSFunction : public JSFunctionOrBoundFunction {
// can be shared by instances. // can be shared by instances.
DECL_ACCESSORS(shared, SharedFunctionInfo) DECL_ACCESSORS(shared, SharedFunctionInfo)
static const int kLengthDescriptorIndex = 0;
static const int kNameDescriptorIndex = 1;
// Fast binding requires length and name accessors. // Fast binding requires length and name accessors.
static const int kMinDescriptorsForFastBind = 2; static const int kMinDescriptorsForFastBind = 2;
......
...@@ -272,6 +272,7 @@ i::Handle<i::JSFunction> Optimize( ...@@ -272,6 +272,7 @@ i::Handle<i::JSFunction> Optimize(
i::OptimizedCompilationInfo info(zone, isolate, shared, function, i::OptimizedCompilationInfo info(zone, isolate, shared, function,
i::CodeKind::TURBOFAN); i::CodeKind::TURBOFAN);
if (flags & ~i::OptimizedCompilationInfo::kInlining) UNIMPLEMENTED();
if (flags & i::OptimizedCompilationInfo::kInlining) { if (flags & i::OptimizedCompilationInfo::kInlining) {
info.set_inlining(); info.set_inlining();
} }
......
...@@ -18,7 +18,8 @@ namespace v8 { ...@@ -18,7 +18,8 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
SerializerTester::SerializerTester(const char* source) SerializerTester::SerializerTester(const char* global_source,
const char* local_source)
: canonical_(main_isolate()) { : canonical_(main_isolate()) {
// The tests only make sense in the context of concurrent compilation. // The tests only make sense in the context of concurrent compilation.
FLAG_concurrent_inlining = true; FLAG_concurrent_inlining = true;
...@@ -33,18 +34,14 @@ SerializerTester::SerializerTester(const char* source) ...@@ -33,18 +34,14 @@ SerializerTester::SerializerTester(const char* source)
FLAG_allow_natives_syntax = true; FLAG_allow_natives_syntax = true;
FlagList::EnforceFlagImplications(); FlagList::EnforceFlagImplications();
CompileRun(global_source);
std::string function_string = "(function() { "; std::string function_string = "(function() { ";
function_string += source; function_string += local_source;
function_string += " })();"; function_string += " })();";
Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle( Handle<JSFunction> function = Handle<JSFunction>::cast(v8::Utils::OpenHandle(
*v8::Local<v8::Function>::Cast(CompileRun(function_string.c_str())))); *v8::Local<v8::Function>::Cast(CompileRun(function_string.c_str()))));
uint32_t flags = i::OptimizedCompilationInfo::kInlining | uint32_t flags = i::OptimizedCompilationInfo::kInlining;
i::OptimizedCompilationInfo::kFunctionContextSpecializing |
i::OptimizedCompilationInfo::kLoopPeeling |
i::OptimizedCompilationInfo::kBailoutOnUninitialized |
i::OptimizedCompilationInfo::kAllocationFolding |
i::OptimizedCompilationInfo::kSplitting |
i::OptimizedCompilationInfo::kAnalyzeEnvironmentLiveness;
Optimize(function, main_zone(), main_isolate(), flags, &broker_); Optimize(function, main_zone(), main_isolate(), flags, &broker_);
// Update handle to the corresponding serialized Handle in the broker. // Update handle to the corresponding serialized Handle in the broker.
function = function =
...@@ -54,7 +51,7 @@ SerializerTester::SerializerTester(const char* source) ...@@ -54,7 +51,7 @@ SerializerTester::SerializerTester(const char* source)
TEST(SerializeEmptyFunction) { TEST(SerializeEmptyFunction) {
SerializerTester tester( SerializerTester tester(
"function f() {}; %EnsureFeedbackVectorForFunction(f); return f;"); "", "function f() {}; %EnsureFeedbackVectorForFunction(f); return f;");
JSFunctionRef function = tester.function(); JSFunctionRef function = tester.function();
CHECK(tester.broker()->IsSerializedForCompilation( CHECK(tester.broker()->IsSerializedForCompilation(
function.shared(), function.feedback_vector())); function.shared(), function.feedback_vector()));
...@@ -63,9 +60,10 @@ TEST(SerializeEmptyFunction) { ...@@ -63,9 +60,10 @@ TEST(SerializeEmptyFunction) {
// This helper function allows for testing whether an inlinee candidate // This helper function allows for testing whether an inlinee candidate
// was properly serialized. It expects that the top-level function (that is // was properly serialized. It expects that the top-level function (that is
// run through the SerializerTester) will return its inlinee candidate. // run through the SerializerTester) will return its inlinee candidate.
void CheckForSerializedInlinee(const char* source, int argc = 0, void CheckForSerializedInlinee(const char* global_source,
const char* local_source, int argc = 0,
Handle<Object> argv[] = {}) { Handle<Object> argv[] = {}) {
SerializerTester tester(source); SerializerTester tester(global_source, local_source);
JSFunctionRef f = tester.function(); JSFunctionRef f = tester.function();
CHECK(tester.broker()->IsSerializedForCompilation(f.shared(), CHECK(tester.broker()->IsSerializedForCompilation(f.shared(),
f.feedback_vector())); f.feedback_vector()));
...@@ -75,7 +73,6 @@ void CheckForSerializedInlinee(const char* source, int argc = 0, ...@@ -75,7 +73,6 @@ void CheckForSerializedInlinee(const char* source, int argc = 0,
tester.isolate()->factory()->undefined_value(), argc, argv); tester.isolate()->factory()->undefined_value(), argc, argv);
Handle<Object> g; Handle<Object> g;
CHECK(g_obj.ToHandle(&g)); CHECK(g_obj.ToHandle(&g));
CHECK_WITH_MSG( CHECK_WITH_MSG(
g->IsJSFunction(), g->IsJSFunction(),
"The return value of the outer function must be a function too"); "The return value of the outer function must be a function too");
...@@ -95,7 +92,7 @@ void CheckForSerializedInlinee(const char* source, int argc = 0, ...@@ -95,7 +92,7 @@ void CheckForSerializedInlinee(const char* source, int argc = 0,
} }
TEST(SerializeInlinedClosure) { TEST(SerializeInlinedClosure) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function f() {" "function f() {"
" function g(){ return g; }" " function g(){ return g; }"
" %EnsureFeedbackVectorForFunction(g);" " %EnsureFeedbackVectorForFunction(g);"
...@@ -106,7 +103,7 @@ TEST(SerializeInlinedClosure) { ...@@ -106,7 +103,7 @@ TEST(SerializeInlinedClosure) {
} }
TEST(SerializeInlinedFunction) { TEST(SerializeInlinedFunction) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g() {};" "function g() {};"
"%EnsureFeedbackVectorForFunction(g);" "%EnsureFeedbackVectorForFunction(g);"
"function f() {" "function f() {"
...@@ -117,7 +114,7 @@ TEST(SerializeInlinedFunction) { ...@@ -117,7 +114,7 @@ TEST(SerializeInlinedFunction) {
} }
TEST(SerializeCallUndefinedReceiver) { TEST(SerializeCallUndefinedReceiver) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g(a,b,c) {};" "function g(a,b,c) {};"
"%EnsureFeedbackVectorForFunction(g);" "%EnsureFeedbackVectorForFunction(g);"
"function f() {" "function f() {"
...@@ -128,7 +125,7 @@ TEST(SerializeCallUndefinedReceiver) { ...@@ -128,7 +125,7 @@ TEST(SerializeCallUndefinedReceiver) {
} }
TEST(SerializeCallUndefinedReceiver2) { TEST(SerializeCallUndefinedReceiver2) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g(a,b) {};" "function g(a,b) {};"
"%EnsureFeedbackVectorForFunction(g);" "%EnsureFeedbackVectorForFunction(g);"
"function f() {" "function f() {"
...@@ -139,7 +136,7 @@ TEST(SerializeCallUndefinedReceiver2) { ...@@ -139,7 +136,7 @@ TEST(SerializeCallUndefinedReceiver2) {
} }
TEST(SerializeCallProperty) { TEST(SerializeCallProperty) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"let obj = {" "let obj = {"
" g: function g(a,b,c) {}" " g: function g(a,b,c) {}"
"};" "};"
...@@ -152,7 +149,7 @@ TEST(SerializeCallProperty) { ...@@ -152,7 +149,7 @@ TEST(SerializeCallProperty) {
} }
TEST(SerializeCallProperty2) { TEST(SerializeCallProperty2) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"let obj = {" "let obj = {"
" g: function g(a,b) {}" " g: function g(a,b) {}"
"};" "};"
...@@ -165,7 +162,7 @@ TEST(SerializeCallProperty2) { ...@@ -165,7 +162,7 @@ TEST(SerializeCallProperty2) {
} }
TEST(SerializeCallAnyReceiver) { TEST(SerializeCallAnyReceiver) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"let obj = {" "let obj = {"
" g: function g() {}" " g: function g() {}"
"};" "};"
...@@ -180,7 +177,7 @@ TEST(SerializeCallAnyReceiver) { ...@@ -180,7 +177,7 @@ TEST(SerializeCallAnyReceiver) {
} }
TEST(SerializeCallWithSpread) { TEST(SerializeCallWithSpread) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g(args) {};" "function g(args) {};"
"%EnsureFeedbackVectorForFunction(g);" "%EnsureFeedbackVectorForFunction(g);"
"const arr = [1,2,3];" "const arr = [1,2,3];"
...@@ -195,7 +192,7 @@ TEST(SerializeCallWithSpread) { ...@@ -195,7 +192,7 @@ TEST(SerializeCallWithSpread) {
// thus allowing us to test if we forward arguments hints (`callee` in this // thus allowing us to test if we forward arguments hints (`callee` in this
// example) and correctly serialize the inlining candidate `j`. // example) and correctly serialize the inlining candidate `j`.
TEST(SerializeCallArguments) { TEST(SerializeCallArguments) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g(callee) { callee(); };" "function g(callee) { callee(); };"
"function h() {};" "function h() {};"
"function i() {};" "function i() {};"
...@@ -213,7 +210,7 @@ TEST(SerializeCallArguments) { ...@@ -213,7 +210,7 @@ TEST(SerializeCallArguments) {
} }
TEST(SerializeConstruct) { TEST(SerializeConstruct) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g() {};" "function g() {};"
"%EnsureFeedbackVectorForFunction(g);" "%EnsureFeedbackVectorForFunction(g);"
"function f() {" "function f() {"
...@@ -224,7 +221,7 @@ TEST(SerializeConstruct) { ...@@ -224,7 +221,7 @@ TEST(SerializeConstruct) {
} }
TEST(SerializeConstructWithSpread) { TEST(SerializeConstructWithSpread) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g(a, b, c) {};" "function g(a, b, c) {};"
"%EnsureFeedbackVectorForFunction(g);" "%EnsureFeedbackVectorForFunction(g);"
"const arr = [1, 2];" "const arr = [1, 2];"
...@@ -236,7 +233,7 @@ TEST(SerializeConstructWithSpread) { ...@@ -236,7 +233,7 @@ TEST(SerializeConstructWithSpread) {
} }
TEST(SerializeConstructSuper) { TEST(SerializeConstructSuper) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"class A {};" "class A {};"
"class B extends A { constructor() { super(); } };" "class B extends A { constructor() { super(); } };"
"%EnsureFeedbackVectorForFunction(A);" "%EnsureFeedbackVectorForFunction(A);"
...@@ -249,7 +246,7 @@ TEST(SerializeConstructSuper) { ...@@ -249,7 +246,7 @@ TEST(SerializeConstructSuper) {
} }
TEST(SerializeConditionalJump) { TEST(SerializeConditionalJump) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g(callee) { callee(); };" "function g(callee) { callee(); };"
"function h() {};" "function h() {};"
"function i() {};" "function i() {};"
...@@ -268,7 +265,7 @@ TEST(SerializeConditionalJump) { ...@@ -268,7 +265,7 @@ TEST(SerializeConditionalJump) {
} }
TEST(SerializeUnconditionalJump) { TEST(SerializeUnconditionalJump) {
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function g(callee) { callee(); };" "function g(callee) { callee(); };"
"function h() {};" "function h() {};"
"function i() {};" "function i() {};"
...@@ -292,6 +289,7 @@ TEST(SerializeUnconditionalJump) { ...@@ -292,6 +289,7 @@ TEST(SerializeUnconditionalJump) {
TEST(MergeJumpTargetEnvironment) { TEST(MergeJumpTargetEnvironment) {
CheckForSerializedInlinee( CheckForSerializedInlinee(
"",
"function f() {" "function f() {"
" let g;" " let g;"
" while (true) {" " while (true) {"
...@@ -305,27 +303,29 @@ TEST(MergeJumpTargetEnvironment) { ...@@ -305,27 +303,29 @@ TEST(MergeJumpTargetEnvironment) {
} }
TEST(BoundFunctionTarget) { TEST(BoundFunctionTarget) {
const char* global = "function apply1(foo, arg) { return foo(arg); };";
CheckForSerializedInlinee( CheckForSerializedInlinee(
"function apply(foo, arg) { return foo(arg); };" global,
"%EnsureFeedbackVectorForFunction(apply);" "%EnsureFeedbackVectorForFunction(apply1);"
"function test() {" "function test() {"
" const lambda = (a) => a;" " const lambda = (a) => a;"
" %EnsureFeedbackVectorForFunction(lambda);" " %EnsureFeedbackVectorForFunction(lambda);"
" let bound = apply.bind(null, lambda).bind(null, 42);" " let bound = apply1.bind(null, lambda).bind(null, 42);"
" %TurbofanStaticAssert(bound() == 42); return apply;" " %TurbofanStaticAssert(bound() == 42); return apply1;"
"};" "};"
"%EnsureFeedbackVectorForFunction(test);" "%EnsureFeedbackVectorForFunction(test);"
"test(); return test;"); "test(); return test;");
} }
TEST(BoundFunctionArguments) { TEST(BoundFunctionArguments) {
const char* global = "function apply2(foo, arg) { return foo(arg); };";
CheckForSerializedInlinee( CheckForSerializedInlinee(
"function apply(foo, arg) { return foo(arg); };" global,
"%EnsureFeedbackVectorForFunction(apply);" "%EnsureFeedbackVectorForFunction(apply2);"
"function test() {" "function test() {"
" const lambda = (a) => a;" " const lambda = (a) => a;"
" %EnsureFeedbackVectorForFunction(lambda);" " %EnsureFeedbackVectorForFunction(lambda);"
" let bound = apply.bind(null, lambda).bind(null, 42);" " let bound = apply2.bind(null, lambda).bind(null, 42);"
" %TurbofanStaticAssert(bound() == 42); return lambda;" " %TurbofanStaticAssert(bound() == 42); return lambda;"
"};" "};"
"%EnsureFeedbackVectorForFunction(test);" "%EnsureFeedbackVectorForFunction(test);"
...@@ -335,7 +335,7 @@ TEST(BoundFunctionArguments) { ...@@ -335,7 +335,7 @@ TEST(BoundFunctionArguments) {
TEST(ArrowFunctionInlined) { TEST(ArrowFunctionInlined) {
// The loop is to ensure there is a feedback vector for the arrow function // The loop is to ensure there is a feedback vector for the arrow function
// {b}. // {b}.
CheckForSerializedInlinee( CheckForSerializedInlinee("",
"function foo() {" "function foo() {"
" let b = x => x * x;" " let b = x => x * x;"
" let a = [1, 2, 3].map(b);" " let a = [1, 2, 3].map(b);"
...@@ -348,6 +348,7 @@ TEST(ArrowFunctionInlined) { ...@@ -348,6 +348,7 @@ TEST(ArrowFunctionInlined) {
TEST(BoundFunctionResult) { TEST(BoundFunctionResult) {
CheckForSerializedInlinee( CheckForSerializedInlinee(
"",
"function id(x) { return x }" "function id(x) { return x }"
"function foo() { id.bind(undefined, 42)(); return id; }" "function foo() { id.bind(undefined, 42)(); return id; }"
"%PrepareFunctionForOptimization(foo);" "%PrepareFunctionForOptimization(foo);"
...@@ -360,6 +361,7 @@ TEST(BoundFunctionResult) { ...@@ -360,6 +361,7 @@ TEST(BoundFunctionResult) {
TEST(MultipleFunctionCalls) { TEST(MultipleFunctionCalls) {
CheckForSerializedInlinee( CheckForSerializedInlinee(
"",
"function inc(x) { return ++x; }" "function inc(x) { return ++x; }"
"function dec(x) { return --x; }" "function dec(x) { return --x; }"
"function apply(f, x) { return f(x); }" "function apply(f, x) { return f(x); }"
......
...@@ -18,15 +18,16 @@ class ZoneStats; ...@@ -18,15 +18,16 @@ class ZoneStats;
// The purpose of this class is to provide testing facility for the // The purpose of this class is to provide testing facility for the
// SerializerForBackgroundCompilation class. On a high-level, it executes the // SerializerForBackgroundCompilation class. On a high-level, it executes the
// following steps: // code given by {global_source} at global scope and then performs the following
// 1. Wraps the provided source in an IIFE // steps for {local_source}:
// 2. Generates bytecode for the given source // 1. Wraps it in an IIFE.
// 3. Runs the bytecode which *must* return a function // 2. Generates bytecode and runs it, which *must* return a function.
// 4. Takes the returned function and optimizes it // 3. Takes the returned function and optimizes it.
// 5. The optimized function is accessible through `function()` // 4. The optimized function is accessible through `function()`.
class SerializerTester : public HandleAndZoneScope { class SerializerTester : public HandleAndZoneScope {
public: public:
explicit SerializerTester(const char* source); explicit SerializerTester(const char* global_source,
const char* local_source);
JSFunctionRef function() const { return function_.value(); } JSFunctionRef function() const { return function_.value(); }
JSHeapBroker* broker() const { return broker_.get(); } JSHeapBroker* broker() const { return broker_.get(); }
......
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