1/*
2 * Copyright (c) 2000, 2002, 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.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.code;
26
27import java.util.*;
28import sun.jvm.hotspot.debugger.*;
29import sun.jvm.hotspot.runtime.*;
30import sun.jvm.hotspot.types.*;
31import sun.jvm.hotspot.utilities.*;
32
33/** <P> A port of the VM's StubQueue. Note that the VM implicitly
34    knows the type of the objects contained in each StubQueue because
35    it passes in an instance of a StubInterface to the StubQueue's
36    constructor; the goal in the VM was to save space in the generated
37    code. In the SA APIs the pattern has been to use the
38    VirtualConstructor mechanism to instantiate wrapper objects of the
39    appropriate type for objects down in the VM; see, for example, the
40    CodeCache, which identifies NMethods, RuntimeStubs, etc. </P>
41
42    <P> In this port we eliminate the StubInterface in favor of
43    passing in the class corresponding to the type of Stub which this
44    StubQueue contains. </P> */
45
46public class StubQueue extends VMObject {
47  // FIXME: add the rest of the fields
48  private static AddressField  stubBufferField;
49  private static CIntegerField bufferLimitField;
50  private static CIntegerField queueBeginField;
51  private static CIntegerField queueEndField;
52  private static CIntegerField numberOfStubsField;
53
54  // The type of the contained stubs (i.e., InterpreterCodelet,
55  // ICStub). Must be a subclass of type Stub.
56  private Class stubType;
57
58  static {
59    VM.registerVMInitializedObserver(new Observer() {
60        public void update(Observable o, Object data) {
61          initialize(VM.getVM().getTypeDataBase());
62        }
63      });
64  }
65
66  private static synchronized void initialize(TypeDataBase db) {
67    Type type = db.lookupType("StubQueue");
68
69    stubBufferField    = type.getAddressField("_stub_buffer");
70    bufferLimitField   = type.getCIntegerField("_buffer_limit");
71    queueBeginField    = type.getCIntegerField("_queue_begin");
72    queueEndField      = type.getCIntegerField("_queue_end");
73    numberOfStubsField = type.getCIntegerField("_number_of_stubs");
74  }
75
76  public StubQueue(Address addr, Class stubType) {
77    super(addr);
78    this.stubType = stubType;
79  }
80
81  public boolean contains(Address pc) {
82    if (pc == null) return false;
83    long offset = pc.minus(getStubBuffer());
84    return ((0 <= offset) && (offset < getBufferLimit()));
85  }
86
87  public Stub getStubContaining(Address pc) {
88    if (contains(pc)) {
89      int i = 0;
90      for (Stub s = getFirst(); s != null; s = getNext(s)) {
91        if (stubContains(s, pc)) {
92          return s;
93        }
94      }
95    }
96    return null;
97  }
98
99  public boolean stubContains(Stub s, Address pc) {
100    return (s.codeBegin().lessThanOrEqual(pc) && s.codeEnd().greaterThan(pc));
101  }
102
103  public int getNumberOfStubs() {
104    return (int) numberOfStubsField.getValue(addr);
105  }
106
107  public Stub getFirst() {
108    return ((getNumberOfStubs() > 0) ? getStubAt(getQueueBegin()) : null);
109  }
110
111  public Stub getNext(Stub s) {
112    long i = getIndexOf(s) + getStubSize(s);
113    if (i == getBufferLimit()) {
114      i = 0;
115    }
116    return ((i == getQueueEnd()) ? null : getStubAt(i));
117  }
118
119  public Stub getPrev(Stub s) {
120    if (getIndexOf(s) == getQueueBegin()) {
121       return null;
122    }
123
124    Stub temp = getFirst();
125    Stub prev = null;
126    while (temp != null && getIndexOf(temp) != getIndexOf(s)) {
127       prev = temp;
128       temp  = getNext(temp);
129    }
130
131    return prev;
132  }
133
134  //--------------------------------------------------------------------------------
135  // Internals only below this point
136  //
137
138  private long getQueueBegin() {
139    return queueBeginField.getValue(addr);
140  }
141
142  private long getQueueEnd() {
143    return queueEndField.getValue(addr);
144  }
145
146  private long getBufferLimit() {
147    return bufferLimitField.getValue(addr);
148  }
149
150  private Address getStubBuffer() {
151    return stubBufferField.getValue(addr);
152  }
153
154  private Stub getStubAt(long offset) {
155    checkIndex(offset);
156    return (Stub) VMObjectFactory.newObject(stubType, getStubBuffer().addOffsetTo(offset));
157  }
158
159  private long getIndexOf(Stub s) {
160    long i = s.getAddress().minus(getStubBuffer());
161    checkIndex(i);
162    return i;
163  }
164
165  private long getStubSize(Stub s) {
166    return s.getSize();
167  }
168
169  private void checkIndex(long i) {
170    if (Assert.ASSERTS_ENABLED) {
171      Assert.that(0 <= i && i < getBufferLimit() && (i % VM.getVM().getAddressSize() == 0), "illegal index");
172    }
173  }
174}
175