Mercurial > hg > truffle
view src/share/vm/interpreter/bytecode.hpp @ 452:00b023ae2d78
6722113: CMS: Incorrect overflow handling during precleaning of Reference lists
Summary: When we encounter marking stack overflow during precleaning of Reference lists, we were using the overflow list mechanism, which can cause problems on account of mutating the mark word of the header because of conflicts with mutator accesses and updates of that field. Instead we should use the usual mechanism for overflow handling in concurrent phases, namely dirtying of the card on which the overflowed object lies. Since precleaning effectively does a form of discovered list processing, albeit with discovery enabled, we needed to adjust some code to be correct in the face of interleaved processing and discovery.
Reviewed-by: apetrusenko, jcoomes
author | ysr |
---|---|
date | Thu, 20 Nov 2008 12:27:41 -0800 |
parents | a61af66fc99e |
children | be93aad57795 |
line wrap: on
line source
/* * Copyright 1997-2002 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. * */ // Base class for different kinds of abstractions working // relative to an objects 'this' pointer. class ThisRelativeObj VALUE_OBJ_CLASS_SPEC { private: int sign_extend (int x, int size) const { const int s = (BytesPerInt - size)*BitsPerByte; return (x << s) >> s; } public: // Address computation address addr_at (int offset) const { return (address)this + offset; } address aligned_addr_at (int offset) const { return (address)round_to((intptr_t)addr_at(offset), jintSize); } int aligned_offset (int offset) const { return aligned_addr_at(offset) - addr_at(0); } // Java unsigned accessors (using Java spec byte ordering) int java_byte_at (int offset) const { return *(jubyte*)addr_at(offset); } int java_hwrd_at (int offset) const { return java_byte_at(offset) << (1 * BitsPerByte) | java_byte_at(offset + 1); } int java_word_at (int offset) const { return java_hwrd_at(offset) << (2 * BitsPerByte) | java_hwrd_at(offset + 2); } // Java signed accessors (using Java spec byte ordering) int java_signed_byte_at(int offset) const { return sign_extend(java_byte_at(offset), 1); } int java_signed_hwrd_at(int offset) const { return sign_extend(java_hwrd_at(offset), 2); } int java_signed_word_at(int offset) const { return java_word_at(offset) ; } // Fast accessors (using the machine's natural byte ordering) int fast_byte_at (int offset) const { return *(jubyte *)addr_at(offset); } int fast_hwrd_at (int offset) const { return *(jushort*)addr_at(offset); } int fast_word_at (int offset) const { return *(juint *)addr_at(offset); } // Fast signed accessors (using the machine's natural byte ordering) int fast_signed_byte_at(int offset) const { return *(jbyte *)addr_at(offset); } int fast_signed_hwrd_at(int offset) const { return *(jshort*)addr_at(offset); } int fast_signed_word_at(int offset) const { return *(jint *)addr_at(offset); } // Fast manipulators (using the machine's natural byte ordering) void set_fast_byte_at (int offset, int x) const { *(jbyte *)addr_at(offset) = (jbyte )x; } void set_fast_hwrd_at (int offset, int x) const { *(jshort*)addr_at(offset) = (jshort)x; } void set_fast_word_at (int offset, int x) const { *(jint *)addr_at(offset) = (jint )x; } }; // The base class for different kinds of bytecode abstractions. // Provides the primitive operations to manipulate code relative // to an objects 'this' pointer. // // Note: Even though it seems that the fast_index & set_fast_index // functions are machine specific, they're not. They only use // the natural way to store a 16bit index on a given machine, // independent of the particular byte ordering. Since all other // places in the system that refer to these indices use the // same method (the natural byte ordering on the platform) // this will always work and be machine-independent). class Bytecode: public ThisRelativeObj { protected: u_char byte_at(int offset) const { return *addr_at(offset); } bool check_must_rewrite() const; public: // Attributes address bcp() const { return addr_at(0); } address next_bcp() const { return addr_at(0) + Bytecodes::length_at(bcp()); } Bytecodes::Code code() const { return Bytecodes::code_at(addr_at(0)); } Bytecodes::Code java_code() const { return Bytecodes::java_code(code()); } bool must_rewrite() const { return Bytecodes::can_rewrite(code()) && check_must_rewrite(); } bool is_active_breakpoint() const { return Bytecodes::is_active_breakpoint_at(bcp()); } int one_byte_index() const { return byte_at(1); } int two_byte_index() const { return (byte_at(1) << 8) + byte_at(2); } int offset() const { return (two_byte_index() << 16) >> 16; } address destination() const { return bcp() + offset(); } int fast_index() const { return Bytes::get_native_u2(addr_at(1)); } // Attribute modification void set_code(Bytecodes::Code code); void set_fast_index(int i); // Creation inline friend Bytecode* Bytecode_at(address bcp); }; inline Bytecode* Bytecode_at(address bcp) { return (Bytecode*)bcp; } // Abstractions for lookupswitch bytecode class LookupswitchPair: ThisRelativeObj { private: int _match; int _offset; public: int match() const { return java_signed_word_at(0 * jintSize); } int offset() const { return java_signed_word_at(1 * jintSize); } }; class Bytecode_lookupswitch: public Bytecode { public: void verify() const PRODUCT_RETURN; // Attributes int default_offset() const { return java_signed_word_at(aligned_offset(1 + 0*jintSize)); } int number_of_pairs() const { return java_signed_word_at(aligned_offset(1 + 1*jintSize)); } LookupswitchPair* pair_at(int i) const { assert(0 <= i && i < number_of_pairs(), "pair index out of bounds"); return (LookupswitchPair*)aligned_addr_at(1 + (1 + i)*2*jintSize); } // Creation inline friend Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp); }; inline Bytecode_lookupswitch* Bytecode_lookupswitch_at(address bcp) { Bytecode_lookupswitch* b = (Bytecode_lookupswitch*)bcp; debug_only(b->verify()); return b; } class Bytecode_tableswitch: public Bytecode { public: void verify() const PRODUCT_RETURN; // Attributes int default_offset() const { return java_signed_word_at(aligned_offset(1 + 0*jintSize)); } int low_key() const { return java_signed_word_at(aligned_offset(1 + 1*jintSize)); } int high_key() const { return java_signed_word_at(aligned_offset(1 + 2*jintSize)); } int dest_offset_at(int i) const; int length() { return high_key()-low_key()+1; } // Creation inline friend Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp); }; inline Bytecode_tableswitch* Bytecode_tableswitch_at(address bcp) { Bytecode_tableswitch* b = (Bytecode_tableswitch*)bcp; debug_only(b->verify()); return b; } // Abstraction for invoke_{virtual, static, interface, special} class Bytecode_invoke: public ResourceObj { protected: methodHandle _method; // method containing the bytecode int _bci; // position of the bytecode Bytecode_invoke(methodHandle method, int bci) : _method(method), _bci(bci) {} public: void verify() const; // Attributes methodHandle method() const { return _method; } int bci() const { return _bci; } address bcp() const { return _method->bcp_from(bci()); } int index() const; // the constant pool index for the invoke symbolOop name() const; // returns the name of the invoked method symbolOop signature() const; // returns the signature of the invoked method BasicType result_type(Thread *thread) const; // returns the result type of the invoke Bytecodes::Code code() const { return Bytecodes::code_at(bcp(), _method()); } Bytecodes::Code adjusted_invoke_code() const { return Bytecodes::java_code(code()); } methodHandle static_target(TRAPS); // "specified" method (from constant pool) // Testers bool is_invokeinterface() const { return adjusted_invoke_code() == Bytecodes::_invokeinterface; } bool is_invokevirtual() const { return adjusted_invoke_code() == Bytecodes::_invokevirtual; } bool is_invokestatic() const { return adjusted_invoke_code() == Bytecodes::_invokestatic; } bool is_invokespecial() const { return adjusted_invoke_code() == Bytecodes::_invokespecial; } bool is_valid() const { return is_invokeinterface() || is_invokevirtual() || is_invokestatic() || is_invokespecial(); } // Creation inline friend Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci); // Like Bytecode_invoke_at. Instead it returns NULL if the bci is not at an invoke. inline friend Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci); }; inline Bytecode_invoke* Bytecode_invoke_at(methodHandle method, int bci) { Bytecode_invoke* b = new Bytecode_invoke(method, bci); debug_only(b->verify()); return b; } inline Bytecode_invoke* Bytecode_invoke_at_check(methodHandle method, int bci) { Bytecode_invoke* b = new Bytecode_invoke(method, bci); return b->is_valid() ? b : NULL; } // Abstraction for all field accesses (put/get field/static_ class Bytecode_field: public Bytecode { public: void verify() const; int index() const; bool is_static() const; // Creation inline friend Bytecode_field* Bytecode_field_at(const methodOop method, address bcp); }; inline Bytecode_field* Bytecode_field_at(const methodOop method, address bcp) { Bytecode_field* b = (Bytecode_field*)bcp; debug_only(b->verify()); return b; } // Abstraction for {get,put}static class Bytecode_static: public Bytecode { public: void verify() const; // Returns the result type of the send by inspecting the field ref BasicType result_type(methodOop method) const; // Creation inline friend Bytecode_static* Bytecode_static_at(const methodOop method, address bcp); }; inline Bytecode_static* Bytecode_static_at(const methodOop method, address bcp) { Bytecode_static* b = (Bytecode_static*)bcp; debug_only(b->verify()); return b; } // Abstraction for checkcast class Bytecode_checkcast: public Bytecode { public: void verify() const { assert(Bytecodes::java_code(code()) == Bytecodes::_checkcast, "check checkcast"); } // Returns index long index() const { return java_hwrd_at(1); }; // Creation inline friend Bytecode_checkcast* Bytecode_checkcast_at(address bcp); }; inline Bytecode_checkcast* Bytecode_checkcast_at(address bcp) { Bytecode_checkcast* b = (Bytecode_checkcast*)bcp; debug_only(b->verify()); return b; } // Abstraction for instanceof class Bytecode_instanceof: public Bytecode { public: void verify() const { assert(code() == Bytecodes::_instanceof, "check instanceof"); } // Returns index long index() const { return java_hwrd_at(1); }; // Creation inline friend Bytecode_instanceof* Bytecode_instanceof_at(address bcp); }; inline Bytecode_instanceof* Bytecode_instanceof_at(address bcp) { Bytecode_instanceof* b = (Bytecode_instanceof*)bcp; debug_only(b->verify()); return b; } class Bytecode_new: public Bytecode { public: void verify() const { assert(java_code() == Bytecodes::_new, "check new"); } // Returns index long index() const { return java_hwrd_at(1); }; // Creation inline friend Bytecode_new* Bytecode_new_at(address bcp); }; inline Bytecode_new* Bytecode_new_at(address bcp) { Bytecode_new* b = (Bytecode_new*)bcp; debug_only(b->verify()); return b; } class Bytecode_multianewarray: public Bytecode { public: void verify() const { assert(java_code() == Bytecodes::_multianewarray, "check new"); } // Returns index long index() const { return java_hwrd_at(1); }; // Creation inline friend Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp); }; inline Bytecode_multianewarray* Bytecode_multianewarray_at(address bcp) { Bytecode_multianewarray* b = (Bytecode_multianewarray*)bcp; debug_only(b->verify()); return b; } class Bytecode_anewarray: public Bytecode { public: void verify() const { assert(java_code() == Bytecodes::_anewarray, "check anewarray"); } // Returns index long index() const { return java_hwrd_at(1); }; // Creation inline friend Bytecode_anewarray* Bytecode_anewarray_at(address bcp); }; inline Bytecode_anewarray* Bytecode_anewarray_at(address bcp) { Bytecode_anewarray* b = (Bytecode_anewarray*)bcp; debug_only(b->verify()); return b; } // Abstraction for ldc, ldc_w and ldc2_w class Bytecode_loadconstant: public Bytecode { public: void verify() const { Bytecodes::Code stdc = Bytecodes::java_code(code()); assert(stdc == Bytecodes::_ldc || stdc == Bytecodes::_ldc_w || stdc == Bytecodes::_ldc2_w, "load constant"); } int index() const; inline friend Bytecode_loadconstant* Bytecode_loadconstant_at(const methodOop method, address bcp); }; inline Bytecode_loadconstant* Bytecode_loadconstant_at(const methodOop method, address bcp) { Bytecode_loadconstant* b = (Bytecode_loadconstant*)bcp; debug_only(b->verify()); return b; }