| Index: test/cctest/compiler/compiler/test-codegen-deopt.cc
|
| diff --git a/test/cctest/compiler/compiler/test-codegen-deopt.cc b/test/cctest/compiler/compiler/test-codegen-deopt.cc
|
| deleted file mode 100644
|
| index 243ece901080f4a76b5b701b7dd327cc98f85cb7..0000000000000000000000000000000000000000
|
| --- a/test/cctest/compiler/compiler/test-codegen-deopt.cc
|
| +++ /dev/null
|
| @@ -1,331 +0,0 @@
|
| -// 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 "src/v8.h"
|
| -#include "test/cctest/cctest.h"
|
| -
|
| -#include "src/compiler/code-generator.h"
|
| -#include "src/compiler/common-operator.h"
|
| -#include "src/compiler/graph.h"
|
| -#include "src/compiler/instruction-selector.h"
|
| -#include "src/compiler/machine-operator.h"
|
| -#include "src/compiler/node.h"
|
| -#include "src/compiler/operator.h"
|
| -#include "src/compiler/raw-machine-assembler.h"
|
| -#include "src/compiler/register-allocator.h"
|
| -#include "src/compiler/schedule.h"
|
| -
|
| -#include "src/full-codegen.h"
|
| -#include "src/parser.h"
|
| -#include "src/rewriter.h"
|
| -
|
| -#include "test/cctest/compiler/function-tester.h"
|
| -
|
| -using namespace v8::internal;
|
| -using namespace v8::internal::compiler;
|
| -
|
| -typedef RawMachineAssembler::Label MLabel;
|
| -
|
| -static Handle<JSFunction> NewFunction(const char* source) {
|
| - return v8::Utils::OpenHandle(
|
| - *v8::Handle<v8::Function>::Cast(CompileRun(source)));
|
| -}
|
| -
|
| -
|
| -class DeoptCodegenTester {
|
| - public:
|
| - explicit DeoptCodegenTester(HandleAndZoneScope* scope, const char* src)
|
| - : scope_(scope),
|
| - function(NewFunction(src)),
|
| - info(function, scope->main_zone()),
|
| - bailout_id(-1) {
|
| - CHECK(Parser::Parse(&info));
|
| - StrictMode strict_mode = info.function()->strict_mode();
|
| - info.SetStrictMode(strict_mode);
|
| - info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
|
| - CHECK(Rewriter::Rewrite(&info));
|
| - CHECK(Scope::Analyze(&info));
|
| - CHECK_NE(NULL, info.scope());
|
| -
|
| - FunctionTester::EnsureDeoptimizationSupport(&info);
|
| -
|
| - ASSERT(info.shared_info()->has_deoptimization_support());
|
| -
|
| - graph = new (scope_->main_zone()) Graph(scope_->main_zone());
|
| - }
|
| -
|
| - virtual ~DeoptCodegenTester() { delete code; }
|
| -
|
| - void GenerateCodeFromSchedule(Schedule* schedule) {
|
| - OFStream os(stdout);
|
| - os << *schedule;
|
| -
|
| - // Initialize the codegen and generate code.
|
| - Linkage* linkage = new (scope_->main_zone()) Linkage(&info);
|
| - code = new v8::internal::compiler::InstructionSequence(linkage, graph,
|
| - schedule);
|
| - SourcePositionTable source_positions(graph);
|
| - InstructionSelector selector(code, &source_positions);
|
| - selector.SelectInstructions();
|
| -
|
| - os << "----- Instruction sequence before register allocation -----\n"
|
| - << *code;
|
| -
|
| - RegisterAllocator allocator(code);
|
| - CHECK(allocator.Allocate());
|
| -
|
| - os << "----- Instruction sequence after register allocation -----\n"
|
| - << *code;
|
| -
|
| - compiler::CodeGenerator generator(code);
|
| - result_code = generator.GenerateCode();
|
| -
|
| -#ifdef DEBUG
|
| - result_code->Print();
|
| -#endif
|
| - }
|
| -
|
| - Zone* zone() { return scope_->main_zone(); }
|
| -
|
| - HandleAndZoneScope* scope_;
|
| - Handle<JSFunction> function;
|
| - CompilationInfo info;
|
| - BailoutId bailout_id;
|
| - Handle<Code> result_code;
|
| - v8::internal::compiler::InstructionSequence* code;
|
| - Graph* graph;
|
| -};
|
| -
|
| -
|
| -class TrivialDeoptCodegenTester : public DeoptCodegenTester {
|
| - public:
|
| - explicit TrivialDeoptCodegenTester(HandleAndZoneScope* scope)
|
| - : DeoptCodegenTester(scope,
|
| - "function foo() { deopt(); return 42; }; foo") {}
|
| -
|
| - void GenerateCode() {
|
| - GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
|
| - }
|
| -
|
| - Schedule* BuildGraphAndSchedule(Graph* graph) {
|
| - Isolate* isolate = info.isolate();
|
| - CommonOperatorBuilder common(zone());
|
| -
|
| - // Manually construct a schedule for the function below:
|
| - // function foo() {
|
| - // deopt();
|
| - // }
|
| -
|
| - MachineRepresentation parameter_reps[] = {kMachineTagged};
|
| - MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 1,
|
| - parameter_reps);
|
| -
|
| - RawMachineAssembler m(graph, &descriptor_builder);
|
| -
|
| - Handle<Object> undef_object =
|
| - Handle<Object>(isolate->heap()->undefined_value(), isolate);
|
| - PrintableUnique<Object> undef_constant =
|
| - PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
|
| - Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
|
| -
|
| - Handle<JSFunction> deopt_function =
|
| - NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
|
| - PrintableUnique<Object> deopt_fun_constant =
|
| - PrintableUnique<Object>::CreateUninitialized(zone(), deopt_function);
|
| - Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
|
| -
|
| - MLabel deopt, cont;
|
| - Node* call = m.CallJS0(deopt_fun_node, undef_node, &cont, &deopt);
|
| -
|
| - m.Bind(&cont);
|
| - m.NewNode(common.Continuation(), call);
|
| - m.Return(undef_node);
|
| -
|
| - m.Bind(&deopt);
|
| - m.NewNode(common.LazyDeoptimization(), call);
|
| -
|
| - bailout_id = GetCallBailoutId();
|
| - FrameStateDescriptor stateDescriptor(bailout_id);
|
| - Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
|
| - m.Deoptimize(state_node);
|
| -
|
| - // Schedule the graph:
|
| - Schedule* schedule = m.Export();
|
| -
|
| - cont_block = cont.block();
|
| - deopt_block = deopt.block();
|
| -
|
| - return schedule;
|
| - }
|
| -
|
| - BailoutId GetCallBailoutId() {
|
| - ZoneList<Statement*>* body = info.function()->body();
|
| - for (int i = 0; i < body->length(); i++) {
|
| - if (body->at(i)->IsExpressionStatement() &&
|
| - body->at(i)->AsExpressionStatement()->expression()->IsCall()) {
|
| - return body->at(i)->AsExpressionStatement()->expression()->id();
|
| - }
|
| - }
|
| - CHECK(false);
|
| - return BailoutId(-1);
|
| - }
|
| -
|
| - BasicBlock* cont_block;
|
| - BasicBlock* deopt_block;
|
| -};
|
| -
|
| -
|
| -TEST(TurboTrivialDeoptCodegen) {
|
| - HandleAndZoneScope scope;
|
| - InitializedHandleScope handles;
|
| -
|
| - FLAG_allow_natives_syntax = true;
|
| - FLAG_turbo_deoptimization = true;
|
| -
|
| - TrivialDeoptCodegenTester t(&scope);
|
| - t.GenerateCode();
|
| -
|
| - DeoptimizationInputData* data =
|
| - DeoptimizationInputData::cast(t.result_code->deoptimization_data());
|
| -
|
| - Label* cont_label = t.code->GetLabel(t.cont_block);
|
| - Label* deopt_label = t.code->GetLabel(t.deopt_block);
|
| -
|
| - // Check the patch table. It should patch the continuation address to the
|
| - // deoptimization block address.
|
| - CHECK_EQ(1, data->ReturnAddressPatchCount());
|
| - CHECK_EQ(cont_label->pos(), data->ReturnAddressPc(0)->value());
|
| - CHECK_EQ(deopt_label->pos(), data->PatchedAddressPc(0)->value());
|
| -
|
| - // Check that we deoptimize to the right AST id.
|
| - CHECK_EQ(1, data->DeoptCount());
|
| - CHECK_EQ(1, data->DeoptCount());
|
| - CHECK_EQ(t.bailout_id.ToInt(), data->AstId(0).ToInt());
|
| -}
|
| -
|
| -
|
| -TEST(TurboTrivialDeoptCodegenAndRun) {
|
| - HandleAndZoneScope scope;
|
| - InitializedHandleScope handles;
|
| -
|
| - FLAG_allow_natives_syntax = true;
|
| - FLAG_turbo_deoptimization = true;
|
| -
|
| - TrivialDeoptCodegenTester t(&scope);
|
| - t.GenerateCode();
|
| -
|
| - t.function->ReplaceCode(*t.result_code);
|
| - t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
|
| -
|
| - Isolate* isolate = scope.main_isolate();
|
| - Handle<Object> result;
|
| - bool has_pending_exception =
|
| - !Execution::Call(isolate, t.function,
|
| - isolate->factory()->undefined_value(), 0, NULL,
|
| - false).ToHandle(&result);
|
| - CHECK(!has_pending_exception);
|
| - CHECK(result->SameValue(Smi::FromInt(42)));
|
| -}
|
| -
|
| -
|
| -class TrivialRuntimeDeoptCodegenTester : public DeoptCodegenTester {
|
| - public:
|
| - explicit TrivialRuntimeDeoptCodegenTester(HandleAndZoneScope* scope)
|
| - : DeoptCodegenTester(
|
| - scope,
|
| - "function foo() { %DeoptimizeFunction(foo); return 42; }; foo") {}
|
| -
|
| - void GenerateCode() {
|
| - GenerateCodeFromSchedule(BuildGraphAndSchedule(graph));
|
| - }
|
| -
|
| - Schedule* BuildGraphAndSchedule(Graph* graph) {
|
| - Isolate* isolate = info.isolate();
|
| - CommonOperatorBuilder common(zone());
|
| -
|
| - // Manually construct a schedule for the function below:
|
| - // function foo() {
|
| - // %DeoptimizeFunction(foo);
|
| - // }
|
| -
|
| - MachineRepresentation parameter_reps[] = {kMachineTagged};
|
| - MachineCallDescriptorBuilder descriptor_builder(kMachineTagged, 2,
|
| - parameter_reps);
|
| -
|
| - RawMachineAssembler m(graph, &descriptor_builder);
|
| -
|
| - Handle<Object> undef_object =
|
| - Handle<Object>(isolate->heap()->undefined_value(), isolate);
|
| - PrintableUnique<Object> undef_constant =
|
| - PrintableUnique<Object>::CreateUninitialized(zone(), undef_object);
|
| - Node* undef_node = m.NewNode(common.HeapConstant(undef_constant));
|
| -
|
| - PrintableUnique<Object> this_fun_constant =
|
| - PrintableUnique<Object>::CreateUninitialized(zone(), function);
|
| - Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
|
| -
|
| - MLabel deopt, cont;
|
| - Node* call = m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node,
|
| - &cont, &deopt);
|
| -
|
| - m.Bind(&cont);
|
| - m.NewNode(common.Continuation(), call);
|
| - m.Return(undef_node);
|
| -
|
| - m.Bind(&deopt);
|
| - m.NewNode(common.LazyDeoptimization(), call);
|
| -
|
| - bailout_id = GetCallBailoutId();
|
| - FrameStateDescriptor stateDescriptor(bailout_id);
|
| - Node* state_node = m.NewNode(common.FrameState(stateDescriptor));
|
| - m.Deoptimize(state_node);
|
| -
|
| - // Schedule the graph:
|
| - Schedule* schedule = m.Export();
|
| -
|
| - cont_block = cont.block();
|
| - deopt_block = deopt.block();
|
| -
|
| - return schedule;
|
| - }
|
| -
|
| - BailoutId GetCallBailoutId() {
|
| - ZoneList<Statement*>* body = info.function()->body();
|
| - for (int i = 0; i < body->length(); i++) {
|
| - if (body->at(i)->IsExpressionStatement() &&
|
| - body->at(i)->AsExpressionStatement()->expression()->IsCallRuntime()) {
|
| - return body->at(i)->AsExpressionStatement()->expression()->id();
|
| - }
|
| - }
|
| - CHECK(false);
|
| - return BailoutId(-1);
|
| - }
|
| -
|
| - BasicBlock* cont_block;
|
| - BasicBlock* deopt_block;
|
| -};
|
| -
|
| -
|
| -TEST(TurboTrivialRuntimeDeoptCodegenAndRun) {
|
| - HandleAndZoneScope scope;
|
| - InitializedHandleScope handles;
|
| -
|
| - FLAG_allow_natives_syntax = true;
|
| - FLAG_turbo_deoptimization = true;
|
| -
|
| - TrivialRuntimeDeoptCodegenTester t(&scope);
|
| - t.GenerateCode();
|
| -
|
| - t.function->ReplaceCode(*t.result_code);
|
| - t.info.context()->native_context()->AddOptimizedCode(*t.result_code);
|
| -
|
| - Isolate* isolate = scope.main_isolate();
|
| - Handle<Object> result;
|
| - bool has_pending_exception =
|
| - !Execution::Call(isolate, t.function,
|
| - isolate->factory()->undefined_value(), 0, NULL,
|
| - false).ToHandle(&result);
|
| - CHECK(!has_pending_exception);
|
| - CHECK(result->SameValue(Smi::FromInt(42)));
|
| -}
|
|
|