v8/test/cctest/compiler/test-calls-with-arraylike-or-spread.cc
Paolo Severini 6a5568b48e [compiler] Wrong receiver in API calls with --turbo-optimize-apply
Enabling --turbo-optimize-apply breaks tests because we are
passing the wrong receiver;
in JSCallReducer::ReduceCallOrConstructWithArrayLikeOrSpread
we create a Call node with the wrong ConvertReceiverMode, we
pass kNullOrUndefined while it should be kAny. This may break
calls to API or in general calls to functions that use the
receiver.

Bug: chromium:1231108, v8:9974
Change-Id: Ib35a1bf8746ad254b6d63274f3ae11b12aa83de8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3043690
Commit-Queue: Paolo Severini <paolosev@microsoft.com>
Reviewed-by: Georg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75886}
2021-07-23 13:29:54 +00:00

183 lines
6.2 KiB
C++

// 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.
#include "src/flags/flags.h"
#include "test/cctest/compiler/node-observer-tester.h"
#include "test/cctest/test-api.h"
namespace v8 {
namespace internal {
namespace compiler {
void CompileRunWithNodeObserver(const std::string& js_code,
int32_t expected_result,
IrOpcode::Value initial_call_opcode,
IrOpcode::Value updated_call_opcode1,
IrOpcode::Value updated_call_opcode2) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
FLAG_allow_natives_syntax = true;
FLAG_turbo_optimize_apply = true;
// Note: Make sure to not capture stack locations (e.g. `this`) here since
// these lambdas are executed on another thread.
ModificationObserver apply_call_observer(
[initial_call_opcode](const Node* node) {
CHECK_EQ(initial_call_opcode, node->opcode());
},
[updated_call_opcode1, updated_call_opcode2](
const Node* node,
const ObservableNodeState& old_state) -> NodeObserver::Observation {
if (updated_call_opcode1 == node->opcode()) {
return NodeObserver::Observation::kContinue;
} else {
CHECK(updated_call_opcode2 == node->opcode());
return NodeObserver::Observation::kStop;
}
});
{
ObserveNodeScope scope(reinterpret_cast<i::Isolate*>(isolate),
&apply_call_observer);
v8::Local<v8::Value> result_value = CompileRun(js_code.c_str());
CHECK(result_value->IsNumber());
int32_t result =
ConvertJSValue<int32_t>::Get(result_value, env.local()).ToChecked();
CHECK_EQ(result, expected_result);
}
}
TEST(ReduceJSCallWithArrayLike) {
CompileRunWithNodeObserver(
"function sum_js3(a, b, c) { return a + b + c; }"
"function foo(x, y, z) {"
" return %ObserveNode(sum_js3.apply(null, [x, y, z]));"
"}"
"%PrepareFunctionForOptimization(sum_js3);"
"%PrepareFunctionForOptimization(foo);"
"foo(41, 42, 43);"
"%OptimizeFunctionOnNextCall(foo);"
"foo(41, 42, 43);",
126, IrOpcode::kJSCall,
IrOpcode::kJSCall, // not JSCallWithArrayLike
IrOpcode::kPhi); // JSCall => Phi when the call is inlined.
}
TEST(ReduceJSCallWithSpread) {
CompileRunWithNodeObserver(
"function sum_js3(a, b, c) { return a + b + c; }"
"function foo(x, y, z) {"
" const numbers = [x, y, z];"
" return %ObserveNode(sum_js3(...numbers));"
"}"
"%PrepareFunctionForOptimization(sum_js3);"
"%PrepareFunctionForOptimization(foo);"
"foo(41, 42, 43);"
"%OptimizeFunctionOnNextCall(foo);"
"foo(41, 42, 43)",
126, IrOpcode::kJSCallWithSpread,
IrOpcode::kJSCall, // not JSCallWithSpread
IrOpcode::kPhi);
}
TEST(ReduceJSCreateClosure) {
CompileRunWithNodeObserver(
"function foo_closure() {"
" return function(a, b, c) {"
" return a + b + c;"
" }"
"}"
"const _foo_closure = foo_closure();"
"%PrepareFunctionForOptimization(_foo_closure);"
"function foo(x, y, z) {"
" return %ObserveNode(foo_closure().apply(null, [x, y, z]));"
"}"
"%PrepareFunctionForOptimization(foo_closure);"
"%PrepareFunctionForOptimization(foo);"
"foo(41, 42, 43);"
"%OptimizeFunctionOnNextCall(foo_closure);"
"%OptimizeFunctionOnNextCall(foo);"
"foo(41, 42, 43)",
126, IrOpcode::kJSCall,
IrOpcode::kJSCall, // not JSCallWithArrayLike
IrOpcode::kPhi);
}
TEST(ReduceJSCreateBoundFunction) {
CompileRunWithNodeObserver(
"function sum_js3(a, b, c) {"
" return this.x + a + b + c;"
"}"
"function foo(x, y ,z) {"
" return %ObserveNode(sum_js3.bind({x : 42}).apply(null, [ x, y, z ]));"
"}"
"%PrepareFunctionForOptimization(sum_js3);"
"%PrepareFunctionForOptimization(foo);"
"foo(41, 42, 43);"
"%OptimizeFunctionOnNextCall(foo);"
"foo(41, 42, 43)",
168, IrOpcode::kJSCall,
IrOpcode::kJSCall, // not JSCallWithArrayLike
IrOpcode::kPhi);
}
static void SumF(const v8::FunctionCallbackInfo<v8::Value>& args) {
ApiTestFuzzer::Fuzz();
v8::Local<v8::Context> context = args.GetIsolate()->GetCurrentContext();
int this_x = args.This()
->Get(context, v8_str("x"))
.ToLocalChecked()
->Int32Value(context)
.FromJust();
args.GetReturnValue().Set(v8_num(
args[0]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust() +
args[1]->Int32Value(args.GetIsolate()->GetCurrentContext()).FromJust() +
this_x));
}
TEST(ReduceCAPICallWithArrayLike) {
LocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
FLAG_allow_natives_syntax = true;
FLAG_turbo_optimize_apply = true;
Local<v8::FunctionTemplate> sum = v8::FunctionTemplate::New(isolate, SumF);
CHECK(env->Global()
->Set(env.local(), v8_str("sum"),
sum->GetFunction(env.local()).ToLocalChecked())
.FromJust());
Local<v8::FunctionTemplate> fun = v8::FunctionTemplate::New(isolate);
v8::Local<v8::String> class_name = v8_str("the_class_name");
fun->SetClassName(class_name);
Local<ObjectTemplate> templ1 = ObjectTemplate::New(isolate, fun);
templ1->Set(isolate, "x", v8_num(42));
templ1->Set(isolate, "foo", sum);
Local<v8::Object> instance1 =
templ1->NewInstance(env.local()).ToLocalChecked();
CHECK(env->Global()->Set(env.local(), v8_str("p"), instance1).FromJust());
std::string js_code =
"function bar(a, b) { return sum.apply(p, [a, b]); }"
"%PrepareFunctionForOptimization(bar);"
"bar(20, 22);"
"%OptimizeFunctionOnNextCall(bar);"
"bar(20, 22);";
v8::Local<v8::Value> result_value = CompileRun(js_code.c_str());
CHECK(result_value->IsNumber());
int32_t result =
ConvertJSValue<int32_t>::Get(result_value, env.local()).ToChecked();
CHECK_EQ(result, 84);
}
} // namespace compiler
} // namespace internal
} // namespace v8