25895aeeaf
We mark certain builtins for inlining, and those should always be inlined into optimized code (CrankShaft already handles it this way), so we should support that in TurboFan as well. Currently this mainly affects a certain set of Math functions, but once have the basics in place we can extend this to any kind of builtin/code stub/accessor. This adds a new flag --turbo_builtin_inlining (enabled by default), that forces the inliner to always inline builtins marked for inlining, but does not affect inlining of other functions (this is still controlled by the --turbo-inlining flag). BUG=v8:3952 LOG=n R=jarin@chromium.org Review URL: https://codereview.chromium.org/993473002 Cr-Commit-Position: refs/heads/master@{#27059}
231 lines
7.2 KiB
C++
231 lines
7.2 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.
|
|
|
|
#ifndef V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
|
|
#define V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
|
|
|
|
#include "src/v8.h"
|
|
#include "test/cctest/cctest.h"
|
|
|
|
#include "src/ast-numbering.h"
|
|
#include "src/compiler.h"
|
|
#include "src/compiler/linkage.h"
|
|
#include "src/compiler/pipeline.h"
|
|
#include "src/execution.h"
|
|
#include "src/full-codegen.h"
|
|
#include "src/handles.h"
|
|
#include "src/objects-inl.h"
|
|
#include "src/parser.h"
|
|
#include "src/rewriter.h"
|
|
#include "src/scopes.h"
|
|
|
|
#define USE_CRANKSHAFT 0
|
|
|
|
namespace v8 {
|
|
namespace internal {
|
|
namespace compiler {
|
|
|
|
class FunctionTester : public InitializedHandleScope {
|
|
public:
|
|
explicit FunctionTester(const char* source, uint32_t flags = 0)
|
|
: isolate(main_isolate()),
|
|
function((FLAG_allow_natives_syntax = true, NewFunction(source))),
|
|
flags_(flags) {
|
|
Compile(function);
|
|
const uint32_t supported_flags = CompilationInfo::kContextSpecializing |
|
|
CompilationInfo::kBuiltinInliningEnabled |
|
|
CompilationInfo::kInliningEnabled |
|
|
CompilationInfo::kTypingEnabled;
|
|
CHECK_EQ(0u, flags_ & ~supported_flags);
|
|
}
|
|
|
|
explicit FunctionTester(Graph* graph)
|
|
: isolate(main_isolate()),
|
|
function(NewFunction("(function(a,b){})")),
|
|
flags_(0) {
|
|
CompileGraph(graph);
|
|
}
|
|
|
|
Isolate* isolate;
|
|
Handle<JSFunction> function;
|
|
|
|
MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
|
|
Handle<Object> args[] = {a, b};
|
|
return Execution::Call(isolate, function, undefined(), 2, args, false);
|
|
}
|
|
|
|
void CheckThrows(Handle<Object> a, Handle<Object> b) {
|
|
TryCatch try_catch;
|
|
MaybeHandle<Object> no_result = Call(a, b);
|
|
CHECK(isolate->has_pending_exception());
|
|
CHECK(try_catch.HasCaught());
|
|
CHECK(no_result.is_null());
|
|
// TODO(mstarzinger): Temporary workaround for issue chromium:362388.
|
|
isolate->OptionalRescheduleException(true);
|
|
}
|
|
|
|
v8::Handle<v8::Message> CheckThrowsReturnMessage(Handle<Object> a,
|
|
Handle<Object> b) {
|
|
TryCatch try_catch;
|
|
MaybeHandle<Object> no_result = Call(a, b);
|
|
CHECK(isolate->has_pending_exception());
|
|
CHECK(try_catch.HasCaught());
|
|
CHECK(no_result.is_null());
|
|
// TODO(mstarzinger): Calling OptionalRescheduleException is a dirty hack,
|
|
// it's the only way to make Message() not to assert because an external
|
|
// exception has been caught by the try_catch.
|
|
isolate->OptionalRescheduleException(true);
|
|
return try_catch.Message();
|
|
}
|
|
|
|
void CheckCall(Handle<Object> expected, Handle<Object> a, Handle<Object> b) {
|
|
Handle<Object> result = Call(a, b).ToHandleChecked();
|
|
CHECK(expected->SameValue(*result));
|
|
}
|
|
|
|
void CheckCall(Handle<Object> expected, Handle<Object> a) {
|
|
CheckCall(expected, a, undefined());
|
|
}
|
|
|
|
void CheckCall(Handle<Object> expected) {
|
|
CheckCall(expected, undefined(), undefined());
|
|
}
|
|
|
|
void CheckCall(double expected, double a, double b) {
|
|
CheckCall(Val(expected), Val(a), Val(b));
|
|
}
|
|
|
|
void CheckTrue(Handle<Object> a, Handle<Object> b) {
|
|
CheckCall(true_value(), a, b);
|
|
}
|
|
|
|
void CheckTrue(Handle<Object> a) { CheckCall(true_value(), a, undefined()); }
|
|
|
|
void CheckTrue(double a, double b) {
|
|
CheckCall(true_value(), Val(a), Val(b));
|
|
}
|
|
|
|
void CheckFalse(Handle<Object> a, Handle<Object> b) {
|
|
CheckCall(false_value(), a, b);
|
|
}
|
|
|
|
void CheckFalse(Handle<Object> a) {
|
|
CheckCall(false_value(), a, undefined());
|
|
}
|
|
|
|
void CheckFalse(double a, double b) {
|
|
CheckCall(false_value(), Val(a), Val(b));
|
|
}
|
|
|
|
Handle<JSFunction> NewFunction(const char* source) {
|
|
return v8::Utils::OpenHandle(
|
|
*v8::Handle<v8::Function>::Cast(CompileRun(source)));
|
|
}
|
|
|
|
Handle<JSObject> NewObject(const char* source) {
|
|
return v8::Utils::OpenHandle(
|
|
*v8::Handle<v8::Object>::Cast(CompileRun(source)));
|
|
}
|
|
|
|
Handle<String> Val(const char* string) {
|
|
return isolate->factory()->InternalizeUtf8String(string);
|
|
}
|
|
|
|
Handle<Object> Val(double value) {
|
|
return isolate->factory()->NewNumber(value);
|
|
}
|
|
|
|
Handle<Object> infinity() { return isolate->factory()->infinity_value(); }
|
|
|
|
Handle<Object> minus_infinity() { return Val(-V8_INFINITY); }
|
|
|
|
Handle<Object> nan() { return isolate->factory()->nan_value(); }
|
|
|
|
Handle<Object> undefined() { return isolate->factory()->undefined_value(); }
|
|
|
|
Handle<Object> null() { return isolate->factory()->null_value(); }
|
|
|
|
Handle<Object> true_value() { return isolate->factory()->true_value(); }
|
|
|
|
Handle<Object> false_value() { return isolate->factory()->false_value(); }
|
|
|
|
Handle<JSFunction> Compile(Handle<JSFunction> function) {
|
|
// TODO(titzer): make this method private.
|
|
#if V8_TURBOFAN_TARGET
|
|
CompilationInfoWithZone info(function);
|
|
|
|
CHECK(Parser::ParseStatic(&info));
|
|
info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
|
|
if (flags_ & CompilationInfo::kContextSpecializing) {
|
|
info.MarkAsContextSpecializing();
|
|
}
|
|
if (flags_ & CompilationInfo::kInliningEnabled) {
|
|
info.MarkAsInliningEnabled();
|
|
}
|
|
if (flags_ & CompilationInfo::kTypingEnabled) {
|
|
info.MarkAsTypingEnabled();
|
|
}
|
|
CHECK(Compiler::Analyze(&info));
|
|
CHECK(Compiler::EnsureDeoptimizationSupport(&info));
|
|
|
|
Pipeline pipeline(&info);
|
|
Handle<Code> code = pipeline.GenerateCode();
|
|
if (FLAG_turbo_deoptimization) {
|
|
info.context()->native_context()->AddOptimizedCode(*code);
|
|
}
|
|
|
|
CHECK(!code.is_null());
|
|
function->ReplaceCode(*code);
|
|
#elif USE_CRANKSHAFT
|
|
Handle<Code> unoptimized = Handle<Code>(function->code());
|
|
Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
|
|
Compiler::NOT_CONCURRENT);
|
|
CHECK(!code.is_null());
|
|
#if ENABLE_DISASSEMBLER
|
|
if (FLAG_print_opt_code) {
|
|
CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
|
|
code->Disassemble("test code", tracing_scope.file());
|
|
}
|
|
#endif
|
|
function->ReplaceCode(*code);
|
|
#endif
|
|
return function;
|
|
}
|
|
|
|
static Handle<JSFunction> ForMachineGraph(Graph* graph) {
|
|
JSFunction* p = NULL;
|
|
{ // because of the implicit handle scope of FunctionTester.
|
|
FunctionTester f(graph);
|
|
p = *f.function;
|
|
}
|
|
return Handle<JSFunction>(p); // allocated in outer handle scope.
|
|
}
|
|
|
|
private:
|
|
uint32_t flags_;
|
|
|
|
// 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) {
|
|
CHECK(Pipeline::SupportedTarget());
|
|
CompilationInfoWithZone info(function);
|
|
|
|
CHECK(Parser::ParseStatic(&info));
|
|
info.SetOptimizing(BailoutId::None(),
|
|
Handle<Code>(function->shared()->code()));
|
|
CHECK(Compiler::Analyze(&info));
|
|
CHECK(Compiler::EnsureDeoptimizationSupport(&info));
|
|
|
|
Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
|
|
CHECK(!code.is_null());
|
|
function->ReplaceCode(*code);
|
|
return function;
|
|
}
|
|
};
|
|
}
|
|
}
|
|
} // namespace v8::internal::compiler
|
|
|
|
#endif // V8_CCTEST_COMPILER_FUNCTION_TESTER_H_
|