// $Id: definite.cpp,v 1.5 1999/03/10 19:59:21 shields Exp $ copyright notice #include "config.h" #include <assert.h> #include <stdio.h> #include "semantic.h" DefiniteAssignmentSet *Semantic::DefiniteExpression(AstExpression *expr, BitSet &set) { DefiniteAssignmentSet *definite = NULL; // // Is the expression a constant expression of type boolean? // Recall that a constant expression may not contain an // assignment statement. // if (expr -> IsConstant() && expr -> Type() == control.boolean_type) { definite = new DefiniteAssignmentSet(universe -> Size()); IntLiteralValue *result = (IntLiteralValue *) expr -> value; if (result -> value) { definite -> true_set = set; definite -> false_set = *universe; } else { definite -> true_set = *universe; definite -> false_set = set; } } else if (expr -> symbol != control.no_type) definite = (this ->* DefiniteExpr[expr -> kind])(expr, set); return definite; } DefiniteAssignmentSet *Semantic::DefiniteSimpleName(AstExpression *expression, BitSet &set) { AstSimpleName *simple_name = (AstSimpleName *) expression; if (simple_name -> resolution_opt) return DefiniteExpression(simple_name -> resolution_opt, set); // // Some simple names are undefined. e.g., the simple name in a method call. // VariableSymbol *variable = (simple_name -> symbol ? simple_name -> symbol -> VariableCast() : (VariableSymbol *) NULL); if (variable && (variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType()))) { if (! set[variable -> LocalVariableIndex()]) { ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_ASSIGNED, simple_name -> identifier_token, simple_name -> identifier_token, variable -> Name()); if (variable -> IsLocal(ThisMethod())) // to avoid cascading errors! set.AddElement(variable -> LocalVariableIndex()); } } return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefiniteArrayAccess(AstExpression *expression, BitSet &set) { AstArrayAccess *array_access = (AstArrayAccess *) expression; DefiniteAssignmentSet *after_base = DefiniteExpression(array_access -> base, set); if (after_base) // if this is true then something is wrong { set = after_base -> true_set * after_base -> false_set; delete after_base; } DefiniteAssignmentSet *after_expr = DefiniteExpression(array_access -> expression, set); if (after_expr) // if this is true then something is wrong { set = after_expr -> true_set * after_expr -> false_set; delete after_expr; } return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefiniteMethodInvocation(AstExpression *expression, BitSet &set) { AstMethodInvocation *method_call = (AstMethodInvocation *) expression; DefiniteAssignmentSet *after_method = DefiniteExpression(method_call -> method, set); if (after_method) { set = after_method -> true_set * after_method -> false_set; delete after_method; } for (int i = 0; i < method_call -> NumArguments(); i++) { AstExpression *expr = method_call -> Argument(i); DefiniteAssignmentSet *after_expr = DefiniteExpression(expr, set); if (after_expr) { set = after_expr -> true_set * after_expr -> false_set; delete after_expr; } } return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefiniteClassInstanceCreationExpression(AstExpression *expression, BitSet &set) { AstClassInstanceCreationExpression *class_creation = (AstClassInstanceCreationExpression *) expression; if (class_creation -> base_opt) { DefiniteAssignmentSet *after_expr = DefiniteExpression(class_creation -> base_opt, set); if (after_expr) { set = after_expr -> true_set * after_expr -> false_set; delete after_expr; } } for (int i = 0; i < class_creation -> NumLocalArguments(); i++) { AstExpression *expr = class_creation -> LocalArgument(i); DefiniteAssignmentSet *after_expr = DefiniteExpression(expr, set); if (after_expr) { set = after_expr -> true_set * after_expr -> false_set; delete after_expr; } } for (int k = 0; k < class_creation -> NumArguments(); k++) { AstExpression *expr = class_creation -> Argument(k); DefiniteAssignmentSet *after_expr = DefiniteExpression(expr, set); if (after_expr) { set = after_expr -> true_set * after_expr -> false_set; delete after_expr; } } return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefiniteArrayCreationExpression(AstExpression *expression, BitSet &set) { AstArrayCreationExpression *array_creation = (AstArrayCreationExpression *) expression; for (int i = 0; i < array_creation -> NumDimExprs(); i++) { AstDimExpr *dim_expr = array_creation -> DimExpr(i); DefiniteAssignmentSet *after_expr = DefiniteExpression(dim_expr -> expression, set); if (after_expr) { set = after_expr -> true_set * after_expr -> false_set; delete after_expr; } } if (array_creation -> array_initializer_opt) DefiniteArrayInitializer(array_creation -> array_initializer_opt); return (DefiniteAssignmentSet *) 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())) { if (variable -> ACC_STATIC()) // there is exactly one copy of a static variable, so, it's always the right one. return variable; AstFieldAccess *sub_field_access = field_access -> base -> FieldAccessCast(); if (field_access -> base -> ThisExpressionCast() || (sub_field_access && sub_field_access -> IsThisAccess())) return variable; } } return NULL; } DefiniteAssignmentSet *Semantic::DefinitePLUSPLUSOrMINUSMINUS(AstExpression *expr, BitSet &set) { DefiniteAssignmentSet *definite = DefiniteExpression(expr, set); if (definite) // if this is true then something is wrong { set = definite -> true_set * definite -> false_set; delete definite; } VariableSymbol *variable = NULL; if (! expr -> ArrayAccessCast()) // some kind of name { MethodSymbol *read_method = NULL; AstSimpleName *simple_name = expr -> SimpleNameCast(); if (simple_name) { if (simple_name -> resolution_opt) read_method = simple_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()); } // // If we have a variable and it is final then... // if (variable && variable -> ACC_FINAL()) { ReportSemError(SemanticError::TARGET_VARIABLE_IS_FINAL, expr -> LeftToken(), expr -> RightToken(), variable -> Name()); if (variable -> IsFinal(ThisType())) // if the final variable in contained in this type, then mark it assigned possibly_assigned_finals -> AddElement(variable -> LocalVariableIndex()); } return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefinitePostUnaryExpression(AstExpression *expression, BitSet &set) { AstPostUnaryExpression *postfix_expression = (AstPostUnaryExpression *) expression; return DefinitePLUSPLUSOrMINUSMINUS(postfix_expression -> expression, set); } DefiniteAssignmentSet *Semantic::DefiniteNOT(AstExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_expr = DefiniteExpression(expr, set); if (after_expr) // is the expression is a complex boolean expression? { BitSet temp(after_expr -> true_set); after_expr -> true_set = after_expr -> false_set; after_expr -> false_set = 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, BitSet &set) { return (this ->* DefiniteExpr[expr -> kind])(expr, set); } DefiniteAssignmentSet *Semantic::DefinitePreUnaryExpression(AstExpression *expression, BitSet &set) { AstPreUnaryExpression *prefix_expression = (AstPreUnaryExpression *) expression; return (this ->* DefinitePreUnaryExpr[prefix_expression -> pre_unary_tag])(prefix_expression -> expression, set); } DefiniteAssignmentSet *Semantic::DefiniteAssignmentAND(TypeSymbol *type, BitSet *before_right, BitSet &set, DefiniteAssignmentSet *after_left, DefiniteAssignmentSet *after_right) { if (after_left || after_right) // one of the subexpressions is a complex boolean expression { if (! after_left) { after_left = new DefiniteAssignmentSet(universe -> Size()); after_left -> true_set = *before_right; after_left -> false_set = *before_right; } if (! after_right) { after_right = new DefiniteAssignmentSet(universe -> Size()); after_right -> true_set = set; after_right -> false_set = set; } after_left -> true_set += after_right -> true_set; // definitely assigned after left when true and after right when true after_left -> false_set *= after_right -> false_set; // definitely assigned after left when false and after right when false after_right -> true_set *= after_right -> false_set; // definitely assigned after right after_left -> false_set += after_right -> true_set; delete after_right; } delete before_right; // nothing happens if before_right is null return after_left; } DefiniteAssignmentSet *Semantic::DefiniteAssignmentIOR(TypeSymbol *type, BitSet *before_right, BitSet &set, DefiniteAssignmentSet *after_left, DefiniteAssignmentSet *after_right) { if (after_left || after_right) // one of the subexpressions is a complex boolean expression { if (! after_left) { after_left = new DefiniteAssignmentSet(universe -> Size()); after_left -> true_set = *before_right; after_left -> false_set = *before_right; } if (! after_right) { after_right = new DefiniteAssignmentSet(universe -> Size()); after_right -> true_set = set; after_right -> false_set = set; } after_left -> true_set *= after_right -> true_set; // after a when true and after b when true after_right -> true_set *= after_right -> false_set; // definitely assigned after b after_left -> true_set += after_right -> true_set; after_left -> false_set += after_right -> false_set; // after a when false or after b when false delete after_right; } delete before_right; // nothing happens if before_right is null return after_left; } DefiniteAssignmentSet *Semantic::DefiniteAssignmentXOR(TypeSymbol *type, BitSet *before_right, BitSet &set, DefiniteAssignmentSet *after_left, DefiniteAssignmentSet *after_right) { DefiniteAssignmentSet *definite = NULL; if (after_left || after_right) // one of the subexpressions is a complex boolean expression { definite = new DefiniteAssignmentSet(universe -> Size()); if (! after_left) { after_left = new DefiniteAssignmentSet(universe -> Size()); after_left -> true_set = *before_right; after_left -> false_set = *before_right; } if (! after_right) { after_right = new DefiniteAssignmentSet(universe -> Size()); after_right -> true_set = set; after_right -> false_set = set; } // // compute definitely assigned after right. // definite -> true_set = definite -> false_set = (after_right -> true_set * after_right -> false_set); // // compute definitely assigned after left when true and after right when true // compute definitely assigned after left when false and after right when false // add the union of these two sets to true_set; // definite -> true_set += (after_left -> true_set * after_right -> true_set) + (after_left -> false_set * after_right -> false_set); // // compute definitely assigned after left when true and after right when false // compute definitely assigned after left when false and after right when true // add the union of these two sets to false_set; // definite -> false_set += (after_left -> true_set * after_right -> false_set) + (after_left -> false_set * after_right -> true_set); delete after_left; delete after_right; } delete before_right; // nothing happens if before_right is NULL return definite; } DefiniteAssignmentSet *Semantic::DefiniteAND(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); BitSet *before_right = NULL; if (after_left) set = after_left -> true_set * after_left -> false_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); return DefiniteAssignmentAND(expr -> left_expression -> Type(), before_right, set, after_left, after_right); } DefiniteAssignmentSet *Semantic::DefiniteIOR(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); BitSet *before_right = NULL; if (after_left) set = after_left -> true_set * after_left -> false_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); return DefiniteAssignmentIOR(expr -> left_expression -> Type(), before_right, set, after_left, after_right); } DefiniteAssignmentSet *Semantic::DefiniteXOR(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); BitSet *before_right = NULL; if (after_left) set = after_left -> true_set * after_left -> false_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); return DefiniteAssignmentXOR(expr -> left_expression -> Type(), before_right, set, after_left, after_right); } DefiniteAssignmentSet *Semantic::DefiniteAND_AND(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); BitSet *before_right = NULL; if (after_left) set = after_left -> true_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); if (after_left) { if (after_right) { after_left -> true_set += after_right -> true_set; after_left -> false_set *= after_right -> false_set; delete after_right; } else { after_left -> true_set += set; after_left -> false_set *= set; } after_right = after_left; } else { if (! after_right) { after_right = new DefiniteAssignmentSet(universe -> Size()); after_right -> true_set = set; after_right -> false_set = set; } after_right -> true_set += *before_right; after_right -> false_set *= *before_right; delete before_right; } return after_right; } DefiniteAssignmentSet *Semantic::DefiniteOR_OR(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); BitSet *before_right = NULL; if (after_left) set = after_left -> false_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); if (after_left) { if (after_right) { after_left -> true_set *= after_right -> true_set; after_left -> false_set += after_right -> false_set; delete after_right; } else { after_left -> true_set *= set; after_left -> false_set += set; } after_right = after_left; } else { if (! after_right) { after_right = new DefiniteAssignmentSet(universe -> Size()); after_right -> true_set = set; after_right -> false_set = set; } after_right -> true_set *= *before_right; after_right -> false_set += *before_right; delete before_right; } return after_right; } DefiniteAssignmentSet *Semantic::DefiniteEQUAL_EQUAL(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); BitSet *before_right = NULL; if (after_left) set = after_left -> true_set * after_left -> false_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); DefiniteAssignmentSet *definite = NULL; if (after_left || after_right) // one of the subexpressions is a complex boolean expression { definite = new DefiniteAssignmentSet(universe -> Size()); if (! after_left) { after_left = new DefiniteAssignmentSet(universe -> Size()); after_left -> true_set = *before_right; after_left -> false_set = *before_right; } if (! after_right) { after_right = new DefiniteAssignmentSet(universe -> Size()); after_right -> true_set = set; after_right -> false_set = set; } // // compute definitely assigned after right. // definite -> true_set = definite -> false_set = (after_right -> true_set * after_right -> false_set); // // compute definitely assigned after left when true and after right when false // compute definitely assigned after left when false and after right when true // and add their union to true_set // definite -> true_set += (after_left -> true_set * after_right -> false_set) + (after_left -> false_set * after_right -> true_set); // // compute definitely assigned after left when true and after right when true // compute definitely assigned after left when false and after right when false // and add their union to false_set // definite -> false_set += (after_left -> true_set * after_right -> true_set) + (after_left -> false_set * after_right -> false_set); delete after_left; delete after_right; } delete before_right; // nothing happens if before_right is NULL return definite; } DefiniteAssignmentSet *Semantic::DefiniteNOT_EQUAL(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); BitSet *before_right = NULL; if (after_left) set = after_left -> true_set * after_left -> false_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); // // NOT_EQUAL has same definite assignment rules as XOR // return DefiniteAssignmentXOR(expr -> left_expression -> Type(), before_right, set, after_left, after_right); } DefiniteAssignmentSet *Semantic::DefiniteDefaultBinaryExpression(AstBinaryExpression *expr, BitSet &set) { DefiniteAssignmentSet *after_left = DefiniteExpression(expr -> left_expression, set); if (after_left) // if this is true there was a mistake !!! { set = after_left -> true_set * after_left -> false_set; delete after_left; } DefiniteAssignmentSet *after_right = DefiniteExpression(expr -> right_expression, set); if (after_right) // if this is true there was a mistake !!! { set = (after_right -> true_set * after_right -> false_set); delete after_right; } return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefiniteBinaryExpression(AstExpression *expression, BitSet &set) { AstBinaryExpression *binary_expression = (AstBinaryExpression *) expression; return (this ->* DefiniteBinaryExpr[binary_expression -> binary_tag])(binary_expression, set); } DefiniteAssignmentSet *Semantic::DefiniteConditionalExpression(AstExpression *expression, BitSet &set) { AstConditionalExpression *conditional_expression = (AstConditionalExpression *) expression; DefiniteAssignmentSet *after_condition = DefiniteExpression(conditional_expression -> test_expression, set); BitSet *before_expressions = NULL; if (after_condition) set = after_condition -> true_set; else before_expressions = new BitSet(set); DefiniteAssignmentSet *after_true = DefiniteExpression(conditional_expression -> true_expression, set); BitSet *after_true_set = (BitSet *) (after_true ? NULL : new BitSet(set)); if (after_condition) set = after_condition -> false_set; else set = *before_expressions; DefiniteAssignmentSet *after_false = DefiniteExpression(conditional_expression -> false_expression, set); DefiniteAssignmentSet *definite = NULL; if (conditional_expression -> Type() == control.boolean_type) { definite = new DefiniteAssignmentSet(universe -> Size()); // // // if (after_true) { // // before "true" expr or after it when true // definite -> true_set = after_true -> true_set + (after_condition ? after_condition -> true_set : *before_expressions); } else definite -> true_set = *after_true_set; if (after_false) { // // before "false" expr or after it when true // definite -> true_set *= (after_false -> true_set + (after_condition ? after_condition -> false_set : *before_expressions)); } else definite -> true_set *= set; // // // if (after_true) { // // before "true" expr or after it when false // definite -> false_set = after_true -> false_set + (after_condition ? after_condition -> true_set : *before_expressions); } else definite -> false_set = *after_true_set; if (after_false) { // // before "false" expr or after it when true // definite -> true_set *= (after_false -> false_set + (after_condition ? after_condition -> false_set : *before_expressions)); } else definite -> false_set *= set; } else { if (after_false) set = after_false -> true_set * after_false -> false_set; // definitely assigned after the false expression ... // ... and definitely assigned after the true expression if (after_true) set *= (after_true -> true_set * after_true -> false_set); else set *= *after_true_set; } delete after_condition; // nothing happens if after_condition is NULL delete before_expressions; // nothing happens if before_expressions is NULL delete after_true; // nothing happens if after_true is NULL delete after_true_set; // nothing happens if after_true_set is NULL delete after_false; // nothing happens if after_false is NULL return definite; } DefiniteAssignmentSet *Semantic::DefiniteAssignmentExpression(AstExpression *expression, BitSet &set) { AstAssignmentExpression *assignment_expression = (AstAssignmentExpression *) expression; AstExpression *left_hand_side = assignment_expression -> left_hand_side; AstSimpleName *simple_name = left_hand_side -> SimpleNameCast(); if (simple_name) { if (simple_name -> resolution_opt) { left_hand_side = simple_name -> resolution_opt; simple_name = left_hand_side -> SimpleNameCast(); } } else { AstFieldAccess *field_access = left_hand_side -> FieldAccessCast(); if (field_access && field_access -> resolution_opt) left_hand_side = field_access -> resolution_opt; } VariableSymbol *variable = (left_hand_side -> symbol ? left_hand_side -> symbol -> VariableCast() : (VariableSymbol *) NULL); // // 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 && variable -> ACC_FINAL()) { if (variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType())) { // // variable already initialized ? // if ((assignment_expression -> assignment_tag != AstAssignmentExpression::EQUAL) || ((*possibly_assigned_finals) [variable -> LocalVariableIndex()])) { ReportSemError(SemanticError::TARGET_VARIABLE_IS_FINAL, left_hand_side -> LeftToken(), left_hand_side -> RightToken(), variable -> Name()); } else if (definite_final_assignment_stack -> Size() > 0) // are we processing the body of a loop ? definite_final_assignment_stack -> Top().Next() = left_hand_side; } else { ReportSemError(SemanticError::TARGET_VARIABLE_IS_FINAL, left_hand_side -> LeftToken(), left_hand_side -> RightToken(), variable -> Name()); } } DefiniteAssignmentSet *after_left = NULL; BitSet *before_right = NULL; // // The left-hand-side of an assignment expression is either a simple name, // a field access or an array access. // if (! simple_name) { AstFieldAccess *field_access = left_hand_side -> FieldAccessCast(); after_left = DefiniteExpression((field_access ? field_access -> base : left_hand_side), set); } if (after_left) set = after_left -> true_set * after_left -> false_set; else before_right = new BitSet(set); DefiniteAssignmentSet *after_right = DefiniteExpression(assignment_expression -> expression, set); if (left_hand_side -> Type() == control.boolean_type) { DefiniteAssignmentSet *definite = NULL; if (assignment_expression -> assignment_tag == AstAssignmentExpression::AND_EQUAL) definite = DefiniteAssignmentAND(control.boolean_type, before_right, set, after_left, after_right); else if (assignment_expression -> assignment_tag == AstAssignmentExpression::XOR_EQUAL) definite = DefiniteAssignmentXOR(control.boolean_type, before_right, set, after_left, after_right); else if (assignment_expression -> assignment_tag == AstAssignmentExpression::IOR_EQUAL) definite = DefiniteAssignmentIOR(control.boolean_type, before_right, set, after_left, after_right); else { delete after_left; delete before_right; definite = after_right; } if (variable && (variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType()))) { if (definite) { definite -> true_set.AddElement(variable -> LocalVariableIndex()); definite -> false_set.AddElement(variable -> LocalVariableIndex()); } else set.AddElement(variable -> LocalVariableIndex()); if (variable -> ACC_FINAL()) possibly_assigned_finals -> AddElement(variable -> LocalVariableIndex()); } return definite; } if (after_right) set = after_right -> true_set * after_right -> false_set; if (variable && (variable -> IsLocal(ThisMethod()) || variable -> IsFinal(ThisType()))) { set.AddElement(variable -> LocalVariableIndex()); if (variable -> ACC_FINAL()) possibly_assigned_finals -> AddElement(variable -> LocalVariableIndex()); } delete after_left; // nothing happens if after_left is NULL delete before_right; // nothing happens if before_right is NULL delete after_right; // nothing happens if after_right is NULL return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefiniteDefaultExpression(AstExpression *expr, BitSet &set) { return (DefiniteAssignmentSet *) NULL; } DefiniteAssignmentSet *Semantic::DefiniteParenthesizedExpression(AstExpression *expression, BitSet &set) { AstParenthesizedExpression *expr = (AstParenthesizedExpression *) expression; return DefiniteExpression(expr -> expression, set); } DefiniteAssignmentSet *Semantic::DefiniteFieldAccess(AstExpression *expression, BitSet &set) { AstFieldAccess *expr = (AstFieldAccess *) expression; VariableSymbol *variable = DefiniteFinal(expr); if (variable) { if (! set[variable -> LocalVariableIndex()]) { ReportSemError(SemanticError::VARIABLE_NOT_DEFINITELY_ASSIGNED, expr -> LeftToken(), expr -> RightToken(), variable -> Name()); set.AddElement(variable -> LocalVariableIndex()); } } return DefiniteExpression((expr -> resolution_opt ? expr -> resolution_opt : expr -> base), set); } DefiniteAssignmentSet *Semantic::DefiniteCastExpression(AstExpression *expression, BitSet &set) { AstCastExpression *expr = (AstCastExpression *) expression; return DefiniteExpression(expr -> expression, set); } void Semantic::DefiniteArrayInitializer(AstArrayInitializer *array_initializer) { for (int i = 0; i < array_initializer -> NumVariableInitializers(); i++) { AstArrayInitializer *sub_array_initializer = array_initializer -> VariableInitializer(i) -> ArrayInitializerCast(); if (sub_array_initializer) DefiniteArrayInitializer(sub_array_initializer); else { AstExpression *init = (AstExpression *) array_initializer -> VariableInitializer(i); DefiniteAssignmentSet *after_init = DefiniteExpression(init, *definitely_assigned_variables); if (after_init) { *definitely_assigned_variables = after_init -> true_set * after_init -> false_set; delete after_init; } } } return; } inline void Semantic::DefiniteVariableInitializer(AstVariableDeclarator *variable_declarator) { AstArrayInitializer *array_initializer = variable_declarator -> variable_initializer_opt -> ArrayInitializerCast(); if (array_initializer) DefiniteArrayInitializer(array_initializer); else { AstExpression *init = (AstExpression *) variable_declarator -> variable_initializer_opt; DefiniteAssignmentSet *after_init = DefiniteExpression(init, *definitely_assigned_variables); if (after_init) { *definitely_assigned_variables = after_init -> true_set * after_init -> false_set; delete after_init; } } return; } inline void Semantic::DefiniteBlockStatements(AstBlock *block_body) { for (int i = 0; i < block_body -> NumStatements(); i++) { AstStatement *statement = (AstStatement *) block_body -> Statement(i); if (statement -> is_reachable) DefiniteStatement(statement); else break; } return; } void Semantic::DefiniteBlock(Ast *stmt) { AstBlock *block_body = (AstBlock *) stmt; definite_block_stack -> Push(block_body); for (int i = 0; i < block_body -> block_symbol -> NumVariableSymbols(); i++) { VariableSymbol *variable = block_body -> block_symbol -> VariableSym(i); definitely_assigned_variables -> RemoveElement(variable -> LocalVariableIndex()); definite_visible_variables -> AddElement(variable); } DefiniteBlockStatements(block_body); for (int k = 0; k < block_body -> block_symbol -> NumVariableSymbols(); k++) definite_visible_variables -> RemoveElement(block_body -> block_symbol -> VariableSym(k)); // // 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_token_opt) *definitely_assigned_variables *= definite_block_stack -> TopBreakSet(); definite_block_stack -> Pop(); return; } void Semantic::DefiniteLocalVariableDeclarationStatement(Ast *stmt) { AstLocalVariableDeclarationStatement *local_decl = (AstLocalVariableDeclarationStatement *) stmt; for (int i = 0; i < local_decl -> NumVariableDeclarators(); i++) { AstVariableDeclarator *variable_declarator = local_decl -> VariableDeclarator(i); VariableSymbol *variable_symbol = variable_declarator -> symbol; if (variable_symbol) { if (variable_declarator -> variable_initializer_opt) { DefiniteVariableInitializer(variable_declarator); definitely_assigned_variables -> AddElement(variable_symbol -> LocalVariableIndex()); if (variable_symbol -> ACC_FINAL()) possibly_assigned_finals -> AddElement(variable_symbol -> LocalVariableIndex()); } else definitely_assigned_variables -> RemoveElement(variable_symbol -> LocalVariableIndex()); } } return; } void Semantic::DefiniteExpressionStatement(Ast *stmt) { AstExpressionStatement *expression_statement = (AstExpressionStatement *) stmt; DefiniteAssignmentSet *after_expr = DefiniteExpression(expression_statement -> expression, *definitely_assigned_variables); if (after_expr) { *definitely_assigned_variables = after_expr -> true_set * after_expr -> false_set; delete after_expr; } return; } void Semantic::DefiniteSynchronizedStatement(Ast *stmt) { AstSynchronizedStatement *synchronized_statement = (AstSynchronizedStatement *) stmt; DefiniteAssignmentSet *after_expr = DefiniteExpression(synchronized_statement -> expression, *definitely_assigned_variables); if (after_expr) { *definitely_assigned_variables = after_expr -> true_set * after_expr -> false_set; delete after_expr; } DefiniteBlock(synchronized_statement -> block); return; } void Semantic::DefiniteIfStatement(Ast *stmt) { AstIfStatement *if_statement = (AstIfStatement *) stmt; DefiniteAssignmentSet *after_expr = DefiniteExpression(if_statement -> expression, *definitely_assigned_variables); BitSet after_expr_finals(*possibly_assigned_finals); BitSet *starting_set = (after_expr ? (BitSet *) NULL : new BitSet(*definitely_assigned_variables)); if (after_expr) *definitely_assigned_variables = after_expr -> true_set; // // If the expression in the if-statement is a boolean constant expression then get its value. // IntLiteralValue *if_constant_expr = (if_statement -> expression -> Type() == control.boolean_type && if_statement -> expression -> IsConstant() ? (IntLiteralValue *) if_statement -> expression -> value : (IntLiteralValue *) NULL); // // If either the expression is not constant or its value is true, then // check the statement that make up the true part of the if statement // if ((! if_constant_expr) || if_constant_expr -> value) DefiniteBlock(if_statement -> true_statement); // // 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. // if (! if_statement -> false_statement_opt) // no else part ? { *definitely_assigned_variables *= (after_expr ? after_expr -> false_set : *starting_set); *possibly_assigned_finals += after_expr_finals; } else { BitSet after_true_finals(*possibly_assigned_finals); *possibly_assigned_finals = after_expr_finals; BitSet true_set(*definitely_assigned_variables); *definitely_assigned_variables = (after_expr ? after_expr -> false_set : *starting_set); if ((! if_constant_expr) || (! if_constant_expr -> value)) // either the expression is not constant or its value is false? DefiniteBlock(if_statement -> false_statement_opt); *definitely_assigned_variables *= true_set; *possibly_assigned_finals += after_true_finals; } delete after_expr; // nothing happens if after_expr is NULL delete starting_set; // nothing happens if starting_set is NULL return; } void Semantic::DefiniteLoopBody(AstStatement *statement) { definite_final_assignment_stack -> Push(); BitSet starting_set(*possibly_assigned_finals); DefiniteStatement(statement); BitSet exit_set(*possibly_assigned_finals); exit_set += definite_block_stack -> TopFinalContinueSet(); // // The set of variables that may have been possibly assigned within the body of a loop // consists of the set of variables that was possibly assigned at the end of the block // UNION the set of variables that was possibly assigned prior to a continue statement // within the body of the loop MINUS the set of variables that were possibly assigned // prior to entering the loop. // BitSet new_set(exit_set); new_set -= starting_set; for (int k = 0; k < definite_final_assignment_stack -> Top().Length(); k++) { AstExpression *name = definite_final_assignment_stack -> Top()[k]; VariableSymbol *variable = (VariableSymbol *) name -> symbol; if (definite_visible_variables -> IsElement(variable) && new_set[variable -> LocalVariableIndex()]) { ReportSemError(SemanticError::FINAL_VARIABLE_TARGET_IN_LOOP, name -> LeftToken(), name -> RightToken(), variable -> Name()); } } exit_set += definite_block_stack -> TopFinalBreakSet(); *possibly_assigned_finals = exit_set; definite_final_assignment_stack -> Pop(); return; } void Semantic::DefiniteWhileStatement(Ast *stmt) { AstWhileStatement *while_statement = (AstWhileStatement *) stmt; BreakableStatementStack().Push(definite_block_stack -> TopBlock()); ContinuableStatementStack().Push(stmt); DefiniteAssignmentSet *after_expr = DefiniteExpression(while_statement -> expression, *definitely_assigned_variables); bool while_expr = true; if (while_statement -> expression -> Type() == control.boolean_type && while_statement -> expression -> IsConstant()) { IntLiteralValue *literal = (IntLiteralValue *) while_statement -> expression -> value; if (! literal -> value) while_expr = false; } if (after_expr) { *definitely_assigned_variables = after_expr -> true_set; // // If the expression is always false, the body of the loop is not reachable and therefore will never execute. // if (while_expr) DefiniteLoopBody(while_statement -> statement); *definitely_assigned_variables = (after_expr -> false_set * definite_block_stack -> TopBreakSet()); delete after_expr; } else { BitSet starting_set(*definitely_assigned_variables); // // If the expression is always false, the body of the loop is not reachable and therefore will never execute. // if (while_expr) DefiniteLoopBody(while_statement -> statement); *definitely_assigned_variables = (starting_set * definite_block_stack -> TopBreakSet()); } ContinuableStatementStack().Pop(); BreakableStatementStack().Pop(); return; } void Semantic::DefiniteForStatement(Ast *stmt) { AstForStatement *for_statement = (AstForStatement *) stmt; // // Note that in constructing the Ast, the parser encloses each // for-statement whose for-init-statements starts with a local // variable declaration in its own block. Therefore a redeclaration // of another local variable with the same name in a different loop // at the same nesting level will not cause any conflict. // // For example, the following sequence of statements is legal: // // for (int i = 0; i < 10; i++); // for (int i = 10; i < 20; i++); // for (int i = 0; i < for_statement -> NumForInitStatements(); i++) DefiniteStatement(for_statement -> ForInitStatement(i)); BreakableStatementStack().Push(definite_block_stack -> TopBlock()); ContinuableStatementStack().Push(stmt); DefiniteAssignmentSet *after_end_expression = NULL; BitSet before_statement(universe -> Size()); bool for_expr = true; if (for_statement -> end_expression_opt) { after_end_expression = DefiniteExpression(for_statement -> end_expression_opt, *definitely_assigned_variables); if (for_statement -> end_expression_opt -> Type() == control.boolean_type && for_statement -> end_expression_opt -> IsConstant()) { IntLiteralValue *literal = (IntLiteralValue *) for_statement -> end_expression_opt -> value; if (! literal -> value) for_expr = false; } } if (after_end_expression) *definitely_assigned_variables = after_end_expression -> true_set; else before_statement = *definitely_assigned_variables; // // If the expression is always false, the body of the loop is not reachable and therefore will never execute. // if (for_expr) DefiniteLoopBody(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. // *definitely_assigned_variables *= definite_block_stack -> TopContinueSet(); for (int j = 0; j < for_statement -> NumForUpdateStatements(); j++) DefiniteExpressionStatement(for_statement -> ForUpdateStatement(j)); // // 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 is definitely assigned when // the condition expression is false. // // . the set of variables that is definitely assigned before every // break statement that may exit the for statement. // *definitely_assigned_variables = (for_statement -> end_expression_opt ? (after_end_expression ? after_end_expression -> false_set : before_statement) : *universe); // set of variables that depend on the condition // // The replacement // *definitely_assigned_variables *= definite_block_stack -> TopBreakSet(); delete after_end_expression; // nothing happens if after_end_expression is NULL ContinuableStatementStack().Pop(); BreakableStatementStack().Pop(); return; } void Semantic::DefiniteDoStatement(Ast *stmt) { AstDoStatement *do_statement = (AstDoStatement *) stmt; BreakableStatementStack().Push(definite_block_stack -> TopBlock()); ContinuableStatementStack().Push(stmt); bool do_expr = true; if (do_statement -> expression -> Type() == control.boolean_type && do_statement -> expression -> IsConstant()) { IntLiteralValue *literal = (IntLiteralValue *) do_statement -> expression -> value; if (! literal -> value) do_expr = false; } if (do_expr) DefiniteLoopBody(do_statement -> statement); else DefiniteStatement(do_statement -> statement); // The expression is always false therefore, loop will execute exactly once. BitSet after_stmt(*definitely_assigned_variables); *definitely_assigned_variables *= definite_block_stack -> TopContinueSet(); DefiniteAssignmentSet *after_expr = DefiniteExpression(do_statement -> expression, *definitely_assigned_variables); if (after_expr) { *definitely_assigned_variables = (after_expr -> false_set * definite_block_stack -> TopBreakSet()); delete after_expr; } else *definitely_assigned_variables *= definite_block_stack -> TopBreakSet(); ContinuableStatementStack().Pop(); BreakableStatementStack().Pop(); return; } void Semantic::DefiniteSwitchStatement(Ast *stmt) { AstSwitchStatement *switch_statement = (AstSwitchStatement *) stmt; AstBlock *block_body = switch_statement -> switch_block; definite_block_stack -> Push(block_body); BreakableStatementStack().Push(block_body); DefiniteAssignmentSet *after_expr = DefiniteExpression(switch_statement -> expression, *definitely_assigned_variables); if (after_expr) { *definitely_assigned_variables = after_expr -> true_set * after_expr -> false_set; delete after_expr; } BitSet starting_set(*definitely_assigned_variables), after_expr_finals(*possibly_assigned_finals), switch_finals_union(*possibly_assigned_finals); for (int i = 0; i < block_body -> NumStatements(); i++) { AstSwitchBlockStatement *switch_block_statement = (AstSwitchBlockStatement *) block_body -> Statement(i); if (switch_block_statement -> NumStatements() > 0) { *definitely_assigned_variables = starting_set; *possibly_assigned_finals = after_expr_finals; for (int k = 0; k < switch_block_statement -> NumStatements(); k++) { AstStatement *statement = (AstStatement *) switch_block_statement -> Statement(k); if (statement -> is_reachable) DefiniteStatement(statement); else break; } // // Update possibly_assigned_finals here. If a continue, break (of an enclosing statement), return or throw // statement was encountered... // switch_finals_union += definite_block_stack -> TopFinalExitSet(*possibly_assigned_finals); } } if (switch_statement -> default_case.switch_block_statement) // Is there a default case? *definitely_assigned_variables *= definite_block_stack -> TopBreakSet(); else *definitely_assigned_variables = starting_set; *possibly_assigned_finals = switch_finals_union; BreakableStatementStack().Pop(); definite_block_stack -> Pop(); return; } void Semantic::DefiniteBreakStatement(Ast *stmt) { AstBreakStatement *break_statement = (AstBreakStatement *) stmt; // // Compute the set of variables that are definitely assigned prior to executing the break. // definite_block_stack -> BreakSet(break_statement -> nesting_level) *= (*definitely_assigned_variables); definite_block_stack -> FinalBreakSet(break_statement -> nesting_level) += (*possibly_assigned_finals); // // 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). // *definitely_assigned_variables = *universe; possibly_assigned_finals -> SetEmpty(); return; } void Semantic::DefiniteContinueStatement(Ast *stmt) { AstContinueStatement *continue_statement = (AstContinueStatement *) stmt; // // Compute the set of variables that are definitely assigned prior to executing the continue. // definite_block_stack -> ContinueSet(continue_statement -> nesting_level) *= (*definitely_assigned_variables); definite_block_stack -> FinalContinueSet(continue_statement -> nesting_level) += (*possibly_assigned_finals); // // 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). // *definitely_assigned_variables = *universe; possibly_assigned_finals -> SetEmpty(); return; } void Semantic::DefiniteReturnStatement(Ast *stmt) { AstReturnStatement *return_statement = (AstReturnStatement *) stmt; if (return_statement -> expression_opt) { DefiniteAssignmentSet *after_expr = DefiniteExpression(return_statement -> expression_opt, *definitely_assigned_variables); if (after_expr) delete after_expr; } // // Compute the set of variables that are definitely assigned prior to executing // this return statement. Note that this set is only relevant to the method or // constructor block containing this statement. // definite_block_stack -> TopReturnSet() *= (*definitely_assigned_variables); // // Compute the set of variables that are possibly assigned prior to executing this return statement. // We have a few cases to consider: // // 1. The return statement is not contained in a try statement - the possibly-assigned set is only relevant // to the enclosing method (or constructor) block. The definitely assigned set is updated as if the return // statement was a break statement out of the method (or constructor) block. // // 2. If the return statement is contained in a try main block or a try // catch block that contains a finally clause - the possibly-assigned // block is relevant to that main try block or catch block. // // 3. otherwise, treat the return statement as if it immediately followed its containing try statement // if (definite_try_stack -> Size() == 0) definite_block_stack -> ReturnSet(0) *= (*definitely_assigned_variables); else { for (int i = definite_try_stack -> Size() - 1; i >= 0; i--) { AstTryStatement *try_statement = definite_try_stack -> TryStatement(i); // // Is the return statement enclosed in a try main block or catch block // that contains a finally clause. Note that a try statement is removed from // the definite_try_stack before its finally clause is processed. thus, a return // statement that is enclosed in a finally clause will appear in an enclosing // try statement, if any... // if (try_statement -> finally_clause_opt) { int k; for (k = definite_block_stack -> Size() - 1; definite_block_stack -> Block(k) != definite_try_stack -> Block(i); k--) ; assert(k >= 0); definite_block_stack -> FinalReturnSet(k) += (*possibly_assigned_finals); break; } } } // // 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). // *definitely_assigned_variables = *universe; possibly_assigned_finals -> SetEmpty(); return; } void Semantic::DefiniteThrowStatement(Ast *stmt) { AstThrowStatement *throw_statement = (AstThrowStatement *) stmt; DefiniteAssignmentSet *after_expr = DefiniteExpression(throw_statement -> expression, *definitely_assigned_variables); if (after_expr) delete after_expr; // // Compute the set of variables that are definitely assigned prior to executing // this throw statement. Note that this set is only relevant to the method or // constructor block containing this statement. // definite_block_stack -> TopThrowSet() *= (*definitely_assigned_variables); // // Compute the set of variables that are possibly assigned prior to executing this throw statement // and update the proper enclosing block appropriately. // // We have a few cases to consider: // // 1. The throw statement is not contained in a try statement - the possibly-assigned // set is only relevant to the enclosing method (or constructor) block. If the // containing function in question is a method (i.e., not a constructor) then the // definitely assigned set is updated as if the throw statement was a break statement // out of the method block. // // 2. The throw statement is enclosed in a try statement main block or catch clause. // // 2a. if the nearest try-block that encloses the throw statement is a main try-block - // the possibly-assigned block is relevant to that main block. // // 2b. if the nearest try-block that encloses the throw statement is a catch-block and // the try block contains a finally clause - the possibly-assigned block is relevant // to the catch-block // // 2c. otherwise, treat the throw statement as if it immediately followed its containing // try statement // if (definite_try_stack -> Size() == 0) { if (ThisMethod() -> Identity() != control.init_name_symbol) // Not a constructor definite_block_stack -> ThrowSet(0) *= (*definitely_assigned_variables); } else { for (int i = definite_try_stack -> Size() - 1; i >= 0; i--) { AstTryStatement *try_statement = definite_try_stack -> TryStatement(i); // // Is the return statement enclosed in a try main block or catch block // that contains a finally clause. Note that a try statement is removed from // the definite_try_stack before its finally clause is processed. thus, a return // statement that is enclosed in a finally clause will appear in an enclosing // try statement, if any... // if (try_statement -> block == definite_try_stack -> Block(i)) // Is the throw statement enclosed in main try block? { int k; for (k = definite_block_stack -> Size() - 1; definite_block_stack -> Block(k) != try_statement -> block; k--) ; assert(k >= 0); definite_block_stack -> FinalThrowSet(k) += (*possibly_assigned_finals); break; } else if (try_statement -> finally_clause_opt) { int k; for (k = definite_block_stack -> Size() - 1; definite_block_stack -> Block(k) != definite_try_stack -> Block(i); k--) ; assert(k >= 0); definite_block_stack -> FinalThrowSet(k) += (*possibly_assigned_finals); break; } } } // // 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). // *definitely_assigned_variables = *universe; possibly_assigned_finals -> SetEmpty(); return; } void Semantic::DefiniteTryStatement(Ast *stmt) { AstTryStatement *try_statement = (AstTryStatement *) stmt; definite_try_stack -> Push(try_statement); BitSet starting_set(*definitely_assigned_variables); AstBlock *try_block_body = try_statement -> block; definite_block_stack -> Push(try_block_body); definite_try_stack -> SetTopBlock(try_block_body); for (int j = 0; j < try_block_body -> block_symbol -> NumVariableSymbols(); j++) { VariableSymbol *variable = try_block_body -> block_symbol -> VariableSym(j); definitely_assigned_variables -> RemoveElement(variable -> LocalVariableIndex()); definite_visible_variables -> AddElement(variable); } BitSet before_try_finals(*possibly_assigned_finals); DefiniteBlockStatements(try_block_body); BitSet &exit_set = definite_block_stack -> TopFinalExitSet(*possibly_assigned_finals), before_catch_finals(exit_set), possibly_finals_union(exit_set); // // Once we are done with a block, its enclosed local variables are no longer visible. // for (int l = 0; l < try_block_body -> block_symbol -> NumVariableSymbols(); l++) definite_visible_variables -> RemoveElement(try_block_body -> block_symbol -> VariableSym(l)); definite_block_stack -> Pop(); // // We initilize 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(*definitely_assigned_variables); // // 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 (int i = 0; i < try_statement -> NumCatchClauses(); i++) { *definitely_assigned_variables = starting_set; // // We process the catch block here instead of invoking DefiniteBlock, // in order to make sure that the formal parameter (which is declared) // inside the block is identified as having been definitely assigned. // AstCatchClause *clause = try_statement -> CatchClause(i); AstBlock *clause_block_body = clause -> block; definite_block_stack -> Push(clause_block_body); definite_try_stack -> SetTopBlock(clause_block_body); for (int j = 0; j < clause_block_body -> block_symbol -> NumVariableSymbols(); j++) { VariableSymbol *variable = clause_block_body -> block_symbol -> VariableSym(j); definitely_assigned_variables -> RemoveElement(variable -> LocalVariableIndex()); definite_visible_variables -> AddElement(variable); } // // The parameter must be (re) added after removing all variables in the block // from the set !!! // definitely_assigned_variables -> AddElement(clause -> parameter_symbol -> LocalVariableIndex()); *possibly_assigned_finals = before_catch_finals; if (clause -> parameter_symbol -> ACC_FINAL()) possibly_assigned_finals -> AddElement(clause -> parameter_symbol -> LocalVariableIndex()); DefiniteBlockStatements(clause_block_body); // // Once we are done with a block, its enclosed local variables are no longer visible. // for (int k = 0; k < clause_block_body -> block_symbol -> NumVariableSymbols(); k++) definite_visible_variables -> RemoveElement(clause_block_body -> block_symbol -> VariableSym(k)); possibly_finals_union += definite_block_stack -> TopFinalExitSet(*possibly_assigned_finals); definite_block_stack -> Pop(); // // Process the set of variables that were definitely assigned // after this catch block // after_blocks *= *definitely_assigned_variables; } *possibly_assigned_finals = possibly_finals_union; definite_try_stack -> Pop(); // // 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) { *definitely_assigned_variables = starting_set; DefiniteBlock(try_statement -> finally_clause_opt -> block); *definitely_assigned_variables += after_blocks; } else *definitely_assigned_variables = after_blocks; return; } void Semantic::DefiniteEmptyStatement(Ast *stmt) { return; } void Semantic::DefiniteClassDeclaration(Ast *decl) { // // All the methods within the body of a local class are processed when // the class is compiled. // return; } void Semantic::DefiniteMethodBody(AstMethodDeclaration *method_declaration, Tuple<VariableSymbol *> &finals) { if (! method_declaration -> method_body -> EmptyStatementCast()) { AstConstructorBlock *constructor_block = method_declaration -> method_body -> ConstructorBlockCast(); AstBlock *block_body = (constructor_block ? constructor_block -> block : (AstBlock *) method_declaration -> method_body); universe = new BitSet(block_body -> block_symbol -> max_variable_index + finals.Length(), BitSet::UNIVERSE); definite_block_stack = new DefiniteBlockStack(method_declaration -> method_symbol -> max_block_depth, universe -> Size()); definite_try_stack = new DefiniteTryStack(method_declaration -> method_symbol -> max_block_depth); definite_final_assignment_stack = new DefiniteFinalAssignmentStack(); definite_visible_variables = new SymbolSet(universe -> Size()); definitely_assigned_variables = new BitSet(universe -> Size(), BitSet::EMPTY); possibly_assigned_finals = new BitSet(universe -> Size(), BitSet::EMPTY); for (int i = 0; i < finals.Length(); i++) // Assume that all final instance variables have been assigned a value. { int index = block_body -> block_symbol -> max_variable_index + i; finals[i] -> SetLocalVariableIndex(index); definitely_assigned_variables -> AddElement(index); possibly_assigned_finals -> AddElement(index); definite_visible_variables -> AddElement(finals[i]); } definite_block_stack -> Push(block_body); AstMethodDeclarator *method_declarator = method_declaration -> method_declarator; for (int k = 0; k < method_declarator -> NumFormalParameters(); k++) { AstFormalParameter *parameter = method_declarator -> FormalParameter(k); definitely_assigned_variables -> AddElement(parameter -> parameter_symbol -> LocalVariableIndex()); if (parameter -> parameter_symbol -> ACC_FINAL()) possibly_assigned_finals -> AddElement(parameter -> parameter_symbol -> LocalVariableIndex()); definite_visible_variables -> AddElement(parameter -> parameter_symbol); } for (int l = 0; l < block_body -> block_symbol -> NumVariableSymbols(); l++) definite_visible_variables -> AddElement(block_body -> block_symbol -> VariableSym(l)); DefiniteBlockStatements(block_body); definite_block_stack -> Pop(); delete universe; delete definitely_assigned_variables; delete definite_block_stack; delete definite_try_stack; delete definite_final_assignment_stack; delete definite_visible_variables; delete possibly_assigned_finals; } return; } void Semantic::DefiniteConstructorBody(AstConstructorDeclaration *constructor_declaration, Tuple<VariableSymbol *> &finals) { AstConstructorBlock *constructor_block = constructor_declaration -> constructor_body; AstBlock *block_body = constructor_block -> block; universe = new BitSet(block_body -> block_symbol -> max_variable_index + finals.Length(), BitSet::UNIVERSE); definite_block_stack = new DefiniteBlockStack(constructor_declaration -> constructor_symbol -> max_block_depth, universe -> Size()); definite_try_stack = new DefiniteTryStack(constructor_declaration -> constructor_symbol -> max_block_depth); definite_final_assignment_stack = new DefiniteFinalAssignmentStack(); definite_visible_variables = new SymbolSet(universe -> Size()); definitely_assigned_variables = new BitSet(universe -> Size(), BitSet::EMPTY); possibly_assigned_finals = new BitSet(universe -> Size(), BitSet::EMPTY); for (int i = 0; i < finals.Length(); i++) { int index = block_body -> block_symbol -> max_variable_index + i; finals[i] -> SetLocalVariableIndex(index); if (finals[i] -> IsDefinitelyAssigned()) { definitely_assigned_variables -> AddElement(index); possibly_assigned_finals -> AddElement(index); } else if (finals[i] -> IsPossiblyAssigned()) possibly_assigned_finals -> AddElement(index); definite_visible_variables -> AddElement(finals[i]); } // // As an explicit constructor call cannot refer to any locally declared variables // other than formal parameters, no local variable can be assigned within it (other // than a formal parameter which is considered to have been assigned anyway). Therefore, // the following code is not necessary: // // if (this_call) // DefiniteThisCall(this_call); // else if (super_call) // DefiniteSuperCall(super_call); // definite_block_stack -> Push(block_body); AstMethodDeclarator *constructor_declarator = constructor_declaration -> constructor_declarator; for (int j = 0; j < constructor_declarator -> NumFormalParameters(); j++) { AstFormalParameter *parameter = constructor_declarator -> FormalParameter(j); definitely_assigned_variables -> AddElement(parameter -> parameter_symbol -> LocalVariableIndex()); if (parameter -> parameter_symbol -> ACC_FINAL()) possibly_assigned_finals -> AddElement(parameter -> parameter_symbol -> LocalVariableIndex()); definite_visible_variables -> AddElement(parameter -> parameter_symbol); } for (int l = 0; l < block_body -> block_symbol -> NumVariableSymbols(); l++) definite_visible_variables -> AddElement(block_body -> block_symbol -> VariableSym(l)); DefiniteBlockStatements(block_body); // // Compute the set of finals that has definitely been assigned in this constructor // BitSet &exit_set = definite_block_stack -> TopExitSet(*definitely_assigned_variables); for (int k = 0; k < finals.Length(); k++) { int index = block_body -> block_symbol -> max_variable_index + k; if (exit_set[index]) finals[k] -> MarkDefinitelyAssigned(); } definite_block_stack -> Pop(); delete universe; delete definitely_assigned_variables; delete definite_block_stack; delete definite_try_stack; delete definite_final_assignment_stack; delete definite_visible_variables; delete possibly_assigned_finals; return; } void Semantic::DefiniteBlockInitializer(AstBlock *block_body, int stack_size, Tuple<VariableSymbol *> &finals) { universe = new BitSet(block_body -> block_symbol -> max_variable_index + finals.Length(), BitSet::UNIVERSE); definite_block_stack = new DefiniteBlockStack(stack_size + 1, universe -> Size()); // +1 to simulate enclosing method block definite_try_stack = new DefiniteTryStack(stack_size + 1); definite_final_assignment_stack = new DefiniteFinalAssignmentStack(); definite_visible_variables = new SymbolSet(universe -> Size()); definitely_assigned_variables = new BitSet(universe -> Size(), BitSet::EMPTY); possibly_assigned_finals = new BitSet(universe -> Size(), BitSet::EMPTY); for (int i = 0; i < finals.Length(); i++) { int index = block_body -> block_symbol -> max_variable_index + i; finals[i] -> SetLocalVariableIndex(index); if (finals[i] -> IsDefinitelyAssigned()) { definitely_assigned_variables -> AddElement(index); possibly_assigned_finals -> AddElement(index); } else if (finals[i] -> IsPossiblyAssigned()) possibly_assigned_finals -> AddElement(index); definite_visible_variables -> AddElement(finals[i]); } definite_block_stack -> Push(NULL); // No method available definite_block_stack -> Push(block_body); for (int j = 0; j < block_body -> block_symbol -> NumVariableSymbols(); j++) definite_visible_variables -> AddElement(block_body -> block_symbol -> VariableSym(j)); DefiniteBlockStatements(block_body); // // For each final that has definitely been assigned a value in this block, // mark it appropriately. // BitSet &exit_set = definite_block_stack -> TopExitSet(*definitely_assigned_variables); for (int k = 0; k < finals.Length(); k++) { int index = block_body -> block_symbol -> max_variable_index + k; if (exit_set[index]) finals[k] -> MarkDefinitelyAssigned(); } // // For each final that may have possibly been assigned a value in this block, // mark it appropriately. // exit_set = definite_block_stack -> TopFinalExitSet(*possibly_assigned_finals); for (int l = 0; l < finals.Length(); l++) { int index = block_body -> block_symbol -> max_variable_index + l; if (exit_set[index]) finals[l] -> MarkPossiblyAssigned(); } definite_block_stack -> Pop(); definite_block_stack -> Pop(); // remove NULL that was pushed to indicate that no method is available delete universe; delete definitely_assigned_variables; delete definite_block_stack; delete definite_try_stack; delete definite_final_assignment_stack; delete definite_visible_variables; delete possibly_assigned_finals; return; } void Semantic::DefiniteVariableInitializer(AstVariableDeclarator *variable_declarator, Tuple<VariableSymbol *> &finals) { universe = new BitSet(finals.Length(), BitSet::UNIVERSE); definite_block_stack = NULL; definite_try_stack = NULL; definite_final_assignment_stack = new DefiniteFinalAssignmentStack(); definite_visible_variables = new SymbolSet(universe -> Size()); definitely_assigned_variables = new BitSet(universe -> Size(), BitSet::EMPTY); possibly_assigned_finals = new BitSet(universe -> Size(), BitSet::EMPTY); for (int i = 0; i < finals.Length(); i++) { finals[i] -> SetLocalVariableIndex(i); if (finals[i] -> IsDefinitelyAssigned()) { definitely_assigned_variables -> AddElement(i); possibly_assigned_finals -> AddElement(i); } else if (finals[i] -> IsPossiblyAssigned()) possibly_assigned_finals -> AddElement(i); definite_visible_variables -> AddElement(finals[i]); } DefiniteVariableInitializer(variable_declarator); VariableSymbol *symbol = variable_declarator -> symbol; if (symbol -> ACC_FINAL()) symbol -> MarkDefinitelyAssigned(); // // Also, update any other finals that may have been initialized as // a side-effect in an assignment embedded within the initializer // expression. // BitSet &exit_set = *definitely_assigned_variables; for (int k = 0; k < finals.Length(); k++) { if (exit_set[k]) finals[k] -> MarkDefinitelyAssigned(); } delete universe; delete definitely_assigned_variables; delete definite_final_assignment_stack; delete definite_visible_variables; delete possibly_assigned_finals; return; }