1 /*
2 * Copyright (c) 2010-2014, 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 package jdk.nashorn.internal.runtime;
27
28 import static jdk.nashorn.internal.codegen.ObjectClassGenerator.OBJECT_FIELDS_ONLY;
29 import static jdk.nashorn.internal.lookup.Lookup.MH;
30
31 import java.lang.invoke.MethodHandle;
32 import java.lang.invoke.MethodHandles;
33
34 /**
35 * Spill property
36 */
37 public class SpillProperty extends AccessorProperty {
38 private static final long serialVersionUID = 3028496245198669460L;
39
40 private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
41
42 private static final MethodHandle PARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "primitiveSpill", long[].class), MH.type(long[].class, Object.class));
43 private static final MethodHandle OARRAY_GETTER = MH.asType(MH.getter(LOOKUP, ScriptObject.class, "objectSpill", Object[].class), MH.type(Object[].class, Object.class));
44
45 private static final MethodHandle OBJECT_GETTER = MH.filterArguments(MH.arrayElementGetter(Object[].class), 0, OARRAY_GETTER);
46 private static final MethodHandle PRIMITIVE_GETTER = MH.filterArguments(MH.arrayElementGetter(long[].class), 0, PARRAY_GETTER);
47 private static final MethodHandle OBJECT_SETTER = MH.filterArguments(MH.arrayElementSetter(Object[].class), 0, OARRAY_GETTER);
48 private static final MethodHandle PRIMITIVE_SETTER = MH.filterArguments(MH.arrayElementSetter(long[].class), 0, PARRAY_GETTER);
49
50 private static class Accessors {
51 private MethodHandle objectGetter;
52 private MethodHandle objectSetter;
53 private MethodHandle primitiveGetter;
54 private MethodHandle primitiveSetter;
55
56 private final int slot;
57 private final MethodHandle ensureSpillSize;
58
59 private static Accessors ACCESSOR_CACHE[] = new Accessors[512];
60
61 //private static final Map<Integer, Reference<Accessors>> ACCESSOR_CACHE = Collections.synchronizedMap(new WeakHashMap<Integer, Reference<Accessors>>());
62
63 Accessors(final int slot) {
64 assert slot >= 0;
65 this.slot = slot;
66 this.ensureSpillSize = MH.asType(MH.insertArguments(ScriptObject.ENSURE_SPILL_SIZE, 1, slot), MH.type(Object.class, Object.class));
67 }
68
69 private static void ensure(final int slot) {
70 int len = ACCESSOR_CACHE.length;
71 if (slot >= len) {
72 do {
73 len *= 2;
74 } while (slot >= len);
75 final Accessors newCache[] = new Accessors[len];
76 System.arraycopy(ACCESSOR_CACHE, 0, newCache, 0, ACCESSOR_CACHE.length);
77 ACCESSOR_CACHE = newCache;
78 }
79 }
80
81 static MethodHandle getCached(final int slot, final boolean isPrimitive, final boolean isGetter) {
82 //Reference<Accessors> ref = ACCESSOR_CACHE.get(slot);
83 ensure(slot);
84 Accessors acc = ACCESSOR_CACHE[slot];
85 if (acc == null) {
86 acc = new Accessors(slot);
87 ACCESSOR_CACHE[slot] = acc;
88 }
89
90 return acc.getOrCreate(isPrimitive, isGetter);
91 }
92
93 private static MethodHandle primordial(final boolean isPrimitive, final boolean isGetter) {
94 if (isPrimitive) {
95 return isGetter ? PRIMITIVE_GETTER : PRIMITIVE_SETTER;
96 }
97 return isGetter ? OBJECT_GETTER : OBJECT_SETTER;
98 }
99
100 MethodHandle getOrCreate(final boolean isPrimitive, final boolean isGetter) {
101 MethodHandle accessor;
102
103 accessor = getInner(isPrimitive, isGetter);
104 if (accessor != null) {
105 return accessor;
106 }
107
108 accessor = primordial(isPrimitive, isGetter);
109 accessor = MH.insertArguments(accessor, 1, slot);
110 if (!isGetter) {
111 accessor = MH.filterArguments(accessor, 0, ensureSpillSize);
112 }
113 setInner(isPrimitive, isGetter, accessor);
114
115 return accessor;
116 }
117
118 void setInner(final boolean isPrimitive, final boolean isGetter, final MethodHandle mh) {
119 if (isPrimitive) {
120 if (isGetter) {
121 primitiveGetter = mh;
122 } else {
123 primitiveSetter = mh;
124 }
125 } else {
126 if (isGetter) {
127 objectGetter = mh;
128 } else {
129 objectSetter = mh;
130 }
131 }
132 }
133
134 MethodHandle getInner(final boolean isPrimitive, final boolean isGetter) {
135 if (isPrimitive) {
136 return isGetter ? primitiveGetter : primitiveSetter;
137 }
138 return isGetter ? objectGetter : objectSetter;
139 }
140 }
141
142 private static MethodHandle primitiveGetter(final int slot) {
143 return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, true);
144 }
145 private static MethodHandle primitiveSetter(final int slot) {
146 return OBJECT_FIELDS_ONLY ? null : Accessors.getCached(slot, true, false);
147 }
148 private static MethodHandle objectGetter(final int slot) {
149 return Accessors.getCached(slot, false, true);
150 }
151 private static MethodHandle objectSetter(final int slot) {
152 return Accessors.getCached(slot, false, false);
153 }
154
155 /**
156 * Constructor for spill properties. Array getters and setters will be created on demand.
157 *
158 * @param key the property key
159 * @param flags the property flags
160 * @param slot spill slot
161 */
162 public SpillProperty(final String key, final int flags, final int slot) {
163 super(key, flags, slot, primitiveGetter(slot), primitiveSetter(slot), objectGetter(slot), objectSetter(slot));
164 assert !OBJECT_FIELDS_ONLY || getLocalType() == Object.class;
165 }
166
167 SpillProperty(final String key, final int flags, final int slot, final Class<?> initialType) {
168 this(key, flags, slot);
169 setType(OBJECT_FIELDS_ONLY ? Object.class : initialType);
170 }
171
172 SpillProperty(final String key, final int flags, final int slot, final ScriptObject owner, final Object initialValue) {
173 this(key, flags, slot);
174 setInitialValue(owner, initialValue);
175 }
176
177 /**
178 * Copy constructor
179 * @param property other property
180 */
181 protected SpillProperty(final SpillProperty property) {
182 super(property);
183 }
184
185 /**
186 * Copy constructor
187 * @param newType new type
188 * @param property other property
189 */
190 protected SpillProperty(final SpillProperty property, final Class<?> newType) {
191 super(property, newType);
192 }
193
194 @Override
195 public Property copy() {
196 return new SpillProperty(this);
197 }
198
199 @Override
200 public Property copy(final Class<?> newType) {
201 return new SpillProperty(this, newType);
202 }
203
204 @Override
205 public boolean isSpill() {
206 return true;
207 }
208
209 @Override
210 void initMethodHandles(final Class<?> structure) {
211 final int slot = getSlot();
212 primitiveGetter = primitiveGetter(slot);
213 primitiveSetter = primitiveSetter(slot);
214 objectGetter = objectGetter(slot);
215 objectSetter = objectSetter(slot);
216 }
217 }
--- EOF ---