blob: 19d14428ed5479c41af2d0d7dc2ba8fcde96a26f [file] [log] [blame]
/*
* 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.
*/
#ifndef _STRING_POOL_H_
#define _STRING_POOL_H_
#include <string.h>
#include <apr_hash.h>
#include "tl/memory_pool.h"
#include "object_layout.h"
#define STRING_PADDING sizeof(void*)
struct String
{
#ifdef _DEBUG
unsigned id; // id for debugging
#endif
// 20030507 Ref to the interned string used by java.lang.String.intern().
// It is compressed when compressing refs.
unsigned len;
union {
// raw reference to interned string if not compressing references
ManagedObject * raw_ref;
// equivalent compressed reference.
U_32 compressed_ref;
} intern;
char bytes[STRING_PADDING];
};
class String_Pool {
public:
String_Pool(size_t st_size);
// lookup string in string table & insert if not found
String * lookup(const char *str);
String * lookup(const char *str, size_t len);
// Iterators for GC
String * get_first_string_intern();
String * get_next_string_intern();
// intern the string
ManagedObject * intern(String *);
// The GC enumeration code needs to lock and unlock the
// pool in order to enumerate it in a thread safe manner.
void lock_pool();
void unlock_pool();
#ifdef VM_STATS
friend class VM_Statistics;
public:
apr_hash_t * string_stat;
unsigned num_ambiguity;
#endif
private:
enum { INTERNED_STRING_ARRAY_SIZE = 32768 };
size_t string_pool_size;
class Entry {
public:
Entry * next;
String str;
Entry(const char *s, size_t len, Entry *n);
/**
* Memory is already allocated for this object.
*/
void *operator new(size_t UNREF sz, void * mem) { return mem; }
void operator delete(void * UNREF mem, void * UNREF mem1) {}
};
struct Interned_Strings {
Interned_Strings * next;
// this field is used for synchronization purposes
volatile unsigned free_slot;
String * elem[INTERNED_STRING_ARRAY_SIZE];
};
struct Interned_Strings_Index {
Interned_Strings * current;
unsigned index;
};
// bit mask to test for end of line character
static const POINTER_SIZE_INT BIT_MASK =
#ifdef POINTER64
0x7efefefefefefeffL;
#else
0x7efefeffL;
#endif
bool has_line_end(POINTER_SIZE_INT val);
void hash_it(const char * str, size_t* len, POINTER_SIZE_INT * hash);
POINTER_SIZE_INT hash_it(const char * str, size_t len);
String * lookup(const char *str, size_t len, POINTER_SIZE_INT hash);
void register_interned_string(String * str);
POINTER_SIZE_INT hash_it_unaligned(const char * str, size_t len);
// memory pool
tl::MemoryPool memory_pool;
// table of string entries
Entry ** table;
// linked list of arrays of interned strings
Interned_Strings * head_interned;
// current list element
volatile Interned_Strings * current_interned;
// iterator to go through interned strings
// NOTE: only one thread can iterate through at once
// Moreover the iteration should be done in stop_the_world phase since no
// synchronization between String_Pool::intern() & String_Pool::get_next_string_intern()
Interned_Strings_Index * index_interned;
// In order to make this code thread safe a light weight lock is used.
// The protocol is simple and the lock is local to this string pool.
volatile POINTER_SIZE_INT string_pool_lock; // 1 is locked, 0 is unlocked
};
#endif // _STRING_POOL_H_