A number of approaches for helping programmers detect incorrect program behaviors are based on combining language-level constructs (such as procedure-level assertions/contracts, program-point assertions, or gradual types) with a number of associated tools (such as code analyzers and run-time verification frameworks) that automatically check the validity of such constructs. However, these constructs and tools are often not used to their full extent in practice due to excessive run-time overhead, limited expressiveness, and/or limitations in the effectiveness of the tools. Verification frameworks that combine static and dynamic verification techniques and are based on abstraction offer the potential to bridge this gap. In this paper we explore the effectiveness of abstract interpretation in detecting parts of program specifications that can be statically simplified to true or false, as well as in reducing the cost of the run-time checks required for the remaining parts of these specifications. Starting with a semantics for programs with assertion checking, and for assertion simplification based on static analysis information obtained via abstract interpretation, we propase and study a number of practica! assertion checking "modes," each of which represents a trade-off between code annotation depth, execution time slowdown, and program safety. We then explore these modes in two typical, library-oriented scenarios. We also propase program transformation-based methods for taking advantage of the run-time checking semantics to improve the precision of the analysis. Finally, we study experimentally the performance of these techniques. Our experiments illustrate the benefits and costs of each of the assertion checking modes proposed, as well as the benefits obtained from analysis and the proposed transformations in these scenarios. (M.V. Hermenegildo). such as static code analyzers/verifiers and run-time verification frameworks. Approaches that fall into this category are the assertion-based frameworks used in (Constraint) Logic Programming [2][3][4][5][6][7][8][9][10][11], soft/gradual typing approaches in functional programming [12][13][14][15][16][17][18][19][20], and contract-based extensions in object-oriented programming [21][22][23]. These tools are aimed at detecting violations of the expected behavior or certifying the absence of any such violations, and often involve a certain degree of run-time testing, specially for complex properties.A practical limitation of many of these tools is that they can incur significant run-time performance overhead, even in the simple case of performing just type checks between typed and untyped parts of programs [16,20]. In [11] overhead reductions are obtained by limiting the points at which the tests are performed and the instrumentation, as well as by inlining, but some types of tests still incurred significant costs. Other approaches opt for limiting the expressiveness of the assertion language in order to reduce the overhead (see [24] for some recent case studies). Recently,...