Chromium Code Reviews| Index: runtime/vm/parser.cc |
| =================================================================== |
| --- runtime/vm/parser.cc (revision 11663) |
| +++ runtime/vm/parser.cc (working copy) |
| @@ -119,24 +119,52 @@ |
| } |
| +LocalVariable* ParsedFunction::GetSavedArgumentsDescriptorVar() const { |
| + const int num_parameters = function().NumberOfParameters(); |
| + LocalScope* scope = node_sequence()->scope(); |
| + if (scope->num_variables() > num_parameters) { |
| + LocalVariable* saved_args_desc_var = scope->VariableAt(num_parameters); |
| + ASSERT(saved_args_desc_var != NULL); |
| + // The scope of the formal parameters may also contain at this position |
| + // an alias for the saved arguments descriptor variable of the enclosing |
| + // function (check its scope owner) or an internal variable such as the |
| + // expression temp variable or the saved entry context variable (check its |
| + // name). |
| + if ((saved_args_desc_var->owner() == scope) && |
| + saved_args_desc_var->name().StartsWith( |
| + String::Handle(Symbols::SavedArgDescVarPrefix()))) { |
| + return saved_args_desc_var; |
| + } |
| + } |
| + return NULL; |
| +} |
| + |
| + |
| void ParsedFunction::AllocateVariables() { |
| LocalScope* scope = node_sequence()->scope(); |
| const int fixed_parameter_count = function().num_fixed_parameters(); |
| const int optional_parameter_count = function().num_optional_parameters(); |
| - const int parameter_count = fixed_parameter_count + optional_parameter_count; |
| + int parameter_count = fixed_parameter_count + optional_parameter_count; |
| const bool is_native_instance_closure = |
| function().is_native() && function().IsImplicitInstanceClosureFunction(); |
| // Compute start indices to parameters and locals, and the number of |
| // parameters to copy. |
| - if (optional_parameter_count == 0 && !is_native_instance_closure) { |
| + if ((optional_parameter_count == 0) && !is_native_instance_closure) { |
| // Parameter i will be at fp[1 + parameter_count - i] and local variable |
| // j will be at fp[kFirstLocalSlotIndex - j]. |
| + ASSERT(GetSavedArgumentsDescriptorVar() == NULL); |
| first_parameter_index_ = 1 + parameter_count; |
| first_stack_local_index_ = kFirstLocalSlotIndex; |
| copied_parameter_count_ = 0; |
| } else { |
| // Parameter i will be at fp[kFirstLocalSlotIndex - i] and local variable |
| // j will be at fp[kFirstLocalSlotIndex - parameter_count - j]. |
| + // The saved argument descriptor variable must be allocated similarly to |
| + // a parameter, so that it gets both a frame slot and a context slot when |
| + // captured. |
| + if (GetSavedArgumentsDescriptorVar() != NULL) { |
| + parameter_count += 1; |
| + } |
| first_parameter_index_ = kFirstLocalSlotIndex; |
| first_stack_local_index_ = first_parameter_index_ - parameter_count; |
| copied_parameter_count_ = parameter_count; |
| @@ -161,8 +189,8 @@ |
| // variables, the context needs to be saved on entry and restored on exit. |
| // Add and allocate a local variable to this purpose. |
| if ((context_owner != NULL) && !function().IsClosureFunction()) { |
| - const String& context_var_name = String::ZoneHandle( |
| - Symbols::New(LocalVariable::kSavedContextVarName)); |
| + const String& context_var_name = |
| + String::ZoneHandle(Symbols::SavedEntryContextVar()); |
| LocalVariable* context_var = |
| new LocalVariable(function().token_pos(), |
| context_var_name, |
| @@ -261,7 +289,7 @@ |
| current_class_(Class::Handle(current_function_.Owner())), |
| library_(Library::Handle(current_class_.library())), |
| try_blocks_list_(NULL), |
| - expression_temp_(NULL) { |
| + expression_temp_(NULL) { |
| ASSERT(tokens_iterator_.IsValid()); |
| ASSERT(!function.IsNull()); |
| if (FLAG_enable_type_checks) { |
| @@ -1133,12 +1161,10 @@ |
| if (LookaheadToken(1) != Token::kRPAREN) { |
| // Parse positional parameters. |
| - ParseFormalParameters(allow_explicit_default_values, |
| - params); |
| + ParseFormalParameters(allow_explicit_default_values, params); |
| if (params->has_named_optional_parameters) { |
| // Parse named optional parameters. |
| - ParseFormalParameters(allow_explicit_default_values, |
| - params); |
| + ParseFormalParameters(allow_explicit_default_values, params); |
| if (CurrentToken() != Token::kRBRACK) { |
| ErrorMsg("',' or ']' expected"); |
| } |
| @@ -7356,6 +7382,94 @@ |
| } |
| +// Returns true if ident resolves to a formal parameter of the current function |
| +// or of one of its enclosing functions. |
| +// Make sure not to capture the formal parameter, since it is not accessed. |
| +bool Parser::IsFormalParameter(const String& ident, |
| + Function* owner_function, |
| + LocalScope** owner_scope, |
| + intptr_t* local_index) { |
| + if (current_block_ == NULL) { |
| + return false; |
| + } |
| + if (ident.Equals(String::Handle(Symbols::This()))) { |
| + // 'this' is not a formal parameter. |
| + return false; |
| + } |
| + // Since an argument definition test does not use the value of the formal |
| + // parameter, there is no reason to capture it. |
| + const bool kTestOnly = true; // No capturing. |
| + LocalVariable* local = |
| + current_block_->scope->LookupVariable(ident, kTestOnly); |
| + if (local == NULL) { |
| + if (!current_function().IsLocalFunction()) { |
| + // We are not generating code for a local function, so all locals, |
| + // captured or not, are in scope. However, 'ident' was not found, so it |
| + // does not exist. |
| + return false; |
| + } |
| + // The formal parameter may belong to an enclosing function and may not have |
| + // been captured, so it was not included in the context scope and it cannot |
| + // be found by LookupVariable. |
| + // 'ident' necessarily refers to the formal parameter of one of the |
| + // enclosing functions, or a compile error would have prevented the |
| + // outermost enclosing function to be executed and we would not be compiling |
| + // this local function. |
| + // Therefore, look for ident directly in the formal parameter lists of the |
| + // enclosing functions. |
| + // There is no need to return the owner_scope, since the caller will not |
| + // create the saved_arguments_descriptor variable, which already exists. |
| + Function& function = Function::Handle(innermost_function().raw()); |
| + String& param_name = String::Handle(); |
| + do { |
| + const int num_parameters = function.NumberOfParameters(); |
| + for (intptr_t i = 0; i < num_parameters; i++) { |
| + param_name = function.ParameterNameAt(i); |
| + if (ident.Equals(param_name)) { |
| + *owner_function = function.raw(); |
| + *owner_scope = NULL; |
| + *local_index = i; |
| + return true; |
| + } |
| + } |
| + function = function.parent_function(); |
| + } while (!function.IsNull()); |
| + UNREACHABLE(); |
|
hausner
2012/08/31 00:34:55
Is this really unreachable? What if the name refer
regis
2012/08/31 01:36:18
Indeed, you missed the comment on line 7414 explai
|
| + } |
| + // Verify that local is a formal parameter of the current function or of one |
| + // of its enclosing functions. |
| + // Note that scopes are not yet associated to functions. |
| + Function& function = Function::Handle(innermost_function().raw()); |
| + LocalScope* scope = current_block_->scope; |
| + while (scope != NULL) { |
| + ASSERT(!function.IsNull()); |
| + // Find the top scope for this function level. |
| + while ((scope->parent() != NULL) && |
| + (scope->parent()->function_level() == scope->function_level())) { |
| + scope = scope->parent(); |
| + } |
| + if (scope == local->owner()) { |
| + // Scope contains 'local' and the formal parameters of 'function'. |
| + const int num_parameters = function.NumberOfParameters(); |
| + for (intptr_t i = 0; i < num_parameters; i++) { |
| + if (scope->VariableAt(i) == local) { |
| + *owner_function = function.raw(); |
| + *owner_scope = scope; |
| + *local_index = i; |
| + return true; |
| + } |
| + } |
| + // The variable 'local' is not a formal parameter. |
| + return false; |
| + } |
| + scope = scope->parent(); |
| + function = function.parent_function(); |
| + } |
| + // The variable 'local' does not belong to a function top scope. |
| + return false; |
| +} |
| + |
| + |
| void Parser::CheckInstanceFieldAccess(intptr_t field_pos, |
| const String& field_name) { |
| // Fields are not accessible from a static function, except from a |
| @@ -8828,6 +8942,65 @@ |
| } |
| +AstNode* Parser::ParseArgumentDefinitionTest() { |
| + const intptr_t test_pos = TokenPos(); |
| + ConsumeToken(); |
| + const intptr_t ident_pos = TokenPos(); |
| + String* ident = ExpectIdentifier("parameter name expected"); |
| + Function& owner_function = Function::Handle(); |
| + LocalScope* owner_scope; |
| + intptr_t param_index; |
| + if (!IsFormalParameter(*ident, &owner_function, &owner_scope, ¶m_index)) { |
| + ErrorMsg(ident_pos, "formal parameter name expected"); |
| + } |
| + if (param_index < owner_function.num_fixed_parameters()) { |
| + // The formal parameter is not optional, therefore the corresponding |
| + // argument is always passed and defined. |
| + return new LiteralNode(test_pos, Bool::ZoneHandle(Bool::True())); |
| + } |
| + char name[64]; |
| + OS::SNPrint(name, 64, "%s_%d", |
| + Symbols::Name(Symbols::kSavedArgDescVarPrefix), |
| + owner_function.token_pos()); |
| + const String& saved_args_desc_name = String::ZoneHandle(Symbols::New(name)); |
| + LocalVariable* saved_args_desc_var = LookupLocalScope(saved_args_desc_name); |
| + if (saved_args_desc_var == NULL) { |
| + ASSERT(owner_scope != NULL); |
| + ASSERT(owner_function.raw() == current_function().raw()); |
| + // We currently generate code for 'owner_function', otherwise the variable |
| + // would have been created when compiling the enclosing function of the |
| + // currently being compiled local function. |
| + saved_args_desc_var = |
| + new LocalVariable(owner_function.token_pos(), |
| + saved_args_desc_name, |
| + Type::ZoneHandle(Type::ListInterface())); |
| + saved_args_desc_var->set_is_final(); |
| + // The saved arguments descriptor variable must be added just after the |
| + // formal parameters. This simplifies the 2-step saving of a captured |
| + // arguments descriptor. |
| + // At this time, the owner scope should only contain formal parameters. |
| + ASSERT(owner_scope->num_variables() == owner_function.NumberOfParameters()); |
| + bool success = owner_scope->AddVariable(saved_args_desc_var); |
| + ASSERT(success); |
| + // Capture the saved argument descriptor variable if necessary. |
| + if (current_function().raw() != innermost_function().raw()) { |
| + LocalVariable* local = LookupLocalScope(saved_args_desc_name); |
| + ASSERT(local == saved_args_desc_var); |
| + ASSERT(local->is_captured()); |
| + } |
| + } else { |
| + // If we currently generate code for a local function of the owner function, |
| + // the saved arguments descriptor variable must have been captured by the |
| + // above lookup. |
| + ASSERT((owner_function.raw() == current_function().raw()) || |
| + saved_args_desc_var->is_captured()); |
| + } |
| + const String& param_name = String::ZoneHandle(Symbols::New(*ident)); |
| + return new ArgumentDefinitionTestNode( |
| + test_pos, param_index, param_name, saved_args_desc_var); |
| +} |
| + |
| + |
| AstNode* Parser::ParsePrimary() { |
| TRACE_PARSER("ParsePrimary"); |
| ASSERT(!is_top_level_); |
| @@ -8947,6 +9120,8 @@ |
| } else { |
| ErrorMsg("illegal super call"); |
| } |
| + } else if (CurrentToken() == Token::kCONDITIONAL) { |
| + primary = ParseArgumentDefinitionTest(); |
| } else { |
| UnexpectedToken(); |
| } |