You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by ml...@apache.org on 2007/10/12 16:42:23 UTC
svn commit: r584170 [5/7] - in
/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363: base/ java5/
java6/
Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/ver_utils.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/ver_utils.h?rev=584170&r1=584169&r2=584170&view=diff
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/ver_utils.h (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/ver_utils.h Fri Oct 12 07:42:03 2007
@@ -1,425 +1,425 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @author Mikhail Loenko, Vladimir Molotkov
- */
-
-#ifndef __VER_UTILS_H_
-#define __VER_UTILS_H_
-
-#include <assert.h>
-#include "clog.h"
-#include <iostream>
-using namespace std;
-
-namespace CPVerifier {
-
- // convenience types
- typedef unsigned short Address;
-
- //TODO:
-#define tc_free(ptr) free(ptr)
-#define tc_realloc(ptr, sz) realloc(ptr, sz)
-#define tc_malloc(sz) malloc(sz)
-#define tc_calloc(sz1, sz2) calloc(sz1, sz2)
-#define tc_memcpy(ptr1, ptr2, sz) vf_memcpy(ptr1, ptr2, sz)
-#define tc_memset(ptr, i1, i2) vf_memset(ptr, i1, i2)
-
- //TODO: delegate to compiler
- inline void *vf_memcpy(void *dest, const void *src, size_t count) {
- char *d = (char *)dest;
- const char *s = (const char *)src;
- for (; count; count--) {
- *d++ = *s++;
- }
- return dest;
- }
-
- //TODO: delegate to compiler
- inline void *vf_memset(void *dest, int val, size_t count) {
- char *d = (char *)dest;
- char v = (char) val;
- for (; count; count--) {
- *d++ = v;
- }
- return dest;
- }
-
- /**
- * Structure of hash entry.
- */
- struct vf_HashEntry_t {
- const char *key; // hash entry key
- int key_size; // hash entry key size
- union { // hash entry data
- unsigned data_index; // when it's an index
- void* data_ptr; // when it's data
- };
- vf_HashEntry_t *next; // next hash entry
- };
-
- class Stack {
- protected:
- int max_depth;
- Address* stack;
- int depth;
-
- public:
- Stack() :
- max_depth(0), stack(0), depth(0)
- {}
-
-
- ~Stack() {
- tc_free(stack);
- }
-
- void push(Address value) {
- if( depth == max_depth ) {
- max_depth += max_depth/2 + 32;
- stack = (Address*) tc_realloc(stack, sizeof(Address) * max_depth);
- }
-
- stack[depth++] = value;
- }
-
- Address pop() {
- assert(depth > 0);
- return stack[--depth];
- }
-
- bool is_empty() {
- return !depth;
- }
-
- void init() {
- depth = 0;
- }
- };
-
- class FastStack : Stack {
- public:
- FastStack() : fdepth(0)
- {}
-
- void push(Address value) {
- if( fdepth < BUFSIZE ) {
- buffer[fdepth++] = value;
- } else {
- Stack::push(value);
- }
- }
-
- Address pop() {
- assert(fdepth > 0);
- return Stack::is_empty() ? buffer[--fdepth] : Stack::pop();
- }
-
- bool is_empty() {
- return !fdepth;
- }
-
- void init() {
- fdepth = 0;
- Stack::init();
- }
-
- private:
- static const int BUFSIZE = 100;
- int fdepth;
- Address buffer[BUFSIZE];
- };
-
- class MarkableStack : public FastStack {
- // contains the following entries:
- // <address, mark> no mask means zero mark
-
- // <non-zero address, 0> is pushed as {address}
- // <0, 0> is pushed as {0, 0}
- // <any address, non-zero mark> is pushed as {address, mark, 0}
-
- public:
- void xPop(Address *addr, short *mark) {
- *addr = pop();
- *mark = (*addr) ? 0 : pop();
-
- if( *mark ) {
- *addr = pop();
- }
- }
-
- void xPush(Address value) {
- if( value ) {
- push(value);
- } else {
- push(0);
- push(0);
- }
- }
-
- void xPush(Address addr, short m) {
- push(addr);
- push(m);
- push(0);
- }
- };
-
- struct MemoryPageHead {
- MemoryPageHead *next;
- size_t size;
-
- MemoryPageHead *get_next(size_t min_size, size_t max_size) {
- assert(this);
- MemoryPageHead *ret = this;
- while ( ret->next && ret->next->size < min_size ) {
- ret = ret->next;
- }
-
- return ret->next ? ret->next : (ret->next = create_next(max_size));
- }
-
- MemoryPageHead *create_next(size_t max_size) {
- MemoryPageHead *ret =(MemoryPageHead*)tc_malloc(max_size + sizeof(MemoryPageHead));
- ret->size = max_size;
- ret->next = 0;
- return ret;
- }
- };
-
- class Memory {
- MemoryPageHead *static_page;
- MemoryPageHead *current_page;
-
- static const int STATICSZ = 2000;
- uint8 static_mem[STATICSZ + sizeof (MemoryPageHead) ];
-
- size_t page_size;
- size_t used;
- public:
- Memory()
- {
- //in 90% of cases no memory allocation will be required
- static_page = (MemoryPageHead *)&static_mem;
- static_page->next = 0;
- static_page->size = STATICSZ;
-
- init();
- }
-
- ~Memory() {
- current_page = static_page->next;
- while (current_page) {
- MemoryPageHead *next = current_page->next;
- tc_free(current_page);
- current_page = next;
- }
- }
-
- void init() {
- used = 0;
- current_page = static_page;
- page_size = current_page->size;
- }
-
- void *malloc(size_t sz) {
- size_t need_on_page = used + sz;
-
- if( need_on_page > page_size ) {
- //create next page
-
- //define new page size - some heuristic formula. subject to change
- size_t desired_size = need_on_page + need_on_page/2 + 128;
-
- //allocating next page
- current_page = current_page->get_next(sz, desired_size);
- if( !static_page ) {
- static_page = current_page;
- }
- used = 0;
- page_size = current_page->size;
- }
-
- void *ret = (uint8*)current_page + sizeof(MemoryPageHead) + used;
- used += sz;
- return ret;
- }
-
- void *calloc(size_t sz) {
- void *ret = malloc(sz);
- tc_memset(ret, 0, sz);
- return ret;
- }
-
- void dealloc_last(void* ptr, size_t sz) {
- assert( ((uint8*)ptr) + sz == (uint8*)current_page + sizeof(MemoryPageHead) + used );
- used -= sz;
- }
- };
-
- /**
- * Verifier hash table structure.
- */
- struct vf_Hash {
- public:
- /**
- * Hash table constructor.
- * @note Function allocates memory for hash pool and hash table.
- */
- vf_Hash()
- {
- memoryPool.init();
- m_hash = (vf_HashEntry_t**)memoryPool.calloc(HASH_SIZE * sizeof(vf_HashEntry_t*));
- assert((0xFFFFFFFF & HASH_MASK) + 1 == HASH_SIZE );
- } // vf_Hash::vf_Hash
-
-
- /**
- * Function looks up hash entry which is identical to given hash key.
- * @param key - given hash key
- * @return Hash entry which is identical to given hash key.
- * @see vf_HashEntry_t
- */
- vf_HashEntry_t * Lookup( const char *key ) {
- assert( key );
- int length = (int)strlen(key);
-
- unsigned hash_index = HashFunc( key, length );
-
- vf_HashEntry_t *hash_entry = m_hash[hash_index];
- while( hash_entry != NULL ) {
- if( CheckKey( hash_entry, key, length ) ) {
- return hash_entry;
- }
- hash_entry = hash_entry->next;
- }
- return NULL;
- } // vf_Hash::Lookup( key )
-
-
- /**
- * Function creates hash entry which is identical to given hash key.
- * @param key - given hash key
- * @param length - length for the key
- * @return Hash entry which are identical to given hash key.
- * @see vf_HashEntry_t
- * @note Created hash key and hash entry is allocated into hash memory pool.
- */
- vf_HashEntry_t * NewHashEntry( const char *key, int length ) {
- // lookup type in hash
- assert( key );
- unsigned hash_index = HashFunc( key, length );
-
- vf_HashEntry_t *hash_entry = m_hash[hash_index];
- while( hash_entry != NULL ) {
- if( CheckKey( hash_entry, key, length ) ) {
- return hash_entry;
- }
- hash_entry = hash_entry->next;
- }
-
- if( !hash_entry ) {
- // create key string
- char *hash_key = (char*)memoryPool.malloc( (length & (~3)) + 4);
- tc_memcpy( hash_key, key, length );
- hash_key[length] = 0;
-
- hash_entry = (vf_HashEntry_t*)memoryPool.malloc(sizeof(vf_HashEntry_t));
- hash_entry->key = hash_key;
- hash_entry->key_size = length;
- hash_entry->next = m_hash[hash_index];
-
- hash_entry->data_ptr = 0;
- hash_entry->data_index = 0;
-
- m_hash[hash_index] = hash_entry;
- }
-
- return hash_entry;
- } // vf_Hash::NewHashEntry( key, length )
-
- /**
- * Function creates hash entry which is identical to given hash key.
- * @param key - given hash key
- * @return Hash entry which are identical to given hash key.
- * @see vf_HashEntry_t
- * @note Created hash key and hash entry is allocated into hash memory pool.
- */
- vf_HashEntry_t * NewHashEntry( const char *key) {
- return NewHashEntry(key, (int)strlen(key));
- } // vf_Hash::NewHashEntry( key )
-
- private:
- static const unsigned HASH_SIZE = 128; ///< hash table size
- static const unsigned HASH_MASK = 127; ///< hash table mask to avoid division
-
- Memory memoryPool;
- vf_HashEntry_t **m_hash; ///< hash table
-
- /**
- * Function checks key identity.
- * @param hash_entry - checked hash entry
- * @param key - checked key
- * @return If keys are identical function returns <code>true</code>,
- * else returns <code>false</code>.
- * @see vf_HashEntry_t
- */
- int CheckKey( vf_HashEntry_t *hash_entry, const char *key, int length) {
- if( hash_entry->key_size != length ) return false;
-
- const char* h_key = hash_entry->key;
- int idx = 0;
-
- for( ; idx < length - 3; idx += 4 ) {
- if( *((uint32*) (key+idx) ) != *((uint32*) (h_key+idx) ) ) return false;
- }
-
- for( ; idx < length; idx++) {
- if( *(key+idx) != *(h_key+idx) ) return false;
- }
-
- return true;
- }
-
- /**
- * Hash function.
- * @param key - key for hash function
- * @return Hash index relevant to key.
- */
- unsigned HashFunc( const char *key, int length ) {
- unsigned result = 0;
-
- int idx = 0;
-
- for( ; idx < length - 3; idx += 4 ) {
- result += *((uint32*) (key+idx) );
- }
-
- for( ; idx < length; idx++) {
- result += *(key+idx);
- }
-
- uint8 *bres = (uint8*) &result;
-
- return (bres[0] + bres[1] + bres[2] + bres[3]) & HASH_MASK;
- } // vf_Hash::HashFunc( key )
-
- }; // struct vf_Hash
-
-} // namespace CPVerifier
-
-
-#endif
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+#ifndef __VER_UTILS_H_
+#define __VER_UTILS_H_
+
+#include <assert.h>
+#include "clog.h"
+#include <iostream>
+using namespace std;
+
+namespace CPVerifier {
+
+ // convenience types
+ typedef unsigned short Address;
+
+ //TODO:
+#define tc_free(ptr) free(ptr)
+#define tc_realloc(ptr, sz) realloc(ptr, sz)
+#define tc_malloc(sz) malloc(sz)
+#define tc_calloc(sz1, sz2) calloc(sz1, sz2)
+#define tc_memcpy(ptr1, ptr2, sz) vf_memcpy(ptr1, ptr2, sz)
+#define tc_memset(ptr, i1, i2) vf_memset(ptr, i1, i2)
+
+ //TODO: delegate to compiler
+ inline void *vf_memcpy(void *dest, const void *src, size_t count) {
+ char *d = (char *)dest;
+ const char *s = (const char *)src;
+ for (; count; count--) {
+ *d++ = *s++;
+ }
+ return dest;
+ }
+
+ //TODO: delegate to compiler
+ inline void *vf_memset(void *dest, int val, size_t count) {
+ char *d = (char *)dest;
+ char v = (char) val;
+ for (; count; count--) {
+ *d++ = v;
+ }
+ return dest;
+ }
+
+ /**
+ * Structure of hash entry.
+ */
+ struct vf_HashEntry_t {
+ const char *key; // hash entry key
+ int key_size; // hash entry key size
+ union { // hash entry data
+ unsigned data_index; // when it's an index
+ void* data_ptr; // when it's data
+ };
+ vf_HashEntry_t *next; // next hash entry
+ };
+
+ class Stack {
+ protected:
+ int max_depth;
+ Address* stack;
+ int depth;
+
+ public:
+ Stack() :
+ max_depth(0), stack(0), depth(0)
+ {}
+
+
+ ~Stack() {
+ tc_free(stack);
+ }
+
+ void push(Address value) {
+ if( depth == max_depth ) {
+ max_depth += max_depth/2 + 32;
+ stack = (Address*) tc_realloc(stack, sizeof(Address) * max_depth);
+ }
+
+ stack[depth++] = value;
+ }
+
+ Address pop() {
+ assert(depth > 0);
+ return stack[--depth];
+ }
+
+ bool is_empty() {
+ return !depth;
+ }
+
+ void init() {
+ depth = 0;
+ }
+ };
+
+ class FastStack : Stack {
+ public:
+ FastStack() : fdepth(0)
+ {}
+
+ void push(Address value) {
+ if( fdepth < BUFSIZE ) {
+ buffer[fdepth++] = value;
+ } else {
+ Stack::push(value);
+ }
+ }
+
+ Address pop() {
+ assert(fdepth > 0);
+ return Stack::is_empty() ? buffer[--fdepth] : Stack::pop();
+ }
+
+ bool is_empty() {
+ return !fdepth;
+ }
+
+ void init() {
+ fdepth = 0;
+ Stack::init();
+ }
+
+ private:
+ static const int BUFSIZE = 100;
+ int fdepth;
+ Address buffer[BUFSIZE];
+ };
+
+ class MarkableStack : public FastStack {
+ // contains the following entries:
+ // <address, mark> no mask means zero mark
+
+ // <non-zero address, 0> is pushed as {address}
+ // <0, 0> is pushed as {0, 0}
+ // <any address, non-zero mark> is pushed as {address, mark, 0}
+
+ public:
+ void xPop(Address *addr, short *mark) {
+ *addr = pop();
+ *mark = (*addr) ? 0 : pop();
+
+ if( *mark ) {
+ *addr = pop();
+ }
+ }
+
+ void xPush(Address value) {
+ if( value ) {
+ push(value);
+ } else {
+ push(0);
+ push(0);
+ }
+ }
+
+ void xPush(Address addr, short m) {
+ push(addr);
+ push(m);
+ push(0);
+ }
+ };
+
+ struct MemoryPageHead {
+ MemoryPageHead *next;
+ size_t size;
+
+ MemoryPageHead *get_next(size_t min_size, size_t max_size) {
+ assert(this);
+ MemoryPageHead *ret = this;
+ while ( ret->next && ret->next->size < min_size ) {
+ ret = ret->next;
+ }
+
+ return ret->next ? ret->next : (ret->next = create_next(max_size));
+ }
+
+ MemoryPageHead *create_next(size_t max_size) {
+ MemoryPageHead *ret =(MemoryPageHead*)tc_malloc(max_size + sizeof(MemoryPageHead));
+ ret->size = max_size;
+ ret->next = 0;
+ return ret;
+ }
+ };
+
+ class Memory {
+ MemoryPageHead *static_page;
+ MemoryPageHead *current_page;
+
+ static const int STATICSZ = 2000;
+ uint8 static_mem[STATICSZ + sizeof (MemoryPageHead) ];
+
+ size_t page_size;
+ size_t used;
+ public:
+ Memory()
+ {
+ //in 90% of cases no memory allocation will be required
+ static_page = (MemoryPageHead *)&static_mem;
+ static_page->next = 0;
+ static_page->size = STATICSZ;
+
+ init();
+ }
+
+ ~Memory() {
+ current_page = static_page->next;
+ while (current_page) {
+ MemoryPageHead *next = current_page->next;
+ tc_free(current_page);
+ current_page = next;
+ }
+ }
+
+ void init() {
+ used = 0;
+ current_page = static_page;
+ page_size = current_page->size;
+ }
+
+ void *malloc(size_t sz) {
+ size_t need_on_page = used + sz;
+
+ if( need_on_page > page_size ) {
+ //create next page
+
+ //define new page size - some heuristic formula. subject to change
+ size_t desired_size = need_on_page + need_on_page/2 + 128;
+
+ //allocating next page
+ current_page = current_page->get_next(sz, desired_size);
+ if( !static_page ) {
+ static_page = current_page;
+ }
+ used = 0;
+ page_size = current_page->size;
+ }
+
+ void *ret = (uint8*)current_page + sizeof(MemoryPageHead) + used;
+ used += sz;
+ return ret;
+ }
+
+ void *calloc(size_t sz) {
+ void *ret = malloc(sz);
+ tc_memset(ret, 0, sz);
+ return ret;
+ }
+
+ void dealloc_last(void* ptr, size_t sz) {
+ assert( ((uint8*)ptr) + sz == (uint8*)current_page + sizeof(MemoryPageHead) + used );
+ used -= sz;
+ }
+ };
+
+ /**
+ * Verifier hash table structure.
+ */
+ struct vf_Hash {
+ public:
+ /**
+ * Hash table constructor.
+ * @note Function allocates memory for hash pool and hash table.
+ */
+ vf_Hash()
+ {
+ memoryPool.init();
+ m_hash = (vf_HashEntry_t**)memoryPool.calloc(HASH_SIZE * sizeof(vf_HashEntry_t*));
+ assert((0xFFFFFFFF & HASH_MASK) + 1 == HASH_SIZE );
+ } // vf_Hash::vf_Hash
+
+
+ /**
+ * Function looks up hash entry which is identical to given hash key.
+ * @param key - given hash key
+ * @return Hash entry which is identical to given hash key.
+ * @see vf_HashEntry_t
+ */
+ vf_HashEntry_t * Lookup( const char *key ) {
+ assert( key );
+ int length = (int)strlen(key);
+
+ unsigned hash_index = HashFunc( key, length );
+
+ vf_HashEntry_t *hash_entry = m_hash[hash_index];
+ while( hash_entry != NULL ) {
+ if( CheckKey( hash_entry, key, length ) ) {
+ return hash_entry;
+ }
+ hash_entry = hash_entry->next;
+ }
+ return NULL;
+ } // vf_Hash::Lookup( key )
+
+
+ /**
+ * Function creates hash entry which is identical to given hash key.
+ * @param key - given hash key
+ * @param length - length for the key
+ * @return Hash entry which are identical to given hash key.
+ * @see vf_HashEntry_t
+ * @note Created hash key and hash entry is allocated into hash memory pool.
+ */
+ vf_HashEntry_t * NewHashEntry( const char *key, int length ) {
+ // lookup type in hash
+ assert( key );
+ unsigned hash_index = HashFunc( key, length );
+
+ vf_HashEntry_t *hash_entry = m_hash[hash_index];
+ while( hash_entry != NULL ) {
+ if( CheckKey( hash_entry, key, length ) ) {
+ return hash_entry;
+ }
+ hash_entry = hash_entry->next;
+ }
+
+ if( !hash_entry ) {
+ // create key string
+ char *hash_key = (char*)memoryPool.malloc( (length & (~3)) + 4);
+ tc_memcpy( hash_key, key, length );
+ hash_key[length] = 0;
+
+ hash_entry = (vf_HashEntry_t*)memoryPool.malloc(sizeof(vf_HashEntry_t));
+ hash_entry->key = hash_key;
+ hash_entry->key_size = length;
+ hash_entry->next = m_hash[hash_index];
+
+ hash_entry->data_ptr = 0;
+ hash_entry->data_index = 0;
+
+ m_hash[hash_index] = hash_entry;
+ }
+
+ return hash_entry;
+ } // vf_Hash::NewHashEntry( key, length )
+
+ /**
+ * Function creates hash entry which is identical to given hash key.
+ * @param key - given hash key
+ * @return Hash entry which are identical to given hash key.
+ * @see vf_HashEntry_t
+ * @note Created hash key and hash entry is allocated into hash memory pool.
+ */
+ vf_HashEntry_t * NewHashEntry( const char *key) {
+ return NewHashEntry(key, (int)strlen(key));
+ } // vf_Hash::NewHashEntry( key )
+
+ private:
+ static const unsigned HASH_SIZE = 128; ///< hash table size
+ static const unsigned HASH_MASK = 127; ///< hash table mask to avoid division
+
+ Memory memoryPool;
+ vf_HashEntry_t **m_hash; ///< hash table
+
+ /**
+ * Function checks key identity.
+ * @param hash_entry - checked hash entry
+ * @param key - checked key
+ * @return If keys are identical function returns <code>true</code>,
+ * else returns <code>false</code>.
+ * @see vf_HashEntry_t
+ */
+ int CheckKey( vf_HashEntry_t *hash_entry, const char *key, int length) {
+ if( hash_entry->key_size != length ) return false;
+
+ const char* h_key = hash_entry->key;
+ int idx = 0;
+
+ for( ; idx < length - 3; idx += 4 ) {
+ if( *((uint32*) (key+idx) ) != *((uint32*) (h_key+idx) ) ) return false;
+ }
+
+ for( ; idx < length; idx++) {
+ if( *(key+idx) != *(h_key+idx) ) return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Hash function.
+ * @param key - key for hash function
+ * @return Hash index relevant to key.
+ */
+ unsigned HashFunc( const char *key, int length ) {
+ unsigned result = 0;
+
+ int idx = 0;
+
+ for( ; idx < length - 3; idx += 4 ) {
+ result += *((uint32*) (key+idx) );
+ }
+
+ for( ; idx < length; idx++) {
+ result += *(key+idx);
+ }
+
+ uint8 *bres = (uint8*) &result;
+
+ return (bres[0] + bres[1] + bres[2] + bres[3]) & HASH_MASK;
+ } // vf_Hash::HashFunc( key )
+
+ }; // struct vf_Hash
+
+} // namespace CPVerifier
+
+
+#endif
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/ver_utils.h
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/ver_utils.h
('svn:executable' removed)
Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/vf_resolve.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/vf_resolve.cpp?rev=584170&r1=584169&r2=584170&view=diff
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/vf_resolve.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/vf_resolve.cpp Fri Oct 12 07:42:03 2007
@@ -1,94 +1,94 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @author Mikhail Loenko, Vladimir Molotkov
- */
-
-#include "verifier.h"
-#include "context_base.h"
-#include "time.h"
-
-namespace CPVerifier {
-
- /**
- * Function checkes constraint for given class.
- * Function loads classes if it's needed.
- */
- vf_Result
- vf_force_check_constraint( class_handler klass,
- vf_TypeConstraint *constraint ) // class constraint
- {
- // get target class
- class_handler target = vf_resolve_class( klass, constraint->target, true );
- if( !target ) {
- return VF_ErrorLoadClass;
- }
-
- //no need to load the source
- if( class_is_interface_(target) ){
- return VF_OK;
- }
-
-
- // get stack reference class
- class_handler source = vf_resolve_class( klass, constraint->source, true );
- if( !source ) {
- return VF_ErrorLoadClass;
- }
-
- // check restriction
- if( !vf_is_extending( source, target ) ) {
- return VF_ErrorIncompatibleArgument;
- }
- return VF_OK;
- } // vf_force_check_constraint
-
-
- /**
- * Returns true if 'from' is (not necessarily directly) extending 'to'
- */
- int vf_is_extending(class_handler from, class_handler to) {
- while (from) {
- if( from == to ) return true;
- from = class_get_super_class(from);
- }
- return false;
- }
-
- /**
- * Function receives class by given class name, loads it if it's needed.
- */
- class_handler
- vf_resolve_class( class_handler k_class, // current class
- const char *name, // resolved class name
- bool need_load) // load flag
- {
- class_handler result;
-
- // get class loader
- classloader_handler class_loader = class_get_class_loader( k_class );
-
- result = need_load ? cl_load_class( class_loader, name ) : cl_get_class( class_loader, name );
-
- //we assume that this pre-defined constant is not a valid class-handler
- assert(CLASS_NOT_LOADED != result);
-
- return result;
- } // vf_resolve_class
-
-
-} // namespace CPVerifier
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+#include "verifier.h"
+#include "context_base.h"
+#include "time.h"
+
+namespace CPVerifier {
+
+ /**
+ * Function checkes constraint for given class.
+ * Function loads classes if it's needed.
+ */
+ vf_Result
+ vf_force_check_constraint( class_handler klass,
+ vf_TypeConstraint *constraint ) // class constraint
+ {
+ // get target class
+ class_handler target = vf_resolve_class( klass, constraint->target, true );
+ if( !target ) {
+ return VF_ErrorLoadClass;
+ }
+
+ //no need to load the source
+ if( class_is_interface_(target) ){
+ return VF_OK;
+ }
+
+
+ // get stack reference class
+ class_handler source = vf_resolve_class( klass, constraint->source, true );
+ if( !source ) {
+ return VF_ErrorLoadClass;
+ }
+
+ // check restriction
+ if( !vf_is_extending( source, target ) ) {
+ return VF_ErrorIncompatibleArgument;
+ }
+ return VF_OK;
+ } // vf_force_check_constraint
+
+
+ /**
+ * Returns true if 'from' is (not necessarily directly) extending 'to'
+ */
+ int vf_is_extending(class_handler from, class_handler to) {
+ while (from) {
+ if( from == to ) return true;
+ from = class_get_super_class(from);
+ }
+ return false;
+ }
+
+ /**
+ * Function receives class by given class name, loads it if it's needed.
+ */
+ class_handler
+ vf_resolve_class( class_handler k_class, // current class
+ const char *name, // resolved class name
+ bool need_load) // load flag
+ {
+ class_handler result;
+
+ // get class loader
+ classloader_handler class_loader = class_get_class_loader( k_class );
+
+ result = need_load ? cl_load_class( class_loader, name ) : cl_get_class( class_loader, name );
+
+ //we assume that this pre-defined constant is not a valid class-handler
+ assert(CLASS_NOT_LOADED != result);
+
+ return result;
+ } // vf_resolve_class
+
+
+} // namespace CPVerifier
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/vf_resolve.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/base/vf_resolve.cpp
('svn:executable' removed)
Modified: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/java5/context_5.cpp
URL: http://svn.apache.org/viewvc/harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/java5/context_5.cpp?rev=584170&r1=584169&r2=584170&view=diff
==============================================================================
--- harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/java5/context_5.cpp (original)
+++ harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/java5/context_5.cpp Fri Oct 12 07:42:03 2007
@@ -1,680 +1,680 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-/**
- * @author Mikhail Loenko, Vladimir Molotkov
- */
-
-#include "context_5.h"
-namespace CPVerifier_5 {
-
- /*
- This method makes the first pass through the instruction set.
- On that pass we check that all instruction have valid opcode, that no
- jumps, no exception handlers lead to the middle of instruction nor
- out of the method. it checks that control does not flow out of the method.
-
- It also finds all instructions that have multiple predecessors
- (like goto tagrtes), this information will be used on the second Pass
-
- Method starts with the instruction <code>instr</code> for each it was invoked and go down
- filling the mask array with the flags. On this pass it distignushes
- 4 types of instructions:
- 0 - non-passed instruction or dead code
- 1 - passed instruction
- 2 - middle of passed instruction
- 3 - passed multiway instruction (having many predecessors)
-
- If the method comes to a return, ret, athrow, or an already passed instruction, it terminates
- If it comes to a switch, an if, or a jsr then it push all branches onto the stack
- If it comes to a goto then it continues from the jump target
- */
-
- vf_Result vf_Context_5::parse(Address instr) {
- // instruction is out of the method or in the middle of another instruction
- if( instr > m_code_length || props.isOperand(instr) ) {
- return error(VF_ErrorCodeEnd, "jump to the middle of instruction or out of the method");
- }
-
- while( instr < m_code_length ) {
- if( props.isParsePassed(instr) ) {
- // more than one branch leads to this instruction
- if( !dead_code_parsing ) {
- props.setMultiway(instr);
- }
- return VF_OK;
- }
-
- OpCode opcode = (OpCode)m_bytecode[instr];
- processed_instruction = instr;
-
- // does code correspond to any valid instruction?
- if( !instr_is_valid_bytecode(opcode) ) {
- return error(VF_ErrorInstruction, "invalid opcode");
- }
-
- // keep all nessesary information about instruction
- ParseInfo &pi = instr_get_parse_info(opcode);
-
- // get MINIMAL length of the instruction with operands
- unsigned instr_len = instr_get_minlen(pi);
-
- // code does not correspond to any valid instruction or method length is less than required
- if( instr + instr_len > m_code_length ) {
- return error(VF_ErrorInstruction, "method length is less than required");
- }
-
- if( instr_is_compound(opcode, pi) ) {
- // get ACTUAL length for variable length insgtructions
- instr_len = instr_get_len_compound(instr, opcode);
-
- // method length is less than required
- if( instr + instr_len > m_code_length ) {
- return error(VF_ErrorInstruction, "compound instruction: method length is less than required");
- }
- }
-
- // mark this instruction as processed
- assert( !props.isParsePassed(instr) );
- props.setParsePassed(instr);
-
- // check that no other instruction jumps to the middle of the current instruction
- for( Address i = instr + 1; i < instr + instr_len; i++ ) {
- if( !props.setOperand(i) ) {
- return error(VF_ErrorUnknown, "jump to the middle of instruction");
- }
- }
-
-
-
- if( instr_is_regular(pi) ) {
- //regular instruction - go to the next instruction
- instr += instr_len;
- } else if( instr_is_jump(pi) ) {
- // goto, goto_w, if*
-
- Address target = instr_get_jump_target(pi, m_bytecode, instr);
-
- // jump out of method or to the middle of an instruction
- if( target >= m_code_length || props.isOperand(target) ) {
- return error(VF_ErrorBranch, "jump out of method or to the middle of an instruction");
- }
-
- if( instr_direct(pi, opcode, m_bytecode, instr) ) {
- //TODO: though the spec does not require to check the dead code for correctness
- //RI seems to check it and some Harmony negative tests have broken dead code
-
- dead_code_stack.push(instr+instr_len);
-
- instr = target; // it is not an if* - go to jump target
- } else {
- // process conditional jump target or jsr
- stack.push(target);
-
- // go to the next instruction
- instr += instr_len;
- }
- } else if( instr_direct(pi, opcode, m_bytecode, instr) ) {
- dead_code_stack.push(instr+instr_len);
-
- // it is not a jump ==> it is return or throw or ret
- return VF_OK;
- } else {
- assert( instr_is_switch(pi) );
-
- Address next_target_adr = (instr & (~3) ) + 4;
-
- //default target
- Address target = instr + read_int32(m_bytecode + next_target_adr);
- stack.push(target);
-
- // in tableswitch instruction target offsets are stored with shift = 4,
- // in lookupswitch with shift = 8
- int shift = (opcode == OP_TABLESWITCH) ? 4 : 8;
-
- for (next_target_adr += 12;
- next_target_adr < instr + instr_len;
- next_target_adr += shift)
- {
- target = instr + read_int32(m_bytecode + next_target_adr);
- // jump out of method or to the middle of an instruction
- if( target >= m_code_length || props.isOperand(target) ) {
- return error(VF_ErrorBranch, "jump out of method or to the middle of an instruction");
- }
- // process conditional jump target
- stack.push(target);
- }
-
- return VF_OK;
- }
- }
-
- //it might be a dead code -- code followed by JSR which never returns
- //if it's a dead code - it's OK, if it's not - we will catch it on the second pass
- return VF_OK;
- }
-
-
- vf_Result vf_Context_5::StartLinearDataflow(Address instr) {
-
- vf_Result tcr;
- int workmap_is_a_copy_of_stackmap;
-
- if( props.isDataflowPassed(instr) ) {
- //passed since it was added to the stack
- assert(instr);
- return VF_OK;
- }
-
- if (instr) {
- workmap_is_a_copy_of_stackmap = true;
- fill_workmap(instr);
- } else {
- //for the first instruction it does not matter if it is multiway or not
- workmap_is_a_copy_of_stackmap = false;
- // may return error in case of method's wrong signature
- if((tcr = create_method_initial_workmap()) != VF_OK ) {
- return tcr;
- }
- }
-
- //list of handlers unknown
- next_start_pc = 0;
-
- return DataflowLoop(instr, workmap_is_a_copy_of_stackmap);
- }
-
- vf_Result vf_Context_5::SubroutineDone(Address subr) {
- SubroutineData *subrdata = ((PropsHead*)props.getInstrProps(subr)->next)->getSubrData(m_max_stack + m_stack_start);
- subrdata->subrDataflowed = 1;
-
- if( !subrdata->retCount ) {
- //no ret from subroutine -- dead code follows
- return VF_OK;
- }
-
- Address jsr = subrdata->caller;
-
- OpCode opcode = (OpCode)m_bytecode[jsr];
- ParseInfo &pi = instr_get_parse_info(opcode);
-
- processed_instruction = jsr;
- if (jsr || props.isMultiway(jsr)) {
- //note that in SubroutineDone unlike StartLinearDataflow we get workmap from stackmap
- //in case of the first instruction of the method
- fill_workmap(jsr);
- } else {
- vf_Result tcr = create_method_initial_workmap();
- assert(tcr == VF_OK); // method's signature was already verified in StartLinearDataflow
- }
-
- //list of handlers unknown
- next_start_pc = 0;
-
- restore_workmap_after_jsr(subr);
-
- //make a shift to the instr following jsr
- Address instr = jsr + (opcode == OP_JSR_W ? 5 : 3);
- assert(opcode == OP_JSR || opcode == OP_JSR_W);
-
-
- return DataflowLoop(instr, 0);
- }
-
-
-
- // iterate thru the instructions starting with 'instr'
- vf_Result vf_Context_5::DataflowLoop (Address instr, int workmap_is_a_copy_of_stackmap) {
-
- vf_Result tcr;
-
- while( instr < m_code_length ) {
- if( !workmap_is_a_copy_of_stackmap && props.isMultiway(instr) ) {
- //if instruction has a stackmap and workmap was not just obtained from that stackmap
- // add constraint: workmap is assignable to stackmap(instr)
- if( (tcr=new_generic_vector_constraint(instr)) != VF_OK ) {
- return tcr;
- }
-
- if( props.isDataflowPassed(instr) ) {
- return VF_OK;
- }
-
- fill_workmap(instr);
- }
- workmap_is_a_copy_of_stackmap = false;
-
- OpCode opcode = (OpCode)m_bytecode[instr];
- processed_instruction = instr;
- // keep all nessesary information about instruction
- ParseInfo &pi = instr_get_parse_info(opcode);
-
- //check IN types, create OUT types, check exception
- if( (tcr=dataflow_instruction(instr)) != VF_OK ) {
- return tcr;
- }
-
- props.setDataflowPassed(instr);
-
- unsigned instr_len = instr_get_minlen(pi);
- if( instr_is_compound(opcode, pi) ) {
- // get ACTUAL length for variable length insgtructions
- instr_len = instr_get_len_compound(instr, opcode);
- }
-
- if( instr_is_jump(pi) ) {
- Address target = instr_get_jump_target(pi, m_bytecode, instr);
-
- if( props.isMultiway(target) || instr_is_jsr(opcode) ) {
- //TODO: need to test commented out optimization
- //&& (!instr_direct(pi, opcode, m_bytecode, instr) || props.isDataflowPassed(target))
- if( (tcr=new_generic_vector_constraint(target)) != VF_OK ) {
- return tcr;
- }
- }
-
- if( instr_direct(pi, opcode, m_bytecode, instr) ) {
- //goto, goto_w
- if( !props.isDataflowPassed(target) ) {
- if( target < instr ) next_start_pc = 0;
-
- //if we like to flush StackMapTable attribute from this method
- if( stackmapattr_calculation && !props.isMultiway(target) ) {
- //store workmap to flush it further
- assert(!props.getInstrProps(target));
- storeWorkmapCopy(target);
- }
-
- instr = target;
- continue;
- } else {
- return VF_OK;
- }
- }
-
-
- //TODO: makes sense to move the block into dataflow_instruction??
- if( instr_is_jsr(opcode) ) {
- PropsHead *target_pro = (PropsHead*)props.getInstrProps(target);
-
- if( !props.isDataflowPassed(target) ) {
- for( unsigned i = 0; i < m_stack_start; i++ ) {
- StackmapElement &el = target_pro->stackmap.elements[i];
- el.clearJsrModified();
- }
-
- //create vector for storing ret types coming out of subroutine
- PropsHead *retpro = newRetData();
- retpro->instr = 0xFFFF;
- assert(!target_pro->next || target_pro->next->instr != 0xFFFF );
- retpro->next = target_pro->next;
- target_pro->next = retpro;
-
- SubroutineData *subrdata = retpro->getSubrData(m_stack_start+m_max_stack);
-
- if( !props.getInstrProps(instr) && instr) {
- //if jsr instruction does not have workmap copy or stackmap, associated with it - create it
- assert(workmap->depth);
- workmap->depth--; // undo PUSH(SM_RETADDR)
- storeWorkmapCopy(instr);
- }
-
- //need to return to that JSR instr later, when finish subroutine processing
- subrdata->caller = instr;
-
- //need to postpone some finalizing stuff
- stack.xPush(target, MARK_SUBROUTINE_DONE);
-
- //process subroutine
- stack.xPush(target);
-
- return VF_OK;
- } else {
- SubroutineData *subrdata = ((PropsHead*)target_pro->next)->getSubrData(m_stack_start+m_max_stack);
-
- if( !subrdata->subrDataflowed ) {
- //recursive call?
- return error(VF_ErrorDataFlow, "recursive subroutine");
- }
-
- restore_workmap_after_jsr(target);
-
- if( !subrdata->retCount ) {
- //no ret from subroutine -- dead code follows
- return VF_OK;
- }
-
- instr += instr_len;
- continue;
- }
- }
-
- if( !props.isMultiway(target) ) {
- //if* with no stackmap at branch
- storeWorkmapCopy(target);
- assert( !props.isDataflowPassed(target) );
- }
-
- if( !props.isDataflowPassed(target) ) {
- stack.xPush(target);
- }
-
- instr += instr_len;
- } else if( instr_direct(pi, opcode, m_bytecode, instr) ) {
- // it is not a jump ==> it is ret, return or throw
- return VF_OK;
- } else if( instr_is_switch(pi) ) {
-
- Address next_target_adr = (instr & (~3) ) + 4;
-
- //default target
- Address target = instr + read_int32(m_bytecode + next_target_adr);
- processSwitchTarget(target);
-
- // in tableswitch instruction target offsets are stored with shift = 4,
- // in lookupswitch with shift = 8
- int shift = (opcode == OP_TABLESWITCH) ? 4 : 8;
-
- // process conditional jump target
- for (next_target_adr += 12;
- next_target_adr < instr + instr_len;
- next_target_adr += shift)
- {
- target = instr + read_int32(m_bytecode + next_target_adr);
- processSwitchTarget(target);
- }
-
- return VF_OK;
- } else {
- assert( instr_is_regular(pi) );
- instr += instr_len;
- }
-
- }
-
- // control went out of method bounds
- return error(VF_ErrorCodeEnd, "control went out of method bounds");
- }
-
- vf_Result vf_Context_5::verify_method(method_handler method) {
- vf_Result tcr;
-
- //nothing to verify
- if( !method_get_code_length( method ) ) {
- return VF_OK;
- }
-
- //load memory storage, read variable like max_stack, etc
- init(method);
-
- //////////////////////////// FIRST PASS /////////////////////////
- pass = 1;
- stack.push(0);
-
- unsigned short idx;
- unsigned short start_pc;
- unsigned short end_pc;
- unsigned short handler_pc;
- unsigned short handler_cp_index;
-
- for( idx = 0; idx < m_handlecount; idx++ ) {
- method_get_exc_handler_info( m_method, idx, &start_pc, &end_pc,
- &handler_pc, &handler_cp_index );
-
- if( start_pc >= end_pc || end_pc > m_code_length ) {
- return error(VF_ErrorHandler, "start_pc >= end_pc OR end_pc > code_length");
- }
- stack.push(handler_pc);
- }
-
- //we have different slightly rules for processing dead and live code
- //e.g. it's not a problem if dead code runs out of the method
- //but we still have to verify it for corrupted instructions to follow RI
- dead_code_parsing = 0;
- do {
- while( !stack.is_empty() ) {
- vf_Result tcr = parse(stack.pop());
- if( tcr != VF_OK ) {
- return tcr;
- }
- }
-
- dead_code_parsing = 1;
-
- while( !dead_code_stack.is_empty() ) {
- vf_Result tcr = parse(dead_code_stack.pop());
- if( tcr != VF_OK ) {
- return tcr;
- }
- }
- } while (!stack.is_empty());
-
-
-
- for( idx = 0; idx < m_handlecount; idx++ ) {
-
- method_get_exc_handler_info( m_method, idx, &start_pc, &end_pc,
- &handler_pc, &handler_cp_index );
-
- if( end_pc < m_code_length && props.isOperand(end_pc) || props.isOperand(start_pc) ) {
- return error(VF_ErrorCodeEnd, "start_pc or end_pc are at the middle of an instruction");
- }
-
- SmConstant handler_type;
- if( handler_cp_index ) {
- if( !tpool.cpool_get_class(handler_cp_index, &handler_type) ||
- !tpool.mustbe_assignable(handler_type, tpool.sm_get_const_throwable()) )
- {
- return error(VF_ErrorHandler, "incorrect constantpool entry");
- }
- } else {
- handler_type = tpool.sm_get_const_throwable();
- }
-
- props.setMultiway(handler_pc);
- createHandlerStackmap(handler_pc, handler_type);
- }
-
- //////////////////////////// SECOND PASS /////////////////////////
- pass = 2;
-
- stack.xPush(0);
- while( !stack.is_empty() ) {
- Address next;
- short mark;
-
- stack.xPop(&next, &mark);
-
- if( !mark ) {
- tcr = StartLinearDataflow(next);
- } else {
- assert(mark == MARK_SUBROUTINE_DONE);
- tcr = SubroutineDone(next);
- }
-
- if( tcr != VF_OK ) {
- return tcr;
- }
- }
-
- return VF_OK;
- }
-
-
-
-
- vf_Result vf_Context_5::new_ret_vector_constraint(Address jsr_target) {
- PropsHead *inpro = (PropsHead*)props.getInstrProps(jsr_target);
- PropsHead *outpro = (PropsHead*)inpro->next;
- assert(outpro->instr == 0xFFFF);
-
- SubroutineData *subrdata = outpro->getSubrData(m_stack_start + m_max_stack);
- subrdata->retCount++;
-
- //if it is a first ret from the given subroutine (majority of the cases)
- if( subrdata->retCount == 1 ) {
- //remove newly appeared ret addresses: it might happen
- //if non-top subroutine made a ret
- StackmapHead* original = inpro->getStackmap();
- unsigned i;
-
- for( i = 0; i < m_stack_start + workmap->depth; i++ ) {
- if( i < m_stack_start && !workmap->elements[i].isJsrModified() ) {
- //nothing new here
- continue;
- }
-
- SmConstant val = workmap->elements[i].getAnyPossibleValue();
- if( val.isRetAddr() ) {
- //check if it's a newly appeared ret addfress
-
- // '-1' is twice below to exclude top of the stack.
- // top of the stack contains ret address for the current subroutine
- // it also cleaned up if it's still there
-
- if( i < m_stack_start + original->depth - 1 &&
- original->elements[i].getAnyIncomingValue() == val )
- {
- //most likely: this ret address was there before
- continue;
- }
-
- //iterate thru original types and look for this ret address
- int found_in_original = 0;
- for( unsigned j = 0; j < m_stack_start + original->depth - 1; j++ ) {
- if( original->elements[j].getAnyIncomingValue() == val ) {
- found_in_original = 1;
- break;
- }
- }
- if( !found_in_original ) {
- //original types did not have this ret address
- workmap->elements[i] = _WorkmapElement(SM_BOGUS);
- }
- }
- }
-
- //TODO make sure incoming was created as JSR transformation
- tc_memcpy(outpro->getWorkmap(), workmap, sizeof(WorkmapHead) + sizeof(WorkmapElement) * (m_stack_start + workmap->depth));
- return VF_OK;
- }
-
- return error(VF_ErrorStackDepth, "Multiple returns to single jsr");
- }
-
-
- void vf_Context_5::restore_workmap_after_jsr(Address jsr_target) {
- PropsHead *inpro = (PropsHead*)props.getInstrProps(jsr_target);
- PropsHead *outpro = (PropsHead*)inpro->next;
- SubroutineData *subrdata = outpro->getSubrData(m_stack_start + m_max_stack);
-
- if( subrdata->retCount ) {
- assert( subrdata->retCount == 1 );
- WorkmapHead* outcoming = outpro->getWorkmap();
- workmap->depth = outcoming->depth;
-
- unsigned i;
- for( i = 0; i < m_stack_start; i++ ) {
- if( outcoming->elements[i].isJsrModified() ) {
- workmap->elements[i] = outcoming->elements[i];
- }
- }
- for( ; i < m_stack_start + workmap->depth; i++ ) {
- workmap->elements[i] = outcoming->elements[i];
- }
- }
- }
-
- vf_Result vf_Context_5::new_scalar_constraint(WorkmapElement *from, StackmapElement *to) {
- assert(from->getAnyPossibleValue() != SM_NONE);
-
- if( from->isJsrModified() ) {
- //JSR overhead
- to->setJsrModified();
- }
-
- if( !from->isVariable() ) {
- SmConstant inc_val = from->getConst();
- return add_incoming_value( inc_val, to );
- } else {
- GenericCnstr* gen = from->getVariable()->firstGenericCnstr();
- while( gen ) {
- if( gen->variable == to ) return VF_OK;
- gen = gen->next();
- }
-
- IncomingType *inc = from->getVariable()->firstIncoming();
- from->getVariable()->newGenericConstraint(&mem, to);
-
- while( inc ) {
- vf_Result vcr = add_incoming_value( inc->value, to );
- if( vcr != VF_OK ) {
- return vcr;
- }
- inc = inc->next();
- }
- return VF_OK;
- }
- }
-
- vf_Result vf_Context_5::add_incoming_value(SmConstant new_value, StackmapElement *destination) {
- //check if the node already has such incoming value
- IncomingType *inc = destination->firstIncoming();
- while( inc ) {
- if( new_value == inc->value || inc->value == SM_BOGUS ) {
- return VF_OK;
- }
- inc = inc->next();
- }
-
- if( new_value.isNonMergeable() && destination->firstIncoming() ) {
- //uninit value merged to any different value is bogus
- //ret address merged to any different value is bogus
- //assert - incoming value exists is different - we've already checked that new_value is missing in the list of incoming values
- new_value = SM_BOGUS;
- }
-
- //add incoming value if it does not have
- Constraint* next = destination->firstOthers();
- //TODO: optimize memory footprint for new_value == SM_BOGUS
- destination->newIncomingType(&mem, new_value);
-
- //check if it contradicts to expected types and further propagate
- while( next ) {
- switch (next->type) {
- case CT_EXPECTED_TYPE:
- if( !tpool.mustbe_assignable(new_value, next->value) ) return error(VF_ErrorUnknown, "unexpected type on stack or local variable");
- break;
- case CT_GENERIC: {
- vf_Result vcr = add_incoming_value(new_value, next->variable);
- if( vcr != VF_OK ) return vcr;
- break;
- }
- case CT_ARRAY2REF: {
- vf_Result vcr = add_incoming_value( tpool.get_ref_from_array(new_value), next->variable);
- if( vcr != VF_OK ) return vcr;
- break;
- }
- default:
- assert(0);
- return error(VF_ErrorInternal, "unreachable statement in add_incoming_value");
- }
- next = next->next();
- }
- return VF_OK;
- }
-
-} // namespace CPVerifier
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @author Mikhail Loenko, Vladimir Molotkov
+ */
+
+#include "context_5.h"
+namespace CPVerifier_5 {
+
+ /*
+ This method makes the first pass through the instruction set.
+ On that pass we check that all instruction have valid opcode, that no
+ jumps, no exception handlers lead to the middle of instruction nor
+ out of the method. it checks that control does not flow out of the method.
+
+ It also finds all instructions that have multiple predecessors
+ (like goto tagrtes), this information will be used on the second Pass
+
+ Method starts with the instruction <code>instr</code> for each it was invoked and go down
+ filling the mask array with the flags. On this pass it distignushes
+ 4 types of instructions:
+ 0 - non-passed instruction or dead code
+ 1 - passed instruction
+ 2 - middle of passed instruction
+ 3 - passed multiway instruction (having many predecessors)
+
+ If the method comes to a return, ret, athrow, or an already passed instruction, it terminates
+ If it comes to a switch, an if, or a jsr then it push all branches onto the stack
+ If it comes to a goto then it continues from the jump target
+ */
+
+ vf_Result vf_Context_5::parse(Address instr) {
+ // instruction is out of the method or in the middle of another instruction
+ if( instr > m_code_length || props.isOperand(instr) ) {
+ return error(VF_ErrorCodeEnd, "jump to the middle of instruction or out of the method");
+ }
+
+ while( instr < m_code_length ) {
+ if( props.isParsePassed(instr) ) {
+ // more than one branch leads to this instruction
+ if( !dead_code_parsing ) {
+ props.setMultiway(instr);
+ }
+ return VF_OK;
+ }
+
+ OpCode opcode = (OpCode)m_bytecode[instr];
+ processed_instruction = instr;
+
+ // does code correspond to any valid instruction?
+ if( !instr_is_valid_bytecode(opcode) ) {
+ return error(VF_ErrorInstruction, "invalid opcode");
+ }
+
+ // keep all nessesary information about instruction
+ ParseInfo &pi = instr_get_parse_info(opcode);
+
+ // get MINIMAL length of the instruction with operands
+ unsigned instr_len = instr_get_minlen(pi);
+
+ // code does not correspond to any valid instruction or method length is less than required
+ if( instr + instr_len > m_code_length ) {
+ return error(VF_ErrorInstruction, "method length is less than required");
+ }
+
+ if( instr_is_compound(opcode, pi) ) {
+ // get ACTUAL length for variable length insgtructions
+ instr_len = instr_get_len_compound(instr, opcode);
+
+ // method length is less than required
+ if( instr + instr_len > m_code_length ) {
+ return error(VF_ErrorInstruction, "compound instruction: method length is less than required");
+ }
+ }
+
+ // mark this instruction as processed
+ assert( !props.isParsePassed(instr) );
+ props.setParsePassed(instr);
+
+ // check that no other instruction jumps to the middle of the current instruction
+ for( Address i = instr + 1; i < instr + instr_len; i++ ) {
+ if( !props.setOperand(i) ) {
+ return error(VF_ErrorUnknown, "jump to the middle of instruction");
+ }
+ }
+
+
+
+ if( instr_is_regular(pi) ) {
+ //regular instruction - go to the next instruction
+ instr += instr_len;
+ } else if( instr_is_jump(pi) ) {
+ // goto, goto_w, if*
+
+ Address target = instr_get_jump_target(pi, m_bytecode, instr);
+
+ // jump out of method or to the middle of an instruction
+ if( target >= m_code_length || props.isOperand(target) ) {
+ return error(VF_ErrorBranch, "jump out of method or to the middle of an instruction");
+ }
+
+ if( instr_direct(pi, opcode, m_bytecode, instr) ) {
+ //TODO: though the spec does not require to check the dead code for correctness
+ //RI seems to check it and some Harmony negative tests have broken dead code
+
+ dead_code_stack.push(instr+instr_len);
+
+ instr = target; // it is not an if* - go to jump target
+ } else {
+ // process conditional jump target or jsr
+ stack.push(target);
+
+ // go to the next instruction
+ instr += instr_len;
+ }
+ } else if( instr_direct(pi, opcode, m_bytecode, instr) ) {
+ dead_code_stack.push(instr+instr_len);
+
+ // it is not a jump ==> it is return or throw or ret
+ return VF_OK;
+ } else {
+ assert( instr_is_switch(pi) );
+
+ Address next_target_adr = (instr & (~3) ) + 4;
+
+ //default target
+ Address target = instr + read_int32(m_bytecode + next_target_adr);
+ stack.push(target);
+
+ // in tableswitch instruction target offsets are stored with shift = 4,
+ // in lookupswitch with shift = 8
+ int shift = (opcode == OP_TABLESWITCH) ? 4 : 8;
+
+ for (next_target_adr += 12;
+ next_target_adr < instr + instr_len;
+ next_target_adr += shift)
+ {
+ target = instr + read_int32(m_bytecode + next_target_adr);
+ // jump out of method or to the middle of an instruction
+ if( target >= m_code_length || props.isOperand(target) ) {
+ return error(VF_ErrorBranch, "jump out of method or to the middle of an instruction");
+ }
+ // process conditional jump target
+ stack.push(target);
+ }
+
+ return VF_OK;
+ }
+ }
+
+ //it might be a dead code -- code followed by JSR which never returns
+ //if it's a dead code - it's OK, if it's not - we will catch it on the second pass
+ return VF_OK;
+ }
+
+
+ vf_Result vf_Context_5::StartLinearDataflow(Address instr) {
+
+ vf_Result tcr;
+ int workmap_is_a_copy_of_stackmap;
+
+ if( props.isDataflowPassed(instr) ) {
+ //passed since it was added to the stack
+ assert(instr);
+ return VF_OK;
+ }
+
+ if (instr) {
+ workmap_is_a_copy_of_stackmap = true;
+ fill_workmap(instr);
+ } else {
+ //for the first instruction it does not matter if it is multiway or not
+ workmap_is_a_copy_of_stackmap = false;
+ // may return error in case of method's wrong signature
+ if((tcr = create_method_initial_workmap()) != VF_OK ) {
+ return tcr;
+ }
+ }
+
+ //list of handlers unknown
+ next_start_pc = 0;
+
+ return DataflowLoop(instr, workmap_is_a_copy_of_stackmap);
+ }
+
+ vf_Result vf_Context_5::SubroutineDone(Address subr) {
+ SubroutineData *subrdata = ((PropsHead*)props.getInstrProps(subr)->next)->getSubrData(m_max_stack + m_stack_start);
+ subrdata->subrDataflowed = 1;
+
+ if( !subrdata->retCount ) {
+ //no ret from subroutine -- dead code follows
+ return VF_OK;
+ }
+
+ Address jsr = subrdata->caller;
+
+ OpCode opcode = (OpCode)m_bytecode[jsr];
+ ParseInfo &pi = instr_get_parse_info(opcode);
+
+ processed_instruction = jsr;
+ if (jsr || props.isMultiway(jsr)) {
+ //note that in SubroutineDone unlike StartLinearDataflow we get workmap from stackmap
+ //in case of the first instruction of the method
+ fill_workmap(jsr);
+ } else {
+ vf_Result tcr = create_method_initial_workmap();
+ assert(tcr == VF_OK); // method's signature was already verified in StartLinearDataflow
+ }
+
+ //list of handlers unknown
+ next_start_pc = 0;
+
+ restore_workmap_after_jsr(subr);
+
+ //make a shift to the instr following jsr
+ Address instr = jsr + (opcode == OP_JSR_W ? 5 : 3);
+ assert(opcode == OP_JSR || opcode == OP_JSR_W);
+
+
+ return DataflowLoop(instr, 0);
+ }
+
+
+
+ // iterate thru the instructions starting with 'instr'
+ vf_Result vf_Context_5::DataflowLoop (Address instr, int workmap_is_a_copy_of_stackmap) {
+
+ vf_Result tcr;
+
+ while( instr < m_code_length ) {
+ if( !workmap_is_a_copy_of_stackmap && props.isMultiway(instr) ) {
+ //if instruction has a stackmap and workmap was not just obtained from that stackmap
+ // add constraint: workmap is assignable to stackmap(instr)
+ if( (tcr=new_generic_vector_constraint(instr)) != VF_OK ) {
+ return tcr;
+ }
+
+ if( props.isDataflowPassed(instr) ) {
+ return VF_OK;
+ }
+
+ fill_workmap(instr);
+ }
+ workmap_is_a_copy_of_stackmap = false;
+
+ OpCode opcode = (OpCode)m_bytecode[instr];
+ processed_instruction = instr;
+ // keep all nessesary information about instruction
+ ParseInfo &pi = instr_get_parse_info(opcode);
+
+ //check IN types, create OUT types, check exception
+ if( (tcr=dataflow_instruction(instr)) != VF_OK ) {
+ return tcr;
+ }
+
+ props.setDataflowPassed(instr);
+
+ unsigned instr_len = instr_get_minlen(pi);
+ if( instr_is_compound(opcode, pi) ) {
+ // get ACTUAL length for variable length insgtructions
+ instr_len = instr_get_len_compound(instr, opcode);
+ }
+
+ if( instr_is_jump(pi) ) {
+ Address target = instr_get_jump_target(pi, m_bytecode, instr);
+
+ if( props.isMultiway(target) || instr_is_jsr(opcode) ) {
+ //TODO: need to test commented out optimization
+ //&& (!instr_direct(pi, opcode, m_bytecode, instr) || props.isDataflowPassed(target))
+ if( (tcr=new_generic_vector_constraint(target)) != VF_OK ) {
+ return tcr;
+ }
+ }
+
+ if( instr_direct(pi, opcode, m_bytecode, instr) ) {
+ //goto, goto_w
+ if( !props.isDataflowPassed(target) ) {
+ if( target < instr ) next_start_pc = 0;
+
+ //if we like to flush StackMapTable attribute from this method
+ if( stackmapattr_calculation && !props.isMultiway(target) ) {
+ //store workmap to flush it further
+ assert(!props.getInstrProps(target));
+ storeWorkmapCopy(target);
+ }
+
+ instr = target;
+ continue;
+ } else {
+ return VF_OK;
+ }
+ }
+
+
+ //TODO: makes sense to move the block into dataflow_instruction??
+ if( instr_is_jsr(opcode) ) {
+ PropsHead *target_pro = (PropsHead*)props.getInstrProps(target);
+
+ if( !props.isDataflowPassed(target) ) {
+ for( unsigned i = 0; i < m_stack_start; i++ ) {
+ StackmapElement &el = target_pro->stackmap.elements[i];
+ el.clearJsrModified();
+ }
+
+ //create vector for storing ret types coming out of subroutine
+ PropsHead *retpro = newRetData();
+ retpro->instr = 0xFFFF;
+ assert(!target_pro->next || target_pro->next->instr != 0xFFFF );
+ retpro->next = target_pro->next;
+ target_pro->next = retpro;
+
+ SubroutineData *subrdata = retpro->getSubrData(m_stack_start+m_max_stack);
+
+ if( !props.getInstrProps(instr) && instr) {
+ //if jsr instruction does not have workmap copy or stackmap, associated with it - create it
+ assert(workmap->depth);
+ workmap->depth--; // undo PUSH(SM_RETADDR)
+ storeWorkmapCopy(instr);
+ }
+
+ //need to return to that JSR instr later, when finish subroutine processing
+ subrdata->caller = instr;
+
+ //need to postpone some finalizing stuff
+ stack.xPush(target, MARK_SUBROUTINE_DONE);
+
+ //process subroutine
+ stack.xPush(target);
+
+ return VF_OK;
+ } else {
+ SubroutineData *subrdata = ((PropsHead*)target_pro->next)->getSubrData(m_stack_start+m_max_stack);
+
+ if( !subrdata->subrDataflowed ) {
+ //recursive call?
+ return error(VF_ErrorDataFlow, "recursive subroutine");
+ }
+
+ restore_workmap_after_jsr(target);
+
+ if( !subrdata->retCount ) {
+ //no ret from subroutine -- dead code follows
+ return VF_OK;
+ }
+
+ instr += instr_len;
+ continue;
+ }
+ }
+
+ if( !props.isMultiway(target) ) {
+ //if* with no stackmap at branch
+ storeWorkmapCopy(target);
+ assert( !props.isDataflowPassed(target) );
+ }
+
+ if( !props.isDataflowPassed(target) ) {
+ stack.xPush(target);
+ }
+
+ instr += instr_len;
+ } else if( instr_direct(pi, opcode, m_bytecode, instr) ) {
+ // it is not a jump ==> it is ret, return or throw
+ return VF_OK;
+ } else if( instr_is_switch(pi) ) {
+
+ Address next_target_adr = (instr & (~3) ) + 4;
+
+ //default target
+ Address target = instr + read_int32(m_bytecode + next_target_adr);
+ processSwitchTarget(target);
+
+ // in tableswitch instruction target offsets are stored with shift = 4,
+ // in lookupswitch with shift = 8
+ int shift = (opcode == OP_TABLESWITCH) ? 4 : 8;
+
+ // process conditional jump target
+ for (next_target_adr += 12;
+ next_target_adr < instr + instr_len;
+ next_target_adr += shift)
+ {
+ target = instr + read_int32(m_bytecode + next_target_adr);
+ processSwitchTarget(target);
+ }
+
+ return VF_OK;
+ } else {
+ assert( instr_is_regular(pi) );
+ instr += instr_len;
+ }
+
+ }
+
+ // control went out of method bounds
+ return error(VF_ErrorCodeEnd, "control went out of method bounds");
+ }
+
+ vf_Result vf_Context_5::verify_method(method_handler method) {
+ vf_Result tcr;
+
+ //nothing to verify
+ if( !method_get_code_length( method ) ) {
+ return VF_OK;
+ }
+
+ //load memory storage, read variable like max_stack, etc
+ init(method);
+
+ //////////////////////////// FIRST PASS /////////////////////////
+ pass = 1;
+ stack.push(0);
+
+ unsigned short idx;
+ unsigned short start_pc;
+ unsigned short end_pc;
+ unsigned short handler_pc;
+ unsigned short handler_cp_index;
+
+ for( idx = 0; idx < m_handlecount; idx++ ) {
+ method_get_exc_handler_info( m_method, idx, &start_pc, &end_pc,
+ &handler_pc, &handler_cp_index );
+
+ if( start_pc >= end_pc || end_pc > m_code_length ) {
+ return error(VF_ErrorHandler, "start_pc >= end_pc OR end_pc > code_length");
+ }
+ stack.push(handler_pc);
+ }
+
+ //we have different slightly rules for processing dead and live code
+ //e.g. it's not a problem if dead code runs out of the method
+ //but we still have to verify it for corrupted instructions to follow RI
+ dead_code_parsing = 0;
+ do {
+ while( !stack.is_empty() ) {
+ vf_Result tcr = parse(stack.pop());
+ if( tcr != VF_OK ) {
+ return tcr;
+ }
+ }
+
+ dead_code_parsing = 1;
+
+ while( !dead_code_stack.is_empty() ) {
+ vf_Result tcr = parse(dead_code_stack.pop());
+ if( tcr != VF_OK ) {
+ return tcr;
+ }
+ }
+ } while (!stack.is_empty());
+
+
+
+ for( idx = 0; idx < m_handlecount; idx++ ) {
+
+ method_get_exc_handler_info( m_method, idx, &start_pc, &end_pc,
+ &handler_pc, &handler_cp_index );
+
+ if( end_pc < m_code_length && props.isOperand(end_pc) || props.isOperand(start_pc) ) {
+ return error(VF_ErrorCodeEnd, "start_pc or end_pc are at the middle of an instruction");
+ }
+
+ SmConstant handler_type;
+ if( handler_cp_index ) {
+ if( !tpool.cpool_get_class(handler_cp_index, &handler_type) ||
+ !tpool.mustbe_assignable(handler_type, tpool.sm_get_const_throwable()) )
+ {
+ return error(VF_ErrorHandler, "incorrect constantpool entry");
+ }
+ } else {
+ handler_type = tpool.sm_get_const_throwable();
+ }
+
+ props.setMultiway(handler_pc);
+ createHandlerStackmap(handler_pc, handler_type);
+ }
+
+ //////////////////////////// SECOND PASS /////////////////////////
+ pass = 2;
+
+ stack.xPush(0);
+ while( !stack.is_empty() ) {
+ Address next;
+ short mark;
+
+ stack.xPop(&next, &mark);
+
+ if( !mark ) {
+ tcr = StartLinearDataflow(next);
+ } else {
+ assert(mark == MARK_SUBROUTINE_DONE);
+ tcr = SubroutineDone(next);
+ }
+
+ if( tcr != VF_OK ) {
+ return tcr;
+ }
+ }
+
+ return VF_OK;
+ }
+
+
+
+
+ vf_Result vf_Context_5::new_ret_vector_constraint(Address jsr_target) {
+ PropsHead *inpro = (PropsHead*)props.getInstrProps(jsr_target);
+ PropsHead *outpro = (PropsHead*)inpro->next;
+ assert(outpro->instr == 0xFFFF);
+
+ SubroutineData *subrdata = outpro->getSubrData(m_stack_start + m_max_stack);
+ subrdata->retCount++;
+
+ //if it is a first ret from the given subroutine (majority of the cases)
+ if( subrdata->retCount == 1 ) {
+ //remove newly appeared ret addresses: it might happen
+ //if non-top subroutine made a ret
+ StackmapHead* original = inpro->getStackmap();
+ unsigned i;
+
+ for( i = 0; i < m_stack_start + workmap->depth; i++ ) {
+ if( i < m_stack_start && !workmap->elements[i].isJsrModified() ) {
+ //nothing new here
+ continue;
+ }
+
+ SmConstant val = workmap->elements[i].getAnyPossibleValue();
+ if( val.isRetAddr() ) {
+ //check if it's a newly appeared ret addfress
+
+ // '-1' is twice below to exclude top of the stack.
+ // top of the stack contains ret address for the current subroutine
+ // it also cleaned up if it's still there
+
+ if( i < m_stack_start + original->depth - 1 &&
+ original->elements[i].getAnyIncomingValue() == val )
+ {
+ //most likely: this ret address was there before
+ continue;
+ }
+
+ //iterate thru original types and look for this ret address
+ int found_in_original = 0;
+ for( unsigned j = 0; j < m_stack_start + original->depth - 1; j++ ) {
+ if( original->elements[j].getAnyIncomingValue() == val ) {
+ found_in_original = 1;
+ break;
+ }
+ }
+ if( !found_in_original ) {
+ //original types did not have this ret address
+ workmap->elements[i] = _WorkmapElement(SM_BOGUS);
+ }
+ }
+ }
+
+ //TODO make sure incoming was created as JSR transformation
+ tc_memcpy(outpro->getWorkmap(), workmap, sizeof(WorkmapHead) + sizeof(WorkmapElement) * (m_stack_start + workmap->depth));
+ return VF_OK;
+ }
+
+ return error(VF_ErrorStackDepth, "Multiple returns to single jsr");
+ }
+
+
+ void vf_Context_5::restore_workmap_after_jsr(Address jsr_target) {
+ PropsHead *inpro = (PropsHead*)props.getInstrProps(jsr_target);
+ PropsHead *outpro = (PropsHead*)inpro->next;
+ SubroutineData *subrdata = outpro->getSubrData(m_stack_start + m_max_stack);
+
+ if( subrdata->retCount ) {
+ assert( subrdata->retCount == 1 );
+ WorkmapHead* outcoming = outpro->getWorkmap();
+ workmap->depth = outcoming->depth;
+
+ unsigned i;
+ for( i = 0; i < m_stack_start; i++ ) {
+ if( outcoming->elements[i].isJsrModified() ) {
+ workmap->elements[i] = outcoming->elements[i];
+ }
+ }
+ for( ; i < m_stack_start + workmap->depth; i++ ) {
+ workmap->elements[i] = outcoming->elements[i];
+ }
+ }
+ }
+
+ vf_Result vf_Context_5::new_scalar_constraint(WorkmapElement *from, StackmapElement *to) {
+ assert(from->getAnyPossibleValue() != SM_NONE);
+
+ if( from->isJsrModified() ) {
+ //JSR overhead
+ to->setJsrModified();
+ }
+
+ if( !from->isVariable() ) {
+ SmConstant inc_val = from->getConst();
+ return add_incoming_value( inc_val, to );
+ } else {
+ GenericCnstr* gen = from->getVariable()->firstGenericCnstr();
+ while( gen ) {
+ if( gen->variable == to ) return VF_OK;
+ gen = gen->next();
+ }
+
+ IncomingType *inc = from->getVariable()->firstIncoming();
+ from->getVariable()->newGenericConstraint(&mem, to);
+
+ while( inc ) {
+ vf_Result vcr = add_incoming_value( inc->value, to );
+ if( vcr != VF_OK ) {
+ return vcr;
+ }
+ inc = inc->next();
+ }
+ return VF_OK;
+ }
+ }
+
+ vf_Result vf_Context_5::add_incoming_value(SmConstant new_value, StackmapElement *destination) {
+ //check if the node already has such incoming value
+ IncomingType *inc = destination->firstIncoming();
+ while( inc ) {
+ if( new_value == inc->value || inc->value == SM_BOGUS ) {
+ return VF_OK;
+ }
+ inc = inc->next();
+ }
+
+ if( new_value.isNonMergeable() && destination->firstIncoming() ) {
+ //uninit value merged to any different value is bogus
+ //ret address merged to any different value is bogus
+ //assert - incoming value exists is different - we've already checked that new_value is missing in the list of incoming values
+ new_value = SM_BOGUS;
+ }
+
+ //add incoming value if it does not have
+ Constraint* next = destination->firstOthers();
+ //TODO: optimize memory footprint for new_value == SM_BOGUS
+ destination->newIncomingType(&mem, new_value);
+
+ //check if it contradicts to expected types and further propagate
+ while( next ) {
+ switch (next->type) {
+ case CT_EXPECTED_TYPE:
+ if( !tpool.mustbe_assignable(new_value, next->value) ) return error(VF_ErrorUnknown, "unexpected type on stack or local variable");
+ break;
+ case CT_GENERIC: {
+ vf_Result vcr = add_incoming_value(new_value, next->variable);
+ if( vcr != VF_OK ) return vcr;
+ break;
+ }
+ case CT_ARRAY2REF: {
+ vf_Result vcr = add_incoming_value( tpool.get_ref_from_array(new_value), next->variable);
+ if( vcr != VF_OK ) return vcr;
+ break;
+ }
+ default:
+ assert(0);
+ return error(VF_ErrorInternal, "unreachable statement in add_incoming_value");
+ }
+ next = next->next();
+ }
+ return VF_OK;
+ }
+
+} // namespace CPVerifier
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/java5/context_5.cpp
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: harmony/enhanced/drlvm/trunk/vm/vmcore/src/verifier-3363/java5/context_5.cpp
('svn:executable' removed)