Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(456)

Unified Diff: test/cctest/compiler/test-codegen-deopt.cc

Issue 426233002: Land the Fan (disabled) (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Review feedback, rebase and "git cl format" Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « test/cctest/compiler/test-branch-combine.cc ('k') | test/cctest/compiler/test-gap-resolver.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: test/cctest/compiler/test-codegen-deopt.cc
diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc
new file mode 100644
index 0000000000000000000000000000000000000000..243ece901080f4a76b5b701b7dd327cc98f85cb7
--- /dev/null
+++ b/test/cctest/compiler/test-codegen-deopt.cc
@@ -0,0 +1,331 @@
+// 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)));
+}
« no previous file with comments | « test/cctest/compiler/test-branch-combine.cc ('k') | test/cctest/compiler/test-gap-resolver.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698