// $Id: definite.cpp,v 1.69 2004/06/02 10:28:06 elliott-oss Exp $ // // This software is subject to the terms of the IBM Jikes Compiler // License Agreement available at the following URL: // http://ibm.com/developerworks/opensource/jikes. // Copyright (C) 1996, 2004 IBM Corporation and others. All Rights Reserved. // You must accept the terms of that agreement to use this software. // #include "platform.h" #include "semantic.h" #include "control.h" #include "option.h" #ifdef HAVE_JIKES_NAMESPACE namespace Jikes { // Open namespace Jikes block #endif // // NOTE: This file is used to determine definite assignment and definite // unassignment rules, per JLS chapter 16. Often, these are abbreviated // da and du. The BitSet type holds a status bit for every variable in // scope. Since many rules operate identically on da and du, the DefinitePair // type is a wrapper for two BitSets. Finally, boolean expressions can // cause different definite assignment status during speculation, so // the DefiniteAssignmentSet is a wrapper for two DefinitePair objects. // // It is a compile-time error if a local variable is accessed that is not // da, and a compile-time error if a blank final is assigned when it is // not du. This code also handles the compile-time error when an assignment // is attempted to an initialized final. // // There are two contexts: expression and statement. In expression context, // we must pass in the current assignment state and return the resultant // state (if different) - this is to allow speculative decisions when // evaluating loop bodies. In statement context, rather than pass the // information around, we store it in the instance variable // *DefinitelyAssignedVariables() for efficiency. // inline DefinitePair::DefinitePair(const DefiniteAssignmentSet& set) : da_set(set.DASet()), du_set(set.DUSet()) {} inline DefinitePair& DefinitePair::operator=(const DefiniteAssignmentSet& rhs) { da_set = rhs.DASet(); du_set = rhs.DUSet(); return *this; } // // There are two versions of DefiniteExpression. Call this version if the // expression can be boolean, but there is no need to track the when true // and when false cases separately; or if the expression cannot be boolean. // If the expression can be (or always is) boolean, and the when true and // when false cases matter, call DefiniteBooleanExpression. // void Semantic::DefiniteExpression(AstExpression* expr, DefinitePair& def_pair) { if (expr -> IsConstant()) // A constant expression has no effect on DA/DU. return; DefiniteAssignmentSet* definite = DefiniteBooleanExpression(expr, def_pair); if (definite) { def_pair = *definite; delete definite; } } // // See the comments for DefiniteExpression above. If the when true and when // false status differ after this expression, the calling function MUST delete // the returned object to avoid a memory leak. // DefiniteAssignmentSet* Semantic::DefiniteBooleanExpression(AstExpression* expr, DefinitePair& def_pair) { DefiniteAssignmentSet* definite = NULL; // // Is the expression a constant expression of type boolean? // Recall that a constant expression does not contain an // assignment statement. // if (IsConstantTrue(expr)) return new DefiniteAssignmentSet(def_pair, *Universe()); else if (IsConstantFalse(expr)) return new DefiniteAssignmentSet(*Universe(), def_pair); else if (expr -> symbol != control.no_type) definite = (this ->* DefiniteExpr[expr -> kind])(expr, def_pair); assert(! definite || expr -> Type() == control.boolean_type); return definite; } DefiniteAssignmentSet* Semantic::DefiniteName(AstExpression* expression, DefinitePair& def_pair) { AstName* name = (AstName*) expression; if (name -> resolution_opt) return DefiniteBooleanExpression(name -> resolution_opt, def_pair); if (name -> base_opt) DefiniteName(name -> base_opt, def_pair); // // Some simple names are undefined. e.g., the simple name in a method call. // Others were generated by the compiler as method shadows, so we know // when and where they will be properly initialized. Qualified names are // always treated as initialized. // VariableSymbol* variable = name -> symbol ? name -> symbol -> VariableCast() : (VariableSymbol*) NULL; if (variable && ! variable -> ACC_SYNTHETIC() && ! name -> base_opt && (variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType()))) { int index = variable -> LocalVariableIndex(this); // // Compile time constants are always da; this matters in switch // blocks, where we might have bypassed the initializer. // if (! def_pair.da_set[index] && ! name -> IsConstant()) { ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_ASSIGNED, name -> identifier_token, variable -> Name()); if (variable -> IsLocal(ThisMethod())) // avoid cascading errors! def_pair.da_set.AddElement(index); } } return NULL; } DefiniteAssignmentSet* Semantic::DefiniteArrayAccess(AstExpression* expression, DefinitePair& def_pair) { AstArrayAccess* array_access = (AstArrayAccess*) expression; DefiniteExpression(array_access -> base, def_pair); DefiniteExpression(array_access -> expression, def_pair); return NULL; } DefiniteAssignmentSet* Semantic::DefiniteMethodInvocation(AstExpression* expression, DefinitePair& def_pair) { AstMethodInvocation* method_call = (AstMethodInvocation*) expression; if (method_call -> base_opt) DefiniteExpression(method_call -> base_opt, def_pair); for (unsigned i = 0; i < method_call -> arguments -> NumArguments(); i++) DefiniteExpression(method_call -> arguments -> Argument(i), def_pair); return NULL; } DefiniteAssignmentSet* Semantic::DefiniteClassCreationExpression(AstExpression* expression, DefinitePair& def_pair) { unsigned i; AstClassCreationExpression* class_creation = (AstClassCreationExpression*) expression; if (class_creation -> resolution_opt) class_creation = class_creation -> resolution_opt; if (class_creation -> base_opt) DefiniteExpression(class_creation -> base_opt, def_pair); for (i = 0; i < class_creation -> arguments -> NumArguments(); i++) DefiniteExpression(class_creation -> arguments -> Argument(i), def_pair); for (i = 0; i < class_creation -> arguments -> NumLocalArguments(); i++) DefiniteExpression(class_creation -> arguments -> LocalArgument(i), def_pair); return NULL; } DefiniteAssignmentSet* Semantic::DefiniteArrayCreationExpression(AstExpression* expression, DefinitePair& def_pair) { AstArrayCreationExpression* array_creation = (AstArrayCreationExpression*) expression; for (unsigned i = 0; i < array_creation -> NumDimExprs(); i++) { AstDimExpr* dim_expr = array_creation -> DimExpr(i); DefiniteExpression(dim_expr -> expression, def_pair); } if (array_creation -> array_initializer_opt) DefiniteArrayInitializer(array_creation -> array_initializer_opt, def_pair); return NULL; } inline VariableSymbol* Semantic::DefiniteFinal(AstFieldAccess* field_access) { if (field_access -> resolution_opt) field_access = field_access -> resolution_opt -> FieldAccessCast(); if (field_access) { VariableSymbol* variable = (field_access -> symbol ? field_access -> symbol -> VariableCast() : (VariableSymbol*) NULL); if (variable && variable -> IsFinal(ThisType())) { // // There is exactly one copy of a static variable, so, it's // always the right one. Access via 'this' is also legal. // if (variable -> ACC_STATIC() || field_access -> base -> ThisExpressionCast()) { return variable; } } } return NULL; } DefiniteAssignmentSet* Semantic::DefinitePLUSPLUSOrMINUSMINUS(AstExpression* expr, DefinitePair& def_pair) { DefiniteExpression(expr, def_pair); // // JLS2 added ability for parenthesized variable to remain a variable // while (expr -> ParenthesizedExpressionCast()) expr = ((AstParenthesizedExpression*) expr) -> expression; VariableSymbol* variable = NULL; if (! expr -> ArrayAccessCast()) // some kind of name { MethodSymbol* read_method = NULL; AstName* name = expr -> NameCast(); if (name) { if (name -> resolution_opt) read_method = name -> resolution_opt -> symbol -> MethodCast(); } else { AstFieldAccess* field_access = expr -> FieldAccessCast(); assert(field_access); if (field_access -> resolution_opt) read_method = field_access -> resolution_opt -> symbol -> MethodCast(); } variable = (read_method ? (VariableSymbol*) read_method -> accessed_member : expr -> symbol -> VariableCast()); while (variable && variable -> accessed_local) variable = variable -> accessed_local; } // // If we have a variable and it is final then... // if (variable && variable -> ACC_FINAL()) { if ((variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType())) && ! variable -> ACC_SYNTHETIC() && (*BlankFinals())[variable -> LocalVariableIndex(this)]) { ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_UNASSIGNED, expr -> LeftToken(), expr -> RightToken(), variable -> Name()); } else { ReportSemError(SemanticError::FINAL_VARIABLE_NOT_BLANK, expr -> LeftToken(), expr -> RightToken(), variable -> Name()); } // Mark it assigned, to catch further errors. if (variable -> IsFinal(ThisType()) && ! variable -> ACC_SYNTHETIC()) def_pair.du_set.RemoveElement(variable -> LocalVariableIndex(this)); } return NULL; } DefiniteAssignmentSet* Semantic::DefinitePostUnaryExpression(AstExpression* expression, DefinitePair& def_pair) { AstPostUnaryExpression* postfix_expression = (AstPostUnaryExpression*) expression; return DefinitePLUSPLUSOrMINUSMINUS(postfix_expression -> expression, def_pair); } DefiniteAssignmentSet* Semantic::DefiniteNOT(AstExpression* expr, DefinitePair& def_pair) { DefiniteAssignmentSet* after_expr = DefiniteBooleanExpression(expr, def_pair); if (after_expr) // is the expression is a complex boolean expression? { DefinitePair temp(after_expr -> true_pair); after_expr -> true_pair = after_expr -> false_pair; after_expr -> false_pair = temp; } return after_expr; } // // The default pre unary operators are +, -, and ~. // As these operators are not applicable to boolean expressions, // we do not need to invoke DefiniteExpression to process them. // DefiniteAssignmentSet* Semantic::DefiniteDefaultPreUnaryExpression(AstExpression* expr, DefinitePair& def_pair) { return (this ->* DefiniteExpr[expr -> kind])(expr, def_pair); } DefiniteAssignmentSet* Semantic::DefinitePreUnaryExpression(AstExpression* expression, DefinitePair& def_pair) { AstPreUnaryExpression* prefix_expression = (AstPreUnaryExpression*) expression; return (this ->* DefinitePreUnaryExpr[prefix_expression -> Tag()]) (prefix_expression -> expression, def_pair); } DefiniteAssignmentSet* Semantic::DefiniteAND_AND(AstBinaryExpression* expr, DefinitePair& def_pair) { DefiniteAssignmentSet* after_left = DefiniteBooleanExpression(expr -> left_expression, def_pair); DefinitePair* before_right = NULL; if (after_left) def_pair = after_left -> true_pair; else before_right = new DefinitePair(def_pair); DefiniteAssignmentSet* after_right = DefiniteBooleanExpression(expr -> right_expression, def_pair); if (after_left) { if (after_right) { after_right -> false_pair *= after_left -> false_pair; delete after_left; } else { after_right = after_left; after_right -> true_pair = def_pair; after_right -> false_pair *= def_pair; } } else { if (! after_right) after_right = new DefiniteAssignmentSet(def_pair); after_right -> false_pair *= *before_right; } // harmless if NULL delete before_right; return after_right; } DefiniteAssignmentSet* Semantic::DefiniteOR_OR(AstBinaryExpression* expr, DefinitePair& def_pair) { DefiniteAssignmentSet* after_left = DefiniteBooleanExpression(expr -> left_expression, def_pair); DefinitePair* before_right = NULL; if (after_left) def_pair = after_left -> false_pair; else before_right = new DefinitePair(def_pair); DefiniteAssignmentSet* after_right = DefiniteBooleanExpression(expr -> right_expression, def_pair); if (after_left) { if (after_right) { after_right -> true_pair *= after_left -> true_pair; delete after_left; } else { after_right = after_left; after_right -> true_pair *= def_pair; after_right -> false_pair = def_pair; } } else { if (! after_right) after_right = new DefiniteAssignmentSet(def_pair); after_right -> true_pair *= *before_right; } // harmless if NULL delete before_right; return after_right; } DefiniteAssignmentSet* Semantic::DefiniteDefaultBinaryExpression(AstBinaryExpression* expr, DefinitePair& def_pair) { DefiniteExpression(expr -> left_expression, def_pair); DefiniteExpression(expr -> right_expression, def_pair); return NULL; } DefiniteAssignmentSet* Semantic::DefiniteBinaryExpression(AstExpression* expression, DefinitePair& def_pair) { AstBinaryExpression* binary_expression = (AstBinaryExpression*) expression; return (this ->* DefiniteBinaryExpr[binary_expression -> Tag()]) (binary_expression, def_pair); } DefiniteAssignmentSet* Semantic::DefiniteInstanceofExpression(AstExpression* expression, DefinitePair& def_pair) { AstInstanceofExpression* expr = (AstInstanceofExpression*) expression; DefiniteExpression(expr -> expression, def_pair); return NULL; } DefiniteAssignmentSet* Semantic::DefiniteConditionalExpression(AstExpression* expression, DefinitePair& def_pair) { AstConditionalExpression* conditional_expression = (AstConditionalExpression*) expression; DefiniteAssignmentSet* after_condition = DefiniteBooleanExpression(conditional_expression -> test_expression, def_pair); DefinitePair* before_expressions = NULL; if (after_condition) def_pair = after_condition -> true_pair; else before_expressions = new DefinitePair(def_pair); DefiniteAssignmentSet* after_true = DefiniteBooleanExpression(conditional_expression -> true_expression, def_pair); DefinitePair* after_true_pair = (after_true ? (DefinitePair*) NULL : new DefinitePair(def_pair)); if (after_condition) def_pair = after_condition -> false_pair; else def_pair = *before_expressions; DefiniteAssignmentSet* after_false = DefiniteBooleanExpression(conditional_expression -> false_expression, def_pair); if (conditional_expression -> Type() == control.boolean_type) { if (! after_true) after_true = new DefiniteAssignmentSet(*after_true_pair); if (after_false) { after_true -> true_pair *= after_false -> true_pair; after_true -> false_pair *= after_false -> false_pair; } else { after_true -> true_pair *= def_pair; after_true -> false_pair *= def_pair; } } else { assert(! after_true && ! after_false); def_pair *= *after_true_pair; } // harmless if NULL delete after_condition; delete before_expressions; delete after_false; return after_true; } DefiniteAssignmentSet* Semantic::DefiniteAssignmentExpression(AstExpression* expression, DefinitePair& def_pair) { AstAssignmentExpression* assignment_expression = (AstAssignmentExpression*) expression; AstCastExpression* casted_left_hand_side = assignment_expression -> left_hand_side -> CastExpressionCast(); AstExpression* left_hand_side = casted_left_hand_side ? casted_left_hand_side -> expression : assignment_expression -> left_hand_side; bool simple_name = false; if (left_hand_side -> NameCast()) { AstName* name = (AstName*) left_hand_side; simple_name = ! name -> base_opt; } else { AstFieldAccess* field_access = left_hand_side -> FieldAccessCast(); if (field_access) { if (field_access -> resolution_opt) left_hand_side = field_access -> resolution_opt; // // Because constructor parameters often shadow field names, // this.name is legal for final instance fields. However, anything // more complex, such as (this).name or Classname.this.name, as // well as Classname.name for static fields or expression.name in // general, will be rejected. // TODO: This is not well-specified in the JLS; rather we are just // following the lead of Sun's javac 1.4.1. Clean this code up when // a decent specification is given. // if (field_access -> base -> ThisExpressionCast()) simple_name = ((AstThisExpression*) field_access -> base) -> base_opt == NULL; } } VariableSymbol* variable = (left_hand_side -> symbol ? left_hand_side -> symbol -> VariableCast() : (VariableSymbol*) NULL); while (variable && variable -> accessed_local) variable = variable -> accessed_local; int index = 0; // // An array access is never considered to be final. Since no variable // is associated with the array access, the testing for the presence of // variable takes care of that possibility. // if (variable) { if (variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType())) { index = variable -> LocalVariableIndex(this); // // If we have a compound assignment then the variable must have // been set prior to such an assignment. otherwise, an error // occurs. // if (! assignment_expression -> SimpleAssignment() && ! def_pair.da_set[index]) { ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_ASSIGNED, left_hand_side -> LeftToken(), left_hand_side -> RightToken(), variable -> Name()); } } else if (variable -> ACC_FINAL()) { // attempt to assign a value to a final field member! ReportSemError(SemanticError::FINAL_VARIABLE_NOT_BLANK, left_hand_side -> LeftToken(), left_hand_side -> RightToken(), variable -> Name()); } } // // The left-hand-side of an assignment expression is either a simple name, // a field access or an array access. A simple name does not need further // action, a field access needs to descend into all qualifying expressions, // and an array access needs to descend into the entire expression. // if (! simple_name) { AstFieldAccess* field_access = left_hand_side -> FieldAccessCast(); DefiniteExpression((field_access ? field_access -> base : left_hand_side), def_pair); } // // JLS2 16.1.7 - The rules for definite assignment of boolean valued // assignments are stricter than they were in JLS1; hence we no longer // consider the when true and when false values separately. // DefiniteExpression(assignment_expression -> expression, def_pair); // // Finally, we mark the variable as assigned. // if (variable && (variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType()))) { if (variable -> ACC_FINAL()) { // // It is an error to assign finals except for DU blank final. Also, // final fields must be assigned by simple name, or by this.name. // if (! (*BlankFinals())[index] || ! def_pair.du_set[index]) { ReportSemError(((*BlankFinals())[index] ? SemanticError::VARIABLE_NOT_DEFINITELY_UNASSIGNED : SemanticError::FINAL_VARIABLE_NOT_BLANK), left_hand_side -> LeftToken(), left_hand_side -> RightToken(), variable -> Name()); } else if (variable -> IsFinal(ThisType()) && ! simple_name) { ReportSemError(SemanticError::FINAL_FIELD_ASSIGNMENT_NOT_SIMPLE, left_hand_side -> LeftToken(), left_hand_side -> RightToken(), variable -> Name(), (variable -> ACC_STATIC() ? NULL : variable -> Name())); } else if (! def_pair.da_set[index]) { // // If the variable is also DA, then this code is never // executed, so it does not affect loop or try-catch analysis. // if (DefiniteFinalAssignments() -> Size() > 0) { DefiniteFinalAssignments() -> Top().Next() = left_hand_side; } ReachableAssignments() -> AddElement(index); } } def_pair.AssignElement(index); } return NULL; } DefiniteAssignmentSet* Semantic::DefiniteParenthesizedExpression(AstExpression* expression, DefinitePair& def_pair) { AstParenthesizedExpression* expr = (AstParenthesizedExpression*) expression; return DefiniteBooleanExpression(expr -> expression, def_pair); } DefiniteAssignmentSet* Semantic::DefiniteFieldAccess(AstExpression* expression, DefinitePair& def_pair) { AstFieldAccess* expr = (AstFieldAccess*) expression; // // TODO: Sun bug 4395322 mentions that DA is underspecified for field // references. In other words, it is legal to read an uninitialized // static value through Classname.fieldname, or an instance value // through this.fieldname. If Sun specifies that this behavior is correct, // this commented code can be removed. // // VariableSymbol* variable = DefiniteFinal(expr); // if (variable) // { // if (! def_pair.da_set[variable -> LocalVariableIndex(this)]) // { // ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_ASSIGNED, // expr -> LeftToken(), // expr -> RightToken(), // variable -> Name()); // // supress further warnings // def_pair.da_set.AddElement(variable -> LocalVariableIndex(this)); // } // } return DefiniteBooleanExpression((expr -> resolution_opt ? expr -> resolution_opt : expr -> base), def_pair); } DefiniteAssignmentSet* Semantic::DefiniteCastExpression(AstExpression* expression, DefinitePair& def_pair) { AstCastExpression* expr = (AstCastExpression*) expression; return DefiniteBooleanExpression(expr -> expression, def_pair); } // // Must have two versions, since this can be called in both expression and // statement context. // void Semantic::DefiniteArrayInitializer(AstArrayInitializer* array_initializer, DefinitePair& def_pair) { for (unsigned i = 0; i < array_initializer -> NumVariableInitializers(); i++) { AstArrayInitializer* sub_array_initializer = array_initializer -> VariableInitializer(i) -> ArrayInitializerCast(); if (sub_array_initializer) DefiniteArrayInitializer(sub_array_initializer, def_pair); else { AstExpression* init = (AstExpression*) array_initializer -> VariableInitializer(i); DefiniteExpression(init, def_pair); } } } inline void Semantic::DefiniteArrayInitializer(AstArrayInitializer* array_initializer) { DefiniteArrayInitializer(array_initializer, *DefinitelyAssignedVariables()); } inline void Semantic::DefiniteVariableInitializer(AstVariableDeclarator* variable_declarator) { assert(variable_declarator -> variable_initializer_opt); AstExpression* init = variable_declarator -> variable_initializer_opt -> ExpressionCast(); if (! init) DefiniteArrayInitializer((AstArrayInitializer*) variable_declarator -> variable_initializer_opt, *DefinitelyAssignedVariables()); else DefiniteExpression(init, *DefinitelyAssignedVariables()); // // Even when initialized by a non-constant, variables declared in a // switch are necessarily blank finals. // TODO: Sun has never given any nice official word on this. // if (DefiniteBlocks() && DefiniteBlocks() -> TopBlock() -> Tag() == AstBlock::SWITCH && (! init || ! init -> IsConstant())) { BlankFinals() -> AddElement(variable_declarator -> symbol -> LocalVariableIndex(this)); } } inline void Semantic::DefiniteStatement(Ast* ast) { (this ->* DefiniteStmt[ast -> kind])(ast); } inline void Semantic::DefiniteBlockStatements(AstBlock* block_body) { for (unsigned i = 0; i < block_body -> NumStatements(); i++) { AstStatement* statement = block_body -> Statement(i); // // As unreachable statements already cause an error, we avoid // them here // if (statement -> is_reachable) DefiniteStatement(statement); else break; } } void Semantic::DefiniteBlock(Ast* stmt) { AstBlock* block_body = (AstBlock*) stmt; unsigned i; DefiniteBlocks() -> Push(block_body); DefiniteBlockStatements(block_body); #ifdef DUMP if ((control.option.g & JikesOption::VARS) && block_body -> NumLocallyDefinedVariables() > 0) { Coutput << "(3) At Line " << lex_stream -> Line(block_body -> RightToken()) << " the range for the following variables end:" << endl << endl; for (i = 0; i < block_body -> NumLocallyDefinedVariables(); i++) Coutput << " \"" << block_body -> LocallyDefinedVariable(i) -> Name() << "\"" << endl; } #endif // DUMP // // Remove all variables that just went out of scope. // for (i = 0; i < block_body -> block_symbol -> NumVariableSymbols(); i++) { VariableSymbol* variable = block_body -> block_symbol -> VariableSym(i); int index = variable -> LocalVariableIndex(this); BlankFinals() -> RemoveElement(index); ReachableAssignments() -> RemoveElement(index); DefinitelyAssignedVariables() -> ReclaimElement(index); DefiniteBlocks() -> ContinuePair(DefiniteBlocks() -> Size() - 2).ReclaimElement(index); } // // Note that in constructing the Ast, the parser encloses each // labeled statement in its own block... Therefore, only blocks // are labeled. // if (block_body -> label_opt) *DefinitelyAssignedVariables() *= DefiniteBlocks() -> TopBreakPair(); DefiniteBlocks() -> Pop(); } void Semantic::DefiniteLocalClassStatement(Ast* stmt) { AstLocalClassStatement* local_decl = (AstLocalClassStatement*) stmt; TypeSymbol* local_type = local_decl -> declaration -> class_body -> semantic_environment -> Type(); assert(local_type -> LocalClassProcessingCompleted()); for (unsigned i = 0; i < local_type -> NumConstructorParameters(); i++) { VariableSymbol* var = local_type -> ConstructorParameter(i) -> accessed_local; if (var -> owner == ThisMethod() && (! DefinitelyAssignedVariables() -> da_set[var -> LocalVariableIndex(this)])) { ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_ASSIGNED, local_decl, var -> Name()); } } } void Semantic::DefiniteLocalVariableStatement(Ast* stmt) { AstLocalVariableStatement* local_decl = (AstLocalVariableStatement*) stmt; for (unsigned i = 0; i < local_decl -> NumVariableDeclarators(); i++) { AstVariableDeclarator* variable_declarator = local_decl -> VariableDeclarator(i); VariableSymbol* variable_symbol = variable_declarator -> symbol; if (! variable_symbol) continue; int index = variable_symbol -> LocalVariableIndex(this); if (control.option.g & JikesOption::VARS) { #ifdef DUMP Coutput << "(3.5) Local Variable \"" << variable_symbol -> Name() << " #" << index << "\" is declared at line " << lex_stream -> Line(variable_declarator -> LeftToken()) << endl; #endif // DUMP DefiniteBlocks() -> TopBlock() -> AddLocallyDefinedVariable(variable_symbol); } if (variable_declarator -> variable_initializer_opt) { DefiniteVariableInitializer(variable_declarator); DefinitelyAssignedVariables() -> AssignElement(index); } else { DefinitelyAssignedVariables() -> ReclaimElement(index); if (variable_symbol -> ACC_FINAL()) BlankFinals() -> AddElement(index); } } } void Semantic::DefiniteExpressionStatement(Ast* stmt) { AstExpressionStatement* expression_statement = (AstExpressionStatement*) stmt; DefiniteExpression(expression_statement -> expression, *DefinitelyAssignedVariables()); } void Semantic::DefiniteSynchronizedStatement(Ast* stmt) { AstSynchronizedStatement* synchronized_statement = (AstSynchronizedStatement*) stmt; DefiniteExpression(synchronized_statement -> expression, *DefinitelyAssignedVariables()); DefiniteBlock(synchronized_statement -> block); } void Semantic::DefiniteIfStatement(Ast* stmt) { AstIfStatement* if_statement = (AstIfStatement*) stmt; DefiniteAssignmentSet* after_expr = DefiniteBooleanExpression(if_statement -> expression, *DefinitelyAssignedVariables()); DefinitePair* starting_pair = new DefinitePair(*DefinitelyAssignedVariables()); if (after_expr) *DefinitelyAssignedVariables() = after_expr -> true_pair; // // Recall that the parser ensures that the statements that appear in an // if-statement (both the true and false statement) are enclosed in a // block. // DefiniteBlock(if_statement -> true_statement); if (! if_statement -> false_statement_opt) // no else part ? { *DefinitelyAssignedVariables() *= (after_expr ? after_expr -> false_pair : *starting_pair); } else { DefinitePair true_set(*DefinitelyAssignedVariables()); *DefinitelyAssignedVariables() = (after_expr ? after_expr -> false_pair : *starting_pair); DefiniteBlock(if_statement -> false_statement_opt); *DefinitelyAssignedVariables() *= true_set; } // harmless if NULL delete starting_pair; } void Semantic::DefiniteLoopBody(BitSet& starting_set) { // // Find the set of variables that were DU before the loop, but not DU // at the loop end. This requires the loop to have merged in the DU // status before all continue statements. // starting_set -= DefinitelyAssignedVariables() -> du_set; for (unsigned i = 0; i < DefiniteFinalAssignments() -> Top().Length(); i++) { AstExpression* name = DefiniteFinalAssignments() -> Top()[i]; VariableSymbol* variable = (VariableSymbol*) name -> symbol; if (starting_set[variable -> LocalVariableIndex(this)]) { ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_UNASSIGNED_IN_LOOP, name -> LeftToken(), name -> RightToken(), variable -> Name()); } } DefiniteFinalAssignments() -> Pop(); } void Semantic::DefiniteWhileStatement(Ast* stmt) { AstWhileStatement* while_statement = (AstWhileStatement*) stmt; DefiniteFinalAssignments() -> Push(); BitSet starting_set(DefinitelyAssignedVariables() -> du_set); DefiniteAssignmentSet* after_expr = DefiniteBooleanExpression(while_statement -> expression, *DefinitelyAssignedVariables()); DefinitePair before_statement(Universe() -> Size()); if (after_expr) *DefinitelyAssignedVariables() = after_expr -> true_pair; else before_statement = *DefinitelyAssignedVariables(); // // We have already given a warning if the statement is unreachable // if (while_statement -> statement -> is_reachable) DefiniteBlock(while_statement -> statement); *DefinitelyAssignedVariables() *= DefiniteBlocks() -> TopContinuePair(); DefiniteLoopBody(starting_set); *DefinitelyAssignedVariables() = DefiniteBlocks() -> TopBreakPair() * (after_expr ? after_expr -> false_pair : before_statement); delete after_expr; } void Semantic::DefiniteForStatement(Ast* stmt) { AstForStatement* for_statement = (AstForStatement*) stmt; unsigned i; // // Note that in constructing the Ast, the parser encloses each // for-statement in its own block, so that any variables defined in the // for-init-statements have scope limited to the for loop. Thus, we do // not need to worry about declaring or reclaiming variables in the // for-init section in this method. // // For example, the following sequence of statements is legal: // // for (int i = 0; i < 10; i++); // for (int i = 10; i < 20; i++); // for (i = 0; i < for_statement -> NumForInitStatements(); i++) DefiniteStatement(for_statement -> ForInitStatement(i)); DefiniteFinalAssignments() -> Push(); BitSet starting_set(DefinitelyAssignedVariables() -> du_set); DefiniteAssignmentSet* after_end_expression = NULL; DefinitePair before_statement(Universe() -> Size()); if (for_statement -> end_expression_opt) after_end_expression = DefiniteBooleanExpression(for_statement -> end_expression_opt, *DefinitelyAssignedVariables()); if (after_end_expression) *DefinitelyAssignedVariables() = after_end_expression -> true_pair; else before_statement = *DefinitelyAssignedVariables(); // // We have already given a warning if the statement is unreachable // if (for_statement -> statement -> is_reachable) DefiniteBlock(for_statement -> statement); // // Compute the set of variables that are definitely assigned after the // contained statement and after every continue statement that may exit // the body of the for statement. // *DefinitelyAssignedVariables() *= DefiniteBlocks() -> TopContinuePair(); for (i = 0; i < for_statement -> NumForUpdateStatements(); i++) DefiniteExpressionStatement(for_statement -> ForUpdateStatement(i)); DefiniteLoopBody(starting_set); // // Compute the set of variables that belongs to both sets below: // // . the universe if no condition expression is present; // otherwise, the set of variables that are DA when // the condition expression is false. // // . the set of variables that are DA before every // break statement that may exit the for statement. // *DefinitelyAssignedVariables() = DefiniteBlocks() -> TopBreakPair() * (for_statement -> end_expression_opt ? (after_end_expression ? after_end_expression -> false_pair : before_statement) : *Universe()); delete after_end_expression; // harmless if NULL } void Semantic::DefiniteForeachStatement(Ast* stmt) { AstForeachStatement* for_statement = (AstForeachStatement*) stmt; // // Note that in constructing the Ast, the parser encloses each // for-statement in its own block, so that the loop variable defined in // the formal parameter has scope limited to the for loop. Thus, we do // not need to worry about declaring or reclaiming variables in the // for-init section in this method. // // For example, the following sequence of statements is legal: // // for (int i : new int[0]); // for (int i : new int[0]); // AstVariableDeclarator* variable_declarator = for_statement -> formal_parameter -> formal_declarator; VariableSymbol* variable_symbol = variable_declarator -> symbol; if (variable_symbol) { int index = variable_symbol -> LocalVariableIndex(this); if (control.option.g & JikesOption::VARS) { #ifdef DUMP Coutput << "(3.6) Foreach Variable \"" << variable_symbol -> Name() << " #" << index << "\" is declared at line " << lex_stream -> Line(variable_declarator -> LeftToken()) << endl; #endif // DUMP DefiniteBlocks() -> TopBlock() -> AddLocallyDefinedVariable(variable_symbol); } DefinitelyAssignedVariables() -> AssignElement(index); } DefiniteExpression(for_statement -> expression, *DefinitelyAssignedVariables()); BitSet starting_set(DefinitelyAssignedVariables() -> du_set); DefinitePair before_statement(*DefinitelyAssignedVariables()); DefiniteFinalAssignments() -> Push(); // // We have already given a warning if the statement is unreachable // if (for_statement -> statement -> is_reachable) DefiniteBlock(for_statement -> statement); // // Compute the set of variables that are definitely assigned after the // contained statement and after every continue statement that may exit // the body of the for statement. // *DefinitelyAssignedVariables() *= DefiniteBlocks() -> TopContinuePair(); DefiniteLoopBody(starting_set); // // Compute the set of variables that are DA before every break statement // that may exit the for statement. // *DefinitelyAssignedVariables() = DefiniteBlocks() -> TopBreakPair() * before_statement; } void Semantic::DefiniteDoStatement(Ast* stmt) { AstDoStatement* do_statement = (AstDoStatement*) stmt; DefiniteFinalAssignments() -> Push(); BitSet starting_set(DefinitelyAssignedVariables() -> du_set); DefiniteBlock(do_statement -> statement); DefinitePair after_stmt(*DefinitelyAssignedVariables()); *DefinitelyAssignedVariables() *= DefiniteBlocks() -> TopContinuePair(); DefiniteAssignmentSet* after_expr = DefiniteBooleanExpression(do_statement -> expression, *DefinitelyAssignedVariables()); DefinitePair after_loop(Universe() -> Size()); if (after_expr) *DefinitelyAssignedVariables() = after_expr -> true_pair; else after_loop = *DefinitelyAssignedVariables(); DefiniteLoopBody(starting_set); *DefinitelyAssignedVariables() = DefiniteBlocks() -> TopBreakPair() * (after_expr ? after_expr -> false_pair : after_loop); delete after_expr; } void Semantic::DefiniteSwitchStatement(Ast* stmt) { AstSwitchStatement* switch_statement = (AstSwitchStatement*) stmt; AstBlock* block_body = switch_statement -> switch_block; DefiniteBlocks() -> Push(block_body); DefiniteExpression(switch_statement -> expression, *DefinitelyAssignedVariables()); DefinitePair starting_pair(*DefinitelyAssignedVariables()); // // Recall that the parser inserts an empty statement if necessary after // the last label, so that all SwitchBlockStatementGroups have statements. // The standard does not allow us to optimize for a constant switch, or // for enumerating all 256 byte cases with no default. // unsigned i; for (i = 0; i < block_body -> NumStatements(); i++) { AstSwitchBlockStatement* switch_block_statement = (AstSwitchBlockStatement*) block_body -> Statement(i); *DefinitelyAssignedVariables() *= starting_pair; DefiniteBlockStatements(switch_block_statement); } if (! switch_statement -> DefaultCase()) *DefinitelyAssignedVariables() *= starting_pair; *DefinitelyAssignedVariables() *= DefiniteBlocks() -> TopBreakPair(); // // Remove all variables that just went out of scope // for (i = 0; i < block_body -> block_symbol -> NumVariableSymbols(); i++) { VariableSymbol* variable = block_body -> block_symbol -> VariableSym(i); int index = variable -> LocalVariableIndex(this); BlankFinals() -> RemoveElement(index); ReachableAssignments() -> RemoveElement(index); DefinitelyAssignedVariables() -> ReclaimElement(index); } DefiniteBlocks() -> Pop(); } void Semantic::DefiniteBreakStatement(Ast* stmt) { AstBreakStatement* break_statement = (AstBreakStatement*) stmt; // // Compute the set of variables that are definitely assigned prior to // executing the break, including if the break occurs in a try or catch // block. // if (AbruptFinallyStack().Top() < break_statement -> nesting_level) { DefiniteBlocks() -> BreakPair(break_statement -> nesting_level) *= *DefinitelyAssignedVariables(); } // // After execution of a break statement, it is vacuously true // that every variable has definitely been assigned and no final // variable has been possibly assigned (as nothing is reachable // any way). // *DefinitelyAssignedVariables() = *Universe(); } void Semantic::DefiniteContinueStatement(Ast* stmt) { AstContinueStatement* continue_statement = (AstContinueStatement*) stmt; // // Compute the set of variables that are definitely assigned prior to // executing the continue, including if the continue occurs in a try or // catch block. // if (AbruptFinallyStack().Top() < continue_statement -> nesting_level) { DefiniteBlocks() -> ContinuePair(continue_statement -> nesting_level) *= *DefinitelyAssignedVariables(); } // // After execution of a continue statement, it is vacuously true // that every variable has definitely been assigned and no final // variable has been possibly assigned (as nothing is reachable // any way). // *DefinitelyAssignedVariables() = *Universe(); } void Semantic::DefiniteReturnStatement(Ast* stmt) { AstReturnStatement* return_statement = (AstReturnStatement*) stmt; if (return_statement -> expression_opt) DefiniteExpression(return_statement -> expression_opt, *DefinitelyAssignedVariables()); if (AbruptFinallyStack().Top() == 0) DefiniteBlocks() -> ReturnPair() *= *DefinitelyAssignedVariables(); // // After execution of a return statement, it is vacuously true // that every variable has definitely been assigned and no final // variable has been possibly assigned (as nothing is reachable // any way). // *DefinitelyAssignedVariables() = *Universe(); } void Semantic::DefiniteThrowStatement(Ast* stmt) { AstThrowStatement* throw_statement = (AstThrowStatement*) stmt; DefiniteExpression(throw_statement -> expression, *DefinitelyAssignedVariables()); // // After execution of a throw statement, it is vacuously true // that every variable has definitely been assigned and no final // variable has been possibly assigned (as nothing is reachable // any way). // *DefinitelyAssignedVariables() = *Universe(); } void Semantic::DefiniteTryStatement(Ast* stmt) { AstTryStatement* try_statement = (AstTryStatement*) stmt; if (try_statement -> finally_clause_opt && (! try_statement -> finally_clause_opt -> block -> can_complete_normally)) { AbruptFinallyStack().Push(try_statement -> finally_clause_opt -> block -> nesting_level); } DefinitePair starting_pair(*DefinitelyAssignedVariables()); BitSet already_assigned(*ReachableAssignments()); ReachableAssignments() -> SetEmpty(); DefiniteBlock(try_statement -> block); BitSet before_catch_finals(starting_pair.du_set - *ReachableAssignments()), possibly_finals_union(DefinitelyAssignedVariables() -> du_set); // // We initialize the variable after_blocks here. It is used to calculate // intersection of the set of variables that are definitely assigned by // all the blocks: the try block, all the catch blocks, if any, and the // finally block, if there is one. // BitSet after_blocks(DefinitelyAssignedVariables() -> da_set); // // Recall that the body of the catch blocks must not be // processed within the environment of the associated try whose // exceptions they are supposed to catch but within the immediate // enclosing block (which may itself be a try block). // for (unsigned i = 0; i < try_statement -> NumCatchClauses(); i++) { DefinitelyAssignedVariables() -> da_set = starting_pair.da_set; DefinitelyAssignedVariables() -> du_set = before_catch_finals; AstCatchClause* clause = try_statement -> CatchClause(i); // // The catch clause parameter must be added, in case it is final. // It is already initialized. // VariableSymbol* variable = clause -> parameter_symbol; int index = variable -> LocalVariableIndex(this); DefinitelyAssignedVariables() -> AddElement(index); if (control.option.g & JikesOption::VARS) { #ifdef DUMP Coutput << "(7) Variable \"" << variable -> Name() << " #" << index << "\" is defined at line " << lex_stream -> Line(clause -> formal_parameter -> LeftToken()) << endl; #endif // DUMP } DefiniteBlock(clause -> block); // // The parameter goes out of scope. We do not need to remove it from // reachable assignments, since if it was final, it can't be assigned. // DefinitelyAssignedVariables() -> ReclaimElement(index); #ifdef DUMP VariableSymbol* variable = clause -> parameter_symbol; if (control.option.g & JikesOption::VARS) Coutput << "(8) Variable \"" << variable -> Name() << " #" << index << "\" goes out of scope at line " << lex_stream -> Line(clause -> formal_parameter -> RightToken()) << endl; #endif // DUMP // // Process the set of variables that were definitely assigned // after this catch block // possibly_finals_union *= DefinitelyAssignedVariables() -> du_set; after_blocks *= DefinitelyAssignedVariables() -> da_set; } // // Like the catch clauses, a finally block must not be processed // in the environment of its associated try block but in the // environment of its immediate enclosing block. // if (try_statement -> finally_clause_opt) { if (! try_statement -> finally_clause_opt -> block -> can_complete_normally) { AbruptFinallyStack().Pop(); } DefinitelyAssignedVariables() -> da_set = starting_pair.da_set; DefinitelyAssignedVariables() -> du_set = starting_pair.du_set - *ReachableAssignments(); DefiniteBlock(try_statement -> finally_clause_opt -> block); DefinitelyAssignedVariables() -> da_set += after_blocks; } else { DefinitelyAssignedVariables() -> da_set = after_blocks; DefinitelyAssignedVariables() -> du_set = possibly_finals_union; } *ReachableAssignments() += already_assigned; } void Semantic::DefiniteAssertStatement(Ast* stmt) { AstAssertStatement* assert_statement = (AstAssertStatement*) stmt; // // Remember what variables were assigned beforehand. // DefinitePair before_assert(*DefinitelyAssignedVariables()); DefiniteAssignmentSet* after_condition = DefiniteBooleanExpression(assert_statement -> condition, *DefinitelyAssignedVariables()); if (after_condition) { // // The second expression is evaluated only when the first is false // Don't modify da, but update du, as a variable is DU after the assert // iff it is DU before the assert and DU after the condition when true. // *DefinitelyAssignedVariables() = after_condition -> false_pair; before_assert.du_set *= after_condition -> true_pair.du_set; } else before_assert.du_set *= DefinitelyAssignedVariables() -> du_set; if (assert_statement -> message_opt) DefiniteExpression(assert_statement -> message_opt, *DefinitelyAssignedVariables()); // // Restore definitely assigned variables to what they were before, // since asserts may be disabled // *DefinitelyAssignedVariables() = before_assert; // harmless if NULL delete after_condition; } // // Called only from DefiniteConstructorBody, for this() calls. // void Semantic::DefiniteThisCall(AstThisCall* this_call) { for (unsigned i = 0; i < this_call -> arguments -> NumArguments(); i++) DefiniteExpression(this_call -> arguments -> Argument(i), *DefinitelyAssignedVariables()); } // // Called only from DefiniteConstructorBody, for super() calls. // void Semantic::DefiniteSuperCall(AstSuperCall* super_call) { if (super_call -> base_opt) DefiniteExpression(super_call -> base_opt, *DefinitelyAssignedVariables()); for (unsigned i = 0; i < super_call -> arguments -> NumArguments(); i++) DefiniteExpression(super_call -> arguments -> Argument(i), *DefinitelyAssignedVariables()); } void Semantic::DefiniteMethodBody(AstMethodDeclaration* method_declaration) { unsigned i; assert(FinalFields()); AstBlock* block_body = method_declaration -> method_body_opt; if (! block_body) return; #ifdef DUMP if (control.option.g & JikesOption::VARS) Coutput << "(9) Processing method \"" << method_declaration -> method_symbol -> Name() << "\" in " << ThisType() -> ContainingPackageName() << "/" << ThisType() -> ExternalName() << endl; #endif // DUMP int size = block_body -> block_symbol -> max_variable_index + FinalFields() -> Length(); Universe() -> Resize(size, BitSet::UNIVERSE); int stack_size = method_declaration -> method_symbol -> max_block_depth; DefiniteBlocks() = new DefiniteBlockStack(stack_size, size); DefinitelyAssignedVariables() -> Resize(size); BlankFinals() -> Resize(size, BitSet::EMPTY); ReachableAssignments() -> Resize(size, BitSet::EMPTY); DefiniteBlocks() -> Push(block_body); AstMethodDeclarator* method_declarator = method_declaration -> method_declarator; for (i = 0; i < method_declarator -> NumFormalParameters(); i++) { AstVariableDeclarator* formal_declarator = method_declarator -> FormalParameter(i) -> formal_declarator; DefinitelyAssignedVariables() -> AssignElement(formal_declarator -> symbol -> LocalVariableIndex(this)); #ifdef DUMP if (control.option.g & JikesOption::VARS) { VariableSymbol* variable = formal_declarator -> symbol; Coutput << "(10) Variable \"" << variable -> Name() << " #" << variable -> LocalVariableIndex(this) << "\" is defined at line " << lex_stream -> Line(formal_declarator -> LeftToken()) << endl; } #endif // DUMP } DefiniteBlockStatements(block_body); #ifdef DUMP if ((control.option.g & JikesOption::VARS) && block_body -> NumLocallyDefinedVariables() > 0) { Coutput << "(11) At Line " << lex_stream -> Line(block_body -> RightToken()) << " the range for the following variables end:" << endl << endl; for (i = 0; i < block_body -> NumLocallyDefinedVariables(); i++) Coutput << " \"" << block_body -> LocallyDefinedVariable(i) -> Name() << "\"" << endl; } #endif // DUMP DefiniteBlocks() -> Pop(); delete DefiniteBlocks(); DefiniteBlocks() = NULL; size = FinalFields() -> Length(); Universe() -> Resize(size); DefinitelyAssignedVariables() -> Resize(size); BlankFinals() -> Resize(size); ReachableAssignments() -> Resize(size); } void Semantic::DefiniteConstructorBody(AstConstructorDeclaration* constructor_declaration) { unsigned i; assert(FinalFields()); #ifdef DUMP if (control.option.g & JikesOption::VARS) Coutput << "(12) Processing constructor \"" << constructor_declaration -> constructor_symbol -> Name() << "\" in " << ThisType() -> ContainingPackageName() << "/" << ThisType() -> ExternalName() << endl; #endif // DUMP AstMethodBody* block_body = constructor_declaration -> constructor_body; int size = block_body -> block_symbol -> max_variable_index + FinalFields() -> Length(); Universe() -> Resize(size, BitSet::UNIVERSE); int stack_size = constructor_declaration -> constructor_symbol -> max_block_depth; DefiniteBlocks() = new DefiniteBlockStack(stack_size, size); DefinitelyAssignedVariables() -> Resize(size); BlankFinals() -> Resize(size, BitSet::EMPTY); ReachableAssignments() -> Resize(size, BitSet::EMPTY); DefiniteBlocks() -> Push(block_body); AstMethodDeclarator* constructor_declarator = constructor_declaration -> constructor_declarator; for (i = 0; i < constructor_declarator -> NumFormalParameters(); i++) { AstVariableDeclarator* formal_declarator = constructor_declarator -> FormalParameter(i) -> formal_declarator; DefinitelyAssignedVariables() -> AddElement(formal_declarator -> symbol -> LocalVariableIndex(this)); #ifdef DUMP if (control.option.g & JikesOption::VARS) { VariableSymbol* variable = formal_declarator -> symbol; Coutput << "(13) Variable \"" << variable -> Name() << " #" << variable -> LocalVariableIndex(this) << "\" is defined at line " << lex_stream -> Line(formal_declarator -> LeftToken()) << endl; } #endif // DUMP } if (block_body -> explicit_constructor_opt) { if (block_body -> explicit_constructor_opt -> ThisCallCast()) DefiniteThisCall((AstThisCall*) block_body -> explicit_constructor_opt); else DefiniteSuperCall((AstSuperCall*) block_body -> explicit_constructor_opt); } DefiniteBlockStatements(block_body); #ifdef DUMP if ((control.option.g & JikesOption::VARS) && block_body -> NumLocallyDefinedVariables() > 0) { Coutput << "(14) At Line " << lex_stream -> Line(block_body -> RightToken()) << " the range for the following variables end:" << endl << endl; for (unsigned j = 0; j < block_body -> NumLocallyDefinedVariables(); j++) Coutput << " \"" << block_body -> LocallyDefinedVariable(j) -> Name() << "\"" << endl; } #endif // DUMP // // Compute the set of finals that has definitely been assigned in this // constructor. // *DefinitelyAssignedVariables() *= DefiniteBlocks() -> ReturnPair(); DefiniteBlocks() -> Pop(); delete DefiniteBlocks(); DefiniteBlocks() = NULL; size = FinalFields() -> Length(); Universe() -> Resize(size); DefinitelyAssignedVariables() -> Resize(size); BlankFinals() -> Resize(size); ReachableAssignments() -> Resize(size); } void Semantic::DefiniteBlockInitializer(AstBlock* block_body, int stack_size) { assert(FinalFields()); #ifdef DUMP if (control.option.g & JikesOption::VARS) Coutput << "(15) Processing Initializer block in " << ThisType() -> ContainingPackageName() << "/" << ThisType() -> ExternalName() << endl; #endif // DUMP int size = block_body -> block_symbol -> max_variable_index + FinalFields() -> Length(); Universe() -> Resize(size, BitSet::UNIVERSE); DefiniteBlocks() = new DefiniteBlockStack(stack_size, size); DefinitelyAssignedVariables() -> Resize(size); BlankFinals() -> Resize(size, BitSet::EMPTY); ReachableAssignments() -> Resize(size, BitSet::EMPTY); DefiniteBlocks() -> Push(block_body); DefiniteBlockStatements(block_body); #ifdef DUMP if ((control.option.g & JikesOption::VARS) && block_body -> NumLocallyDefinedVariables() > 0) { Coutput << "(16) At Line " << lex_stream -> Line(block_body -> RightToken()) << " the range for the following variables end:" << endl << endl; for (i = 0; i < block_body -> NumLocallyDefinedVariables(); i++) Coutput << " \"" << block_body -> LocallyDefinedVariable(i) -> Name() << "\"" << endl; } #endif // DUMP DefiniteBlocks() -> Pop(); delete DefiniteBlocks(); DefiniteBlocks() = NULL; size = FinalFields() -> Length(); Universe() -> Resize(size); DefinitelyAssignedVariables() -> Resize(size); BlankFinals() -> Resize(size); ReachableAssignments() -> Resize(size); } void Semantic::DefiniteFieldInitializer(AstVariableDeclarator* variable_declarator) { assert(FinalFields()); DefiniteVariableInitializer(variable_declarator); if (variable_declarator -> symbol -> ACC_FINAL()) { DefinitelyAssignedVariables() -> AssignElement(variable_declarator -> symbol -> LocalVariableIndex()); } } void Semantic::DefiniteSetup() { // // Compute the set of final variables (all fields in an interface are // final) in this type. Then process all initializers. // assert(! FinalFields()); TypeSymbol* this_type = ThisType(); FinalFields() = new Tuple (this_type -> NumVariableSymbols()); int size = 0; for (unsigned i = 0; i < this_type -> NumVariableSymbols(); i++) { VariableSymbol* variable_symbol = this_type -> VariableSym(i); if (variable_symbol -> ACC_FINAL() && ! variable_symbol -> ACC_SYNTHETIC()) { variable_symbol -> SetLocalVariableIndex(size++); FinalFields() -> Next() = variable_symbol; } } Universe() = new DefinitePair(size, BitSet::UNIVERSE); DefiniteFinalAssignments() = new DefiniteFinalAssignmentStack(); DefinitelyAssignedVariables() = new DefinitePair(size); BlankFinals() = new BitSet(size, BitSet::EMPTY); ReachableAssignments() = new BitSet(size, BitSet::EMPTY); for (int j = 0; j < size; j++) { VariableSymbol* final_var = (*FinalFields())[j]; if (! final_var -> declarator -> variable_initializer_opt) BlankFinals() -> AddElement(j); } } void Semantic::DefiniteCleanUp() { assert (FinalFields()); delete FinalFields(); FinalFields() = NULL; delete Universe(); delete DefinitelyAssignedVariables(); delete DefiniteFinalAssignments(); delete BlankFinals(); delete ReachableAssignments(); } #ifdef HAVE_JIKES_NAMESPACE } // Close namespace Jikes block #endif