Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. | 5 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64. |
| 6 #if defined(TARGET_ARCH_X64) | 6 #if defined(TARGET_ARCH_X64) |
| 7 | 7 |
| 8 #include "vm/flow_graph_compiler.h" | 8 #include "vm/flow_graph_compiler.h" |
| 9 | 9 |
| 10 #include "vm/ast_printer.h" | 10 #include "vm/ast_printer.h" |
| 11 #include "vm/code_generator.h" | 11 #include "vm/code_generator.h" |
| 12 #include "vm/disassembler.h" | 12 #include "vm/disassembler.h" |
| 13 #include "vm/longjump.h" | 13 #include "vm/longjump.h" |
| 14 #include "vm/parser.h" | 14 #include "vm/parser.h" |
| 15 #include "vm/stub_code.h" | 15 #include "vm/stub_code.h" |
| 16 | 16 |
| 17 namespace dart { | 17 namespace dart { |
| 18 | 18 |
| 19 DECLARE_FLAG(bool, print_ast); | 19 DECLARE_FLAG(bool, print_ast); |
| 20 DECLARE_FLAG(bool, print_scopes); | 20 DECLARE_FLAG(bool, print_scopes); |
| 21 DECLARE_FLAG(bool, trace_functions); | 21 DECLARE_FLAG(bool, trace_functions); |
| 22 DECLARE_FLAG(bool, disassemble); | 22 DECLARE_FLAG(bool, disassemble); |
| 23 | 23 |
| 24 void FlowGraphCompiler::Bailout(const char* reason) { | 24 void FlowGraphCompiler::Bailout(const char* reason) { |
| 25 const char* kFormat = "FlowGraphCompiler Bailout: %s."; | 25 const char* kFormat = "FlowGraphCompiler Bailout: %s %s."; |
| 26 intptr_t len = OS::SNPrint(NULL, 0, kFormat, reason) + 1; | 26 const char* function_name = parsed_function_.function().ToCString(); |
| 27 intptr_t len = OS::SNPrint(NULL, 0, kFormat, function_name, reason) + 1; | |
| 27 char* chars = reinterpret_cast<char*>( | 28 char* chars = reinterpret_cast<char*>( |
| 28 Isolate::Current()->current_zone()->Allocate(len)); | 29 Isolate::Current()->current_zone()->Allocate(len)); |
| 29 OS::SNPrint(chars, len, kFormat, reason); | 30 OS::SNPrint(chars, len, kFormat, function_name, reason); |
| 30 const Error& error = Error::Handle( | 31 const Error& error = Error::Handle( |
| 31 LanguageError::New(String::Handle(String::New(chars)))); | 32 LanguageError::New(String::Handle(String::New(chars)))); |
| 32 Isolate::Current()->long_jump_base()->Jump(1, error); | 33 Isolate::Current()->long_jump_base()->Jump(1, error); |
| 33 } | 34 } |
| 34 | 35 |
| 35 | 36 |
| 36 #define __ assembler_-> | 37 #define __ assembler_-> |
| 37 | 38 |
| 38 void FlowGraphCompiler::LoadValue(Value* value) { | 39 void FlowGraphCompiler::LoadValue(Value* value) { |
| 39 if (value->IsConstant()) { | 40 if (value->IsConstant()) { |
| 40 ConstantValue* constant = value->AsConstant(); | 41 ConstantVal* constant = value->AsConstant(); |
| 41 if (constant->instance().IsSmi()) { | 42 if (constant->instance().IsSmi()) { |
| 42 int64_t imm = reinterpret_cast<int64_t>(constant->instance().raw()); | 43 int64_t imm = reinterpret_cast<int64_t>(constant->instance().raw()); |
| 43 __ movq(RAX, Immediate(imm)); | 44 __ movq(RAX, Immediate(imm)); |
| 44 } else { | 45 } else { |
| 45 __ LoadObject(RAX, value->AsConstant()->instance()); | 46 __ LoadObject(RAX, value->AsConstant()->instance()); |
| 46 } | 47 } |
| 47 } else { | 48 } else { |
| 48 ASSERT(value->IsTemp()); | 49 ASSERT(value->IsTemp()); |
| 49 Bailout("return of non-ConstantValue value"); | 50 __ popq(RAX); |
| 50 } | 51 } |
| 51 } | 52 } |
| 52 | 53 |
| 53 | 54 |
| 55 void FlowGraphCompiler::VisitTemp(TempVal* val) { | |
| 56 Bailout("TempVal"); | |
| 57 } | |
| 58 | |
| 59 | |
| 60 void FlowGraphCompiler::VisitConstant(ConstantVal* val) { | |
| 61 Bailout("ConstantVal"); | |
| 62 } | |
| 63 | |
| 64 | |
| 65 void FlowGraphCompiler::VisitAssertAssignable(AssertAssignableComp* comp) { | |
| 66 Bailout("AssertAssignableComp"); | |
| 67 } | |
| 68 | |
| 69 | |
| 70 void FlowGraphCompiler::VisitInstanceCall(InstanceCallComp* comp) { | |
| 71 Bailout("InstanceCallComp"); | |
| 72 } | |
| 73 | |
| 74 | |
| 75 void FlowGraphCompiler::VisitStrictCompare(StrictCompareComp* comp) { | |
| 76 Bailout("StrictCompareComp"); | |
| 77 } | |
| 78 | |
| 79 | |
| 80 | |
| 81 void FlowGraphCompiler::VisitStaticCall(StaticCallComp* comp) { | |
| 82 Bailout("StaticCallComp"); | |
| 83 } | |
| 84 | |
| 85 | |
| 86 void FlowGraphCompiler::VisitLoadLocal(LoadLocalComp* comp) { | |
| 87 if (comp->local().is_captured()) { | |
| 88 Bailout("load of context variable"); | |
| 89 } | |
| 90 __ movw(RAX, Address(RBP, comp->local().index() * kWordSize)); | |
|
Kevin Millikin (Google)
2012/02/27 13:40:42
Oops, movq.
| |
| 91 } | |
| 92 | |
| 93 | |
| 94 void FlowGraphCompiler::VisitStoreLocal(StoreLocalComp* comp) { | |
| 95 if (comp->local().is_captured()) { | |
| 96 Bailout("store to context variable"); | |
| 97 } | |
| 98 LoadValue(comp->value()); | |
| 99 __ movq(Address(RBP, comp->local().index() * kWordSize), RAX); | |
| 100 } | |
| 101 | |
| 102 | |
| 54 void FlowGraphCompiler::VisitJoinEntry(JoinEntryInstr* instr) { | 103 void FlowGraphCompiler::VisitJoinEntry(JoinEntryInstr* instr) { |
| 55 Bailout("JoinEntryInstr"); | 104 Bailout("JoinEntryInstr"); |
| 56 } | 105 } |
| 57 | 106 |
| 58 | 107 |
| 59 void FlowGraphCompiler::VisitTargetEntry(TargetEntryInstr* instr) { | 108 void FlowGraphCompiler::VisitTargetEntry(TargetEntryInstr* instr) { |
| 60 // Since we don't handle branching control flow yet, there is nothing to do. | 109 // Since we don't handle branching control flow yet, there is nothing to do. |
| 61 } | 110 } |
| 62 | 111 |
| 63 | 112 |
| 64 void FlowGraphCompiler::VisitDo(DoInstr* instr) { | 113 void FlowGraphCompiler::VisitDo(DoInstr* instr) { |
| 65 Bailout("DoInstr"); | 114 instr->computation()->Accept(this); |
| 66 } | 115 } |
| 67 | 116 |
| 68 | 117 |
| 69 void FlowGraphCompiler::VisitBind(BindInstr* instr) { | 118 void FlowGraphCompiler::VisitBind(BindInstr* instr) { |
| 70 Bailout("DoInstr"); | 119 instr->computation()->Accept(this); |
| 120 __ pushq(RAX); | |
| 71 } | 121 } |
| 72 | 122 |
| 73 | 123 |
| 74 void FlowGraphCompiler::VisitReturn(ReturnInstr* instr) { | 124 void FlowGraphCompiler::VisitReturn(ReturnInstr* instr) { |
| 75 LoadValue(instr->value()); | 125 LoadValue(instr->value()); |
| 76 | 126 |
| 77 #ifdef DEBUG | 127 #ifdef DEBUG |
| 78 // Check that the entry stack size matches the exit stack size. | 128 // Check that the entry stack size matches the exit stack size. |
| 79 const intptr_t locals_space_size = 0; | |
| 80 __ movq(R10, RBP); | 129 __ movq(R10, RBP); |
| 81 __ subq(R10, RSP); | 130 __ subq(R10, RSP); |
| 82 __ cmpq(R10, Immediate(locals_space_size)); | 131 __ cmpq(R10, Immediate(stack_local_count() * kWordSize)); |
| 83 Label stack_ok; | 132 Label stack_ok; |
| 84 __ j(EQUAL, &stack_ok, Assembler::kNearJump); | 133 __ j(EQUAL, &stack_ok, Assembler::kNearJump); |
| 85 __ Stop("Exit stack size does not match the entry stack size."); | 134 __ Stop("Exit stack size does not match the entry stack size."); |
| 86 __ Bind(&stack_ok); | 135 __ Bind(&stack_ok); |
| 87 #endif // DEBUG. | 136 #endif // DEBUG. |
| 88 | 137 |
| 89 if (FLAG_trace_functions) { | 138 if (FLAG_trace_functions) { |
| 90 __ pushq(RAX); // Preserve result. | 139 __ pushq(RAX); // Preserve result. |
| 91 const Function& function = | 140 const Function& function = |
| 92 Function::ZoneHandle(parsed_function_.function().raw()); | 141 Function::ZoneHandle(parsed_function_.function().raw()); |
| 93 __ LoadObject(RBX, function); | 142 __ LoadObject(RBX, function); |
| 94 __ pushq(RBX); | 143 __ pushq(RBX); |
| 95 GenerateCallRuntime(AstNode::kNoId, | 144 GenerateCallRuntime(AstNode::kNoId, |
| 96 0, | 145 0, |
| 97 kTraceFunctionExitRuntimeEntry); | 146 kTraceFunctionExitRuntimeEntry); |
| 98 __ popq(RAX); // Remove argument. | 147 __ popq(RAX); // Remove argument. |
| 99 __ popq(RAX); // Restore result. | 148 __ popq(RAX); // Restore result. |
| 100 } | 149 } |
| 101 __ LeaveFrame(); | 150 __ LeaveFrame(); |
| 102 __ ret(); | 151 __ ret(); |
| 103 } | 152 } |
| 104 | 153 |
| 105 | 154 |
| 106 void FlowGraphCompiler::VisitBranch(BranchInstr* instr) { | 155 void FlowGraphCompiler::VisitBranch(BranchInstr* instr) { |
| 107 Bailout("VisitBranch"); | 156 Bailout("BranchInstr"); |
| 108 } | 157 } |
| 109 | 158 |
| 110 | 159 |
| 111 void FlowGraphCompiler::CompileGraph() { | 160 void FlowGraphCompiler::CompileGraph() { |
| 112 const Function& function = parsed_function_.function(); | 161 const Function& function = parsed_function_.function(); |
| 113 if ((function.num_fixed_parameters() != 0) || | 162 if ((function.num_optional_parameters() != 0)) { |
| 114 (function.num_optional_parameters() != 0)) { | 163 Bailout("function has optional parameters"); |
| 115 Bailout("function has parameters"); | |
| 116 } | 164 } |
| 117 LocalScope* scope = parsed_function_.node_sequence()->scope(); | 165 LocalScope* scope = parsed_function_.node_sequence()->scope(); |
| 118 if (scope->child() != NULL) { | |
| 119 Bailout("function has local scopes"); | |
| 120 } | |
| 121 LocalScope* context_owner = NULL; | 166 LocalScope* context_owner = NULL; |
| 122 const int first_parameter_index = 1; | 167 const int parameter_count = function.num_fixed_parameters(); |
| 123 const int parameter_count = 0; | 168 const int first_parameter_index = 1 + parameter_count; |
| 124 const int first_local_index = -1; | 169 const int first_local_index = -1; |
| 125 int first_free_frame_index = | 170 int first_free_frame_index = |
| 126 scope->AllocateVariables(first_parameter_index, | 171 scope->AllocateVariables(first_parameter_index, |
| 127 parameter_count, | 172 parameter_count, |
| 128 first_local_index, | 173 first_local_index, |
| 129 scope, | 174 scope, |
| 130 &context_owner); | 175 &context_owner); |
| 131 const int local_count = first_local_index - first_free_frame_index; | 176 set_stack_local_count(first_local_index - first_free_frame_index); |
| 132 if (local_count != 0) Bailout("function has locals"); | |
| 133 | 177 |
| 134 if (blocks_->length() != 1) Bailout("more than 1 basic block"); | 178 if (blocks_->length() != 1) Bailout("more than 1 basic block"); |
| 135 | 179 |
| 136 // Specialized version of entry code from CodeGenerator::GenerateEntryCode. | 180 // Specialized version of entry code from CodeGenerator::GenerateEntryCode. |
| 137 __ EnterFrame(0); | 181 __ EnterFrame(stack_local_count() * kWordSize); |
| 138 #ifdef DEBUG | 182 #ifdef DEBUG |
| 139 const bool check_arguments = true; | 183 const bool check_arguments = true; |
| 140 #else | 184 #else |
| 141 const bool check_arguments = function.IsClosureFunction(); | 185 const bool check_arguments = function.IsClosureFunction(); |
| 142 #endif | 186 #endif |
| 143 if (check_arguments) { | 187 if (check_arguments) { |
| 144 // Check that num_fixed <= argc <= num_params. | 188 // Check that num_fixed <= argc <= num_params. |
| 145 Label argc_in_range; | 189 Label argc_in_range; |
| 146 // Total number of args is the first Smi in args descriptor array (R10). | 190 // Total number of args is the first Smi in args descriptor array (R10). |
| 147 __ movq(RAX, FieldAddress(R10, Array::data_offset())); | 191 __ movq(RAX, FieldAddress(R10, Array::data_offset())); |
| 148 __ cmpq(RAX, Immediate(Smi::RawValue(0))); | 192 __ cmpq(RAX, Immediate(Smi::RawValue(0))); |
| 149 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); | 193 __ j(EQUAL, &argc_in_range, Assembler::kNearJump); |
| 150 if (function.IsClosureFunction()) { | 194 if (function.IsClosureFunction()) { |
| 151 GenerateCallRuntime(AstNode::kNoId, | 195 GenerateCallRuntime(AstNode::kNoId, |
| 152 function.token_index(), | 196 function.token_index(), |
| 153 kClosureArgumentMismatchRuntimeEntry); | 197 kClosureArgumentMismatchRuntimeEntry); |
| 154 } else { | 198 } else { |
| 155 __ Stop("Wrong number of arguments"); | 199 __ Stop("Wrong number of arguments"); |
| 156 } | 200 } |
| 157 __ Bind(&argc_in_range); | 201 __ Bind(&argc_in_range); |
| 158 } | 202 } |
| 203 | |
| 204 // Initialize locals to null. | |
| 205 if (stack_local_count() > 0) { | |
| 206 __ movq(RAX, Immediate(reinterpret_cast<intptr_t>(Object::null()))); | |
| 207 for (int i = 0; i < stack_local_count(); ++i) { | |
| 208 // Subtract index i (locals lie at lower addresses than RBP). | |
| 209 __ movq(Address(RBP, (first_local_index - i) * kWordSize), RAX); | |
| 210 } | |
| 211 } | |
| 212 | |
| 159 // Generate stack overflow check. | 213 // Generate stack overflow check. |
| 160 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address())); | 214 __ movq(TMP, Immediate(Isolate::Current()->stack_limit_address())); |
| 161 __ cmpq(RSP, Address(TMP, 0)); | 215 __ cmpq(RSP, Address(TMP, 0)); |
| 162 Label no_stack_overflow; | 216 Label no_stack_overflow; |
| 163 __ j(ABOVE, &no_stack_overflow); | 217 __ j(ABOVE, &no_stack_overflow, Assembler::kNearJump); |
|
Kevin Millikin (Google)
2012/02/27 13:40:42
I did not make this change (to shorten the encodin
| |
| 164 GenerateCallRuntime(AstNode::kNoId, | 218 GenerateCallRuntime(AstNode::kNoId, |
| 165 function.token_index(), | 219 function.token_index(), |
| 166 kStackOverflowRuntimeEntry); | 220 kStackOverflowRuntimeEntry); |
| 167 __ Bind(&no_stack_overflow); | 221 __ Bind(&no_stack_overflow); |
| 168 | 222 |
| 169 if (FLAG_print_scopes) { | 223 if (FLAG_print_scopes) { |
| 170 // Print the function scope (again) after generating the prologue in order | 224 // Print the function scope (again) after generating the prologue in order |
| 171 // to see annotations such as allocation indices of locals. | 225 // to see annotations such as allocation indices of locals. |
| 172 if (FLAG_print_ast) { | 226 if (FLAG_print_ast) { |
| 173 // Second printing. | 227 // Second printing. |
| (...skipping 44 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 218 assembler_->CodeSize(), | 272 assembler_->CodeSize(), |
| 219 node_id, | 273 node_id, |
| 220 token_index, | 274 token_index, |
| 221 CatchClauseNode::kInvalidTryIndex); | 275 CatchClauseNode::kInvalidTryIndex); |
| 222 } | 276 } |
| 223 | 277 |
| 224 | 278 |
| 225 } // namespace dart | 279 } // namespace dart |
| 226 | 280 |
| 227 #endif // defined TARGET_ARCH_X64 | 281 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |