1 /*
2  * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 #include "CmdIDList.h"
27 
28 // How much space to allocate initially
29 static const UINT ARRAY_INITIAL_SIZE = 1024;
30 
31 // Array expansion increment when need more free space
32 static const UINT ARRAY_SIZE_INCREMENT = 1024;
33 
34 // It seems that Win95 can not handle ids greater than 2**16
35 static const UINT ARRAY_MAXIMUM_SIZE = 32768;
36 
37 
AwtCmdIDList()38 AwtCmdIDList::AwtCmdIDList()
39 {
40     m_capacity = ARRAY_INITIAL_SIZE;
41     m_first_free = -1;
42     m_array = (CmdIDEntry *)SAFE_SIZE_ARRAY_ALLOC(safe_Malloc, m_capacity, sizeof(AwtObject*));
43     BuildFreeList(0);
44 }
45 
~AwtCmdIDList()46 AwtCmdIDList::~AwtCmdIDList()
47 {
48     free(m_array);
49 }
50 
51 
52 // Build a new free list from a newly allocated memory.  This only
53 // happens after malloc/realloc, and new free entries are contiguous
54 // from first_index to m_capacity-1
BuildFreeList(UINT first_index)55 INLINE void AwtCmdIDList::BuildFreeList(UINT first_index)
56 {
57     DASSERT(m_first_free == -1);
58     for (UINT i = first_index; i < m_capacity-1; ++i)
59         m_array[i].next_free_index = i+1;
60     m_array[m_capacity-1].next_free_index = -1; // nil
61     m_first_free = first_index; // head of the free list
62 }
63 
64 
isFreeIDAvailable()65 jboolean AwtCmdIDList::isFreeIDAvailable() {
66     CriticalSection::Lock l(m_lock);
67 
68     if (m_first_free == -1) {   // out of free ids
69         if (m_capacity == ARRAY_MAXIMUM_SIZE) {
70             return JNI_FALSE;
71         }
72     }
73     return JNI_TRUE;
74 }
75 
76 // Assign an id to the object.  Recycle the first free entry from the
77 // head of the free list or allocate more memory for a new free list.
Add(AwtObject * obj)78 UINT AwtCmdIDList::Add(AwtObject* obj)
79 {
80     CriticalSection::Lock l(m_lock);
81     if (!isFreeIDAvailable()) {
82         throw std::bad_alloc(); // fatal error
83     }
84 
85     if (m_first_free == -1) {   // out of free ids
86         // snarf a bigger arena
87         UINT old_capacity = m_capacity; // will be the first free entry
88         m_capacity += ARRAY_SIZE_INCREMENT;
89         if (m_capacity > ARRAY_MAXIMUM_SIZE)
90             m_capacity = ARRAY_MAXIMUM_SIZE;
91         m_array = (CmdIDEntry *)SAFE_SIZE_ARRAY_REALLOC(safe_Realloc, m_array,
92                                     m_capacity, sizeof(CmdIDEntry*));
93         BuildFreeList(old_capacity);
94     }
95 
96     DASSERT(m_first_free != -1);
97     UINT newid = m_first_free;  // use the entry from the head of the list
98     m_first_free = m_array[newid].next_free_index; // advance free pointer
99     m_array[newid].obj = obj;
100 
101     return newid;
102 }
103 
104 // Return the object associated with this id..
Lookup(UINT id)105 AwtObject* AwtCmdIDList::Lookup(UINT id)
106 {
107     CriticalSection::Lock l(m_lock);
108     DASSERT(id < m_capacity);
109     if (m_array[id].next_free_index <= ARRAY_MAXIMUM_SIZE) {
110         return NULL;
111     }
112     return m_array[id].obj;
113 }
114 
115 // Return this id to the head of the free list.
Remove(UINT id)116 void AwtCmdIDList::Remove(UINT id)
117 {
118     CriticalSection::Lock l(m_lock);
119     DASSERT(id < m_capacity);
120     DASSERT(m_array[id].next_free_index > ARRAY_MAXIMUM_SIZE); // it's a pointer
121     m_array[id].next_free_index = m_first_free;
122     m_first_free = id;
123 }
124