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/flow_graph_builder.h" | 5 #include "vm/flow_graph_builder.h" |
6 | 6 |
7 #include "lib/invocation_mirror.h" | 7 #include "lib/invocation_mirror.h" |
8 #include "vm/ast_printer.h" | 8 #include "vm/ast_printer.h" |
9 #include "vm/bit_vector.h" | 9 #include "vm/bit_vector.h" |
10 #include "vm/class_finalizer.h" | 10 #include "vm/class_finalizer.h" |
(...skipping 2207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
2218 | 2218 |
2219 void EffectGraphVisitor::VisitClosureNode(ClosureNode* node) { | 2219 void EffectGraphVisitor::VisitClosureNode(ClosureNode* node) { |
2220 const Function& function = node->function(); | 2220 const Function& function = node->function(); |
2221 | 2221 |
2222 if (function.IsImplicitStaticClosureFunction()) { | 2222 if (function.IsImplicitStaticClosureFunction()) { |
2223 const Instance& closure = | 2223 const Instance& closure = |
2224 Instance::ZoneHandle(function.ImplicitStaticClosure()); | 2224 Instance::ZoneHandle(function.ImplicitStaticClosure()); |
2225 ReturnDefinition(new ConstantInstr(closure)); | 2225 ReturnDefinition(new ConstantInstr(closure)); |
2226 return; | 2226 return; |
2227 } | 2227 } |
2228 if (function.IsNonImplicitClosureFunction()) { | 2228 const bool is_implicit = function.IsImplicitInstanceClosureFunction(); |
2229 // The context scope may have already been set by the non-optimizing | 2229 ASSERT(is_implicit || function.IsNonImplicitClosureFunction()); |
2230 // compiler. If it was not, set it here. | 2230 // The context scope may have already been set by the non-optimizing |
2231 if (function.context_scope() == ContextScope::null()) { | 2231 // compiler. If it was not, set it here. |
2232 const ContextScope& context_scope = ContextScope::ZoneHandle( | 2232 if (function.context_scope() == ContextScope::null()) { |
2233 node->scope()->PreserveOuterScope(owner()->context_level())); | 2233 ASSERT(!is_implicit); |
2234 ASSERT(!function.HasCode()); | 2234 const ContextScope& context_scope = ContextScope::ZoneHandle( |
2235 ASSERT(function.context_scope() == ContextScope::null()); | 2235 node->scope()->PreserveOuterScope(owner()->context_level())); |
2236 function.set_context_scope(context_scope); | 2236 ASSERT(!function.HasCode()); |
2237 const Class& cls = Class::Handle( | 2237 ASSERT(function.context_scope() == ContextScope::null()); |
2238 owner()->parsed_function()->function().Owner()); | 2238 function.set_context_scope(context_scope); |
2239 // The closure is now properly setup, add it to the lookup table. | 2239 const Class& cls = Class::Handle( |
2240 owner()->parsed_function()->function().Owner()); | |
2241 // The closure is now properly setup, add it to the lookup table. | |
2240 #if DEBUG | 2242 #if DEBUG |
2241 const Function& found_func = Function::Handle( | 2243 const Function& found_func = Function::Handle( |
2242 cls.LookupClosureFunction(function.token_pos())); | 2244 cls.LookupClosureFunction(function.token_pos())); |
2243 ASSERT(found_func.IsNull() || | 2245 ASSERT(found_func.IsNull() || |
2244 (found_func.token_pos() != function.token_pos()) || | 2246 (found_func.token_pos() != function.token_pos()) || |
2245 // TODO(hausner): The following check should not be necessary. | 2247 // TODO(hausner): The following check should not be necessary. |
2246 // Since we only lookup based on the token_pos we can get | 2248 // Since we only lookup based on the token_pos we can get |
2247 // duplicate entries due to closurized and non-closurized parent | 2249 // duplicate entries due to closurized and non-closurized parent |
2248 // functions (see Parser::ParseFunctionStatement). | 2250 // functions (see Parser::ParseFunctionStatement). |
2249 // We need two ways to lookup in this cache: One way to cache the | 2251 // We need two ways to lookup in this cache: One way to cache the |
2250 // appropriate closure function and one way to find the functions | 2252 // appropriate closure function and one way to find the functions |
2251 // while debugging (we might need to set breakpoints in multiple | 2253 // while debugging (we might need to set breakpoints in multiple |
2252 // different function for a single token index.) | 2254 // different function for a single token index.) |
2253 (found_func.parent_function() != function.parent_function())); | 2255 (found_func.parent_function() != function.parent_function())); |
2254 #endif // DEBUG | 2256 #endif // DEBUG |
2255 cls.AddClosureFunction(function); | 2257 cls.AddClosureFunction(function); |
2256 } | 2258 } |
2257 ZoneGrowableArray<PushArgumentInstr*>* arguments = | 2259 ZoneGrowableArray<PushArgumentInstr*>* arguments = |
2258 new ZoneGrowableArray<PushArgumentInstr*>(2); | 2260 new ZoneGrowableArray<PushArgumentInstr*>(1); |
2259 ASSERT(function.context_scope() != ContextScope::null()); | 2261 ASSERT(function.context_scope() != ContextScope::null()); |
2260 | 2262 |
2261 // The function type of a closure may have type arguments. In that case, | 2263 // The function type of a closure may have type arguments. In that case, |
2262 // pass the type arguments of the instantiator. | 2264 // pass the type arguments of the instantiator. |
2263 const Class& cls = Class::ZoneHandle(function.signature_class()); | 2265 const Class& cls = Class::ZoneHandle(function.signature_class()); |
2264 ASSERT(!cls.IsNull()); | 2266 ASSERT(!cls.IsNull()); |
2265 const bool requires_type_arguments = cls.NumTypeArguments() > 0; | 2267 const bool requires_type_arguments = cls.NumTypeArguments() > 0; |
2266 Value* type_arguments = NULL; | 2268 Value* type_arguments = NULL; |
2267 if (requires_type_arguments) { | 2269 if (requires_type_arguments) { |
2268 ASSERT(cls.type_arguments_field_offset() == | 2270 ASSERT(cls.type_arguments_field_offset() == |
2269 Closure::type_arguments_offset()); | 2271 Closure::type_arguments_offset()); |
2270 const Class& instantiator_class = Class::Handle( | 2272 ASSERT(cls.instance_size() == Closure::InstanceSize()); |
2271 owner()->parsed_function()->function().Owner()); | 2273 const Class& instantiator_class = Class::Handle( |
2272 type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), | 2274 owner()->parsed_function()->function().Owner()); |
2273 instantiator_class, | 2275 type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), |
2274 NULL); | 2276 instantiator_class, |
2275 arguments->Add(PushArgument(type_arguments)); | 2277 NULL); |
2276 } | 2278 arguments->Add(PushArgument(type_arguments)); |
2277 AllocateObjectInstr* alloc = new AllocateObjectInstr(node->token_pos(), | 2279 } |
2278 cls, | 2280 AllocateObjectInstr* alloc = new AllocateObjectInstr(node->token_pos(), |
2279 arguments); | 2281 cls, |
2280 alloc->set_closure_function(function); | 2282 arguments); |
2283 alloc->set_closure_function(function); | |
2281 | 2284 |
2282 // Create fake fields for function and context. Only the context field is | 2285 // Create fake fields for function and context. Only the context field is |
2283 // stored at the allocation to be used later when inlining a closure call. | 2286 // stored at the allocation to be used later when inlining a closure call. |
2284 const Field& function_field = | 2287 const Field& function_field = |
Ivan Posva
2014/02/26 05:16:02
In a separate CL we should make these singletons i
Florian Schneider
2014/02/26 11:46:07
I would just allocate one instance per compilation
Ivan Posva
2014/02/27 18:12:34
Florian, the code below is technically wrong. The
| |
2285 Field::ZoneHandle( | 2288 Field::ZoneHandle( |
2286 Field::New(Symbols::ClosureFunctionField(), | 2289 Field::New(Symbols::ClosureFunctionField(), |
2287 false, // !static | 2290 false, // !static |
2288 false, // !final | 2291 false, // !final |
2289 false, // !const | 2292 false, // !const |
2290 alloc->cls(), | 2293 alloc->cls(), |
2291 0)); // No token position. | 2294 0)); // No token position. |
2292 function_field.SetOffset(Closure::function_offset()); | 2295 function_field.SetOffset(Closure::function_offset()); |
2293 const Field& context_field = | 2296 const Field& context_field = |
2294 Field::ZoneHandle(Field::New( | 2297 Field::ZoneHandle(Field::New( |
2295 Symbols::ClosureContextField(), | 2298 Symbols::ClosureContextField(), |
2296 false, // !static | 2299 false, // !static |
2297 false, // !final | 2300 false, // !final |
2298 false, // !const | 2301 false, // !const |
2299 alloc->cls(), | 2302 alloc->cls(), |
2300 0)); // No token position. | 2303 0)); // No token position. |
2301 context_field.SetOffset(Closure::context_offset()); | 2304 context_field.SetOffset(Closure::context_offset()); |
2302 alloc->set_context_field(context_field); | 2305 alloc->set_context_field(context_field); |
2303 | 2306 |
2304 Value* closure_val = Bind(alloc); | 2307 Value* closure_val = Bind(alloc); |
2305 { LocalVariable* tmp_var = EnterTempLocalScope(closure_val); | 2308 { LocalVariable* closure_tmp_var = EnterTempLocalScope(closure_val); |
2306 // Store function. | 2309 // Store function. |
2307 Value* tmp_val = Bind(new LoadLocalInstr(*tmp_var)); | 2310 Value* closure_tmp_val = Bind(new LoadLocalInstr(*closure_tmp_var)); |
2308 Value* func_val = | 2311 Value* func_val = |
2309 Bind(new ConstantInstr(Function::ZoneHandle(function.raw()))); | 2312 Bind(new ConstantInstr(Function::ZoneHandle(function.raw()))); |
2310 Do(new StoreInstanceFieldInstr(function_field, | 2313 Do(new StoreInstanceFieldInstr(function_field, |
2311 tmp_val, | 2314 closure_tmp_val, |
2312 func_val, | 2315 func_val, |
2313 kEmitStoreBarrier)); | 2316 kEmitStoreBarrier)); |
2314 // Store current context. | 2317 if (is_implicit) { |
2315 tmp_val = Bind(new LoadLocalInstr(*tmp_var)); | 2318 // Create new context containing the receiver. |
2319 const intptr_t kNumContextVariables = 1; // The receiver. | |
2320 Value* allocated_context = | |
2321 Bind(new AllocateContextInstr(node->token_pos(), | |
2322 kNumContextVariables)); | |
2323 { LocalVariable* context_tmp_var = EnterTempLocalScope(allocated_context); | |
2324 // First operand (receiver). | |
2325 ValueGraphVisitor for_receiver(owner()); | |
2326 node->receiver()->Visit(&for_receiver); | |
2327 Append(for_receiver); | |
2328 Value* receiver = for_receiver.value(); | |
2329 | |
2330 // Second operand (context). | |
2331 Value* context_tmp_val = Bind(new LoadLocalInstr(*context_tmp_var)); | |
2332 | |
2333 // Store receiver in context. | |
2334 Do(new StoreVMFieldInstr(context_tmp_val, | |
2335 Context::variable_offset(0), | |
2336 receiver, | |
2337 Type::ZoneHandle())); | |
2338 // Store new context in closure. | |
2339 closure_tmp_val = Bind(new LoadLocalInstr(*closure_tmp_var)); | |
2340 context_tmp_val = Bind(new LoadLocalInstr(*context_tmp_var)); | |
2341 Do(new StoreInstanceFieldInstr(context_field, | |
2342 closure_tmp_val, | |
2343 context_tmp_val, | |
2344 kEmitStoreBarrier)); | |
2345 Do(ExitTempLocalScope(context_tmp_var)); | |
2346 } | |
2347 } else { | |
2348 // Store current context in closure. | |
2349 closure_tmp_val = Bind(new LoadLocalInstr(*closure_tmp_var)); | |
2316 Value* context = Bind(new CurrentContextInstr()); | 2350 Value* context = Bind(new CurrentContextInstr()); |
2317 Do(new StoreInstanceFieldInstr(context_field, | 2351 Do(new StoreInstanceFieldInstr(context_field, |
2318 tmp_val, | 2352 closure_tmp_val, |
2319 context, | 2353 context, |
2320 kEmitStoreBarrier)); | 2354 kEmitStoreBarrier)); |
2321 ReturnDefinition(ExitTempLocalScope(tmp_var)); | |
2322 } | 2355 } |
2323 } else { | 2356 ReturnDefinition(ExitTempLocalScope(closure_tmp_var)); |
2324 ASSERT(function.IsImplicitInstanceClosureFunction()); | |
2325 ValueGraphVisitor for_receiver(owner()); | |
2326 node->receiver()->Visit(&for_receiver); | |
2327 Append(for_receiver); | |
2328 Value* receiver = for_receiver.value(); | |
2329 | |
2330 PushArgumentInstr* push_receiver = PushArgument(receiver); | |
2331 ZoneGrowableArray<PushArgumentInstr*>* arguments = | |
2332 new ZoneGrowableArray<PushArgumentInstr*>(2); | |
2333 arguments->Add(push_receiver); | |
2334 ASSERT(function.context_scope() != ContextScope::null()); | |
2335 | |
2336 // The function type of a closure may have type arguments. In that case, | |
2337 // pass the type arguments of the instantiator. Otherwise, pass null object. | |
2338 const Class& cls = Class::Handle(function.signature_class()); | |
2339 ASSERT(!cls.IsNull()); | |
2340 const bool requires_type_arguments = cls.NumTypeArguments() > 0; | |
2341 Value* type_arguments = NULL; | |
2342 if (requires_type_arguments) { | |
2343 const Class& instantiator_class = Class::Handle( | |
2344 owner()->parsed_function()->function().Owner()); | |
2345 type_arguments = BuildInstantiatorTypeArguments(node->token_pos(), | |
2346 instantiator_class, | |
2347 NULL); | |
2348 } else { | |
2349 type_arguments = BuildNullValue(); | |
2350 } | |
2351 PushArgumentInstr* push_type_arguments = PushArgument(type_arguments); | |
2352 arguments->Add(push_type_arguments); | |
2353 ReturnDefinition( | |
2354 new CreateClosureInstr(node->function(), arguments, node->token_pos())); | |
2355 } | 2357 } |
2356 } | 2358 } |
2357 | 2359 |
2358 | 2360 |
2359 void EffectGraphVisitor::BuildPushArguments( | 2361 void EffectGraphVisitor::BuildPushArguments( |
2360 const ArgumentListNode& node, | 2362 const ArgumentListNode& node, |
2361 ZoneGrowableArray<PushArgumentInstr*>* values) { | 2363 ZoneGrowableArray<PushArgumentInstr*>* values) { |
2362 for (intptr_t i = 0; i < node.length(); ++i) { | 2364 for (intptr_t i = 0; i < node.length(); ++i) { |
2363 ValueGraphVisitor for_argument(owner()); | 2365 ValueGraphVisitor for_argument(owner()); |
2364 node.NodeAt(i)->Visit(&for_argument); | 2366 node.NodeAt(i)->Visit(&for_argument); |
(...skipping 1576 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
3941 LanguageError::kError, | 3943 LanguageError::kError, |
3942 Heap::kNew, | 3944 Heap::kNew, |
3943 "FlowGraphBuilder Bailout: %s %s", | 3945 "FlowGraphBuilder Bailout: %s %s", |
3944 String::Handle(function.name()).ToCString(), | 3946 String::Handle(function.name()).ToCString(), |
3945 reason)); | 3947 reason)); |
3946 Isolate::Current()->long_jump_base()->Jump(1, error); | 3948 Isolate::Current()->long_jump_base()->Jump(1, error); |
3947 } | 3949 } |
3948 | 3950 |
3949 | 3951 |
3950 } // namespace dart | 3952 } // namespace dart |
OLD | NEW |