be6990457b
Code objects are exposed through JSFunction and SharedFunctionInfo. If they are builtins, we don't have to worry about background threads seeing partially initialized code objects. If they are optimized code objects, we may. Background threads read the code fields with AcquireLoad semantics. The fields are set on the main thread with ReleaseStore semantics when appropriate. Special care is taken when setting an optimized code object in a closure in the interpreter entry stub. Since the MacroAssembler doesn't support ReleaseStore semantics, this CL ensures that the optimized code object is stored with those semantics in the feedback vector, where the interpreter entry stub finds it. Bug: v8:7790 Change-Id: I41ecedfe0e9d1ad5091cbe9a97f66c66ca9e07dd Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2676633 Commit-Queue: Michael Stanton <mvstanton@chromium.org> Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Santiago Aboy Solanes <solanes@chromium.org> Reviewed-by: Leszek Swirski <leszeks@chromium.org> Reviewed-by: Georg Neis <neis@chromium.org> Cr-Commit-Position: refs/heads/master@{#72869}
168 lines
5.5 KiB
C++
168 lines
5.5 KiB
C++
// 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/cctest/compiler/function-tester.h"
|
|
|
|
#include "src/api/api-inl.h"
|
|
#include "src/codegen/assembler.h"
|
|
#include "src/codegen/optimized-compilation-info.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"
|
|
#include "test/cctest/cctest.h"
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
FunctionTester::FunctionTester(const char* source, uint32_t flags)
|
|
: isolate(main_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(Graph* graph, int param_count)
|
|
: isolate(main_isolate()),
|
|
canonical(isolate),
|
|
function(NewFunction(BuildFunction(param_count).c_str())),
|
|
flags_(0) {
|
|
CompileGraph(graph);
|
|
}
|
|
|
|
FunctionTester::FunctionTester(Handle<Code> code, int param_count)
|
|
: isolate(main_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(*code, kReleaseStore);
|
|
}
|
|
|
|
FunctionTester::FunctionTester(Handle<Code> code) : FunctionTester(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(source))));
|
|
}
|
|
|
|
Handle<JSObject> FunctionTester::NewObject(const char* source) {
|
|
return Handle<JSObject>::cast(
|
|
v8::Utils::OpenHandle(*v8::Local<v8::Object>::Cast(CompileRun(source))));
|
|
}
|
|
|
|
Handle<String> FunctionTester::Val(const char* string) {
|
|
return isolate->factory()->InternalizeUtf8String(string);
|
|
}
|
|
|
|
Handle<Object> FunctionTester::Val(double value) {
|
|
return isolate->factory()->NewNumber(value);
|
|
}
|
|
|
|
Handle<Object> FunctionTester::infinity() {
|
|
return isolate->factory()->infinity_value();
|
|
}
|
|
|
|
Handle<Object> FunctionTester::minus_infinity() { return Val(-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::ForMachineGraph(Graph* graph,
|
|
int param_count) {
|
|
JSFunction p;
|
|
{ // because of the implicit handle scope of FunctionTester.
|
|
FunctionTester f(graph, param_count);
|
|
p = *f.function;
|
|
}
|
|
return Handle<JSFunction>(
|
|
p, p.GetIsolate()); // allocated in outer handle scope.
|
|
}
|
|
|
|
Handle<JSFunction> FunctionTester::Compile(Handle<JSFunction> function) {
|
|
Zone zone(isolate->allocator(), ZONE_NAME);
|
|
return Optimize(function, &zone, isolate, 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;
|
|
}
|
|
|
|
} // namespace compiler
|
|
} // namespace internal
|
|
} // namespace v8
|