Fri, 14 Jun 2013 21:16:14 +0530
8016618: script mirror object access should be improved
Reviewed-by: jlaskey, lagergren
1 /*
2 * Copyright (c) 2010, 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 */
26 package jdk.nashorn.internal.objects;
28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError;
29 import static jdk.nashorn.internal.runtime.ScriptRuntime.UNDEFINED;
31 import jdk.nashorn.api.scripting.ScriptObjectMirror;
32 import jdk.nashorn.internal.objects.annotations.Attribute;
33 import jdk.nashorn.internal.objects.annotations.Constructor;
34 import jdk.nashorn.internal.objects.annotations.Function;
35 import jdk.nashorn.internal.objects.annotations.ScriptClass;
36 import jdk.nashorn.internal.objects.annotations.Where;
37 import jdk.nashorn.internal.runtime.ECMAException;
38 import jdk.nashorn.internal.runtime.JSType;
39 import jdk.nashorn.internal.runtime.ScriptFunction;
40 import jdk.nashorn.internal.runtime.ScriptObject;
41 import jdk.nashorn.internal.runtime.ScriptRuntime;
42 import jdk.nashorn.internal.runtime.linker.InvokeByName;
44 /**
45 * ECMA 15.2 Object objects
46 *
47 * JavaScript Object constructor/prototype. Note: instances of this class are
48 * never created. This class is not even a subclass of ScriptObject. But, we use
49 * this class to generate prototype and constructor for "Object".
50 *
51 */
52 @ScriptClass("Object")
53 public final class NativeObject {
54 private static final InvokeByName TO_STRING = new InvokeByName("toString", ScriptObject.class);
56 private NativeObject() {
57 }
59 private static ECMAException notAnObject(final Object obj) {
60 return typeError("not.an.object", ScriptRuntime.safeToString(obj));
61 }
63 /**
64 * ECMA 15.2.3.2 Object.getPrototypeOf ( O )
65 *
66 * @param self self reference
67 * @param obj object to get prototype from
68 * @return the prototype of an object
69 */
70 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
71 public static Object getPrototypeOf(final Object self, final Object obj) {
72 if (obj instanceof ScriptObject) {
73 return ((ScriptObject)obj).getProto();
74 } else if (obj instanceof ScriptObjectMirror) {
75 return ((ScriptObjectMirror)obj).getProto();
76 } else {
77 throw notAnObject(obj);
78 }
79 }
81 /**
82 * ECMA 15.2.3.3 Object.getOwnPropertyDescriptor ( O, P )
83 *
84 * @param self self reference
85 * @param obj object from which to get property descriptor for {@code ToString(prop)}
86 * @param prop property descriptor
87 * @return property descriptor
88 */
89 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
90 public static Object getOwnPropertyDescriptor(final Object self, final Object obj, final Object prop) {
91 if (obj instanceof ScriptObject) {
92 final String key = JSType.toString(prop);
93 final ScriptObject sobj = (ScriptObject)obj;
95 return sobj.getOwnPropertyDescriptor(key);
96 } else if (obj instanceof ScriptObjectMirror) {
97 final String key = JSType.toString(prop);
98 final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj;
100 return sobjMirror.getOwnPropertyDescriptor(key);
101 } else {
102 throw notAnObject(obj);
103 }
104 }
106 /**
107 * ECMA 15.2.3.4 Object.getOwnPropertyNames ( O )
108 *
109 * @param self self reference
110 * @param obj object to query for property names
111 * @return array of property names
112 */
113 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
114 public static Object getOwnPropertyNames(final Object self, final Object obj) {
115 if (obj instanceof ScriptObject) {
116 return new NativeArray(((ScriptObject)obj).getOwnKeys(true));
117 } else if (obj instanceof ScriptObjectMirror) {
118 return new NativeArray(((ScriptObjectMirror)obj).getOwnKeys(true));
119 } else {
120 throw notAnObject(obj);
121 }
122 }
124 /**
125 * ECMA 15.2.3.5 Object.create ( O [, Properties] )
126 *
127 * @param self self reference
128 * @param proto prototype object
129 * @param props properties to define
130 * @return object created
131 */
132 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
133 public static Object create(final Object self, final Object proto, final Object props) {
134 if (proto != null) {
135 Global.checkObject(proto);
136 }
138 // FIXME: should we create a proper object with correct number of
139 // properties?
140 final ScriptObject newObj = Global.newEmptyInstance();
141 newObj.setProtoCheck(proto);
142 if (props != UNDEFINED) {
143 NativeObject.defineProperties(self, newObj, props);
144 }
146 return newObj;
147 }
149 /**
150 * ECMA 15.2.3.6 Object.defineProperty ( O, P, Attributes )
151 *
152 * @param self self reference
153 * @param obj object in which to define a property
154 * @param prop property to define
155 * @param attr attributes for property descriptor
156 * @return object
157 */
158 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
159 public static Object defineProperty(final Object self, final Object obj, final Object prop, final Object attr) {
160 Global.checkObject(obj);
161 ((ScriptObject)obj).defineOwnProperty(JSType.toString(prop), attr, true);
162 return obj;
163 }
165 /**
166 * ECMA 5.2.3.7 Object.defineProperties ( O, Properties )
167 *
168 * @param self self reference
169 * @param obj object in which to define properties
170 * @param props properties
171 * @return object
172 */
173 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
174 public static Object defineProperties(final Object self, final Object obj, final Object props) {
175 Global.checkObject(obj);
177 final ScriptObject sobj = (ScriptObject)obj;
178 final Object propsObj = Global.toObject(props);
180 if (propsObj instanceof ScriptObject) {
181 final Object[] keys = ((ScriptObject)propsObj).getOwnKeys(false);
182 for (final Object key : keys) {
183 final String prop = JSType.toString(key);
184 sobj.defineOwnProperty(prop, ((ScriptObject)propsObj).get(prop), true);
185 }
186 }
187 return sobj;
188 }
190 /**
191 * ECMA 15.2.3.8 Object.seal ( O )
192 *
193 * @param self self reference
194 * @param obj object to seal
195 * @return sealed object
196 */
197 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
198 public static Object seal(final Object self, final Object obj) {
199 if (obj instanceof ScriptObject) {
200 return ((ScriptObject)obj).seal();
201 } else if (obj instanceof ScriptObjectMirror) {
202 return ((ScriptObjectMirror)obj).seal();
203 } else {
204 throw notAnObject(obj);
205 }
206 }
209 /**
210 * ECMA 15.2.3.9 Object.freeze ( O )
211 *
212 * @param self self reference
213 * @param obj object to freeze
214 * @return frozen object
215 */
216 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
217 public static Object freeze(final Object self, final Object obj) {
218 if (obj instanceof ScriptObject) {
219 return ((ScriptObject)obj).freeze();
220 } else if (obj instanceof ScriptObjectMirror) {
221 return ((ScriptObjectMirror)obj).freeze();
222 } else {
223 throw notAnObject(obj);
224 }
225 }
227 /**
228 * ECMA 15.2.3.10 Object.preventExtensions ( O )
229 *
230 * @param self self reference
231 * @param obj object, for which to set the internal extensible property to false
232 * @return object
233 */
234 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
235 public static Object preventExtensions(final Object self, final Object obj) {
236 if (obj instanceof ScriptObject) {
237 return ((ScriptObject)obj).preventExtensions();
238 } else if (obj instanceof ScriptObjectMirror) {
239 return ((ScriptObjectMirror)obj).preventExtensions();
240 } else {
241 throw notAnObject(obj);
242 }
243 }
245 /**
246 * ECMA 15.2.3.11 Object.isSealed ( O )
247 *
248 * @param self self reference
249 * @param obj check whether an object is sealed
250 * @return true if sealed, false otherwise
251 */
252 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
253 public static Object isSealed(final Object self, final Object obj) {
254 if (obj instanceof ScriptObject) {
255 return ((ScriptObject)obj).isSealed();
256 } else if (obj instanceof ScriptObjectMirror) {
257 return ((ScriptObjectMirror)obj).isSealed();
258 } else {
259 throw notAnObject(obj);
260 }
261 }
263 /**
264 * ECMA 15.2.3.12 Object.isFrozen ( O )
265 *
266 * @param self self reference
267 * @param obj check whether an object
268 * @return true if object is frozen, false otherwise
269 */
270 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
271 public static Object isFrozen(final Object self, final Object obj) {
272 if (obj instanceof ScriptObject) {
273 return ((ScriptObject)obj).isFrozen();
274 } else if (obj instanceof ScriptObjectMirror) {
275 return ((ScriptObjectMirror)obj).isFrozen();
276 } else {
277 throw notAnObject(obj);
278 }
279 }
281 /**
282 * ECMA 15.2.3.13 Object.isExtensible ( O )
283 *
284 * @param self self reference
285 * @param obj check whether an object is extensible
286 * @return true if object is extensible, false otherwise
287 */
288 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
289 public static Object isExtensible(final Object self, final Object obj) {
290 if (obj instanceof ScriptObject) {
291 return ((ScriptObject)obj).isExtensible();
292 } else if (obj instanceof ScriptObjectMirror) {
293 return ((ScriptObjectMirror)obj).isExtensible();
294 } else {
295 throw notAnObject(obj);
296 }
297 }
299 /**
300 * ECMA 15.2.3.14 Object.keys ( O )
301 *
302 * @param self self reference
303 * @param obj object from which to extract keys
304 * @return array of keys in object
305 */
306 @Function(attributes = Attribute.NOT_ENUMERABLE, where = Where.CONSTRUCTOR)
307 public static Object keys(final Object self, final Object obj) {
308 if (obj instanceof ScriptObject) {
309 final ScriptObject sobj = (ScriptObject)obj;
310 return new NativeArray(sobj.getOwnKeys(false));
311 } else if (obj instanceof ScriptObjectMirror) {
312 final ScriptObjectMirror sobjMirror = (ScriptObjectMirror)obj;
313 return new NativeArray(sobjMirror.getOwnKeys(false));
314 } else {
315 throw notAnObject(obj);
316 }
317 }
319 /**
320 * ECMA 15.2.2.1 , 15.2.1.1 new Object([value]) and Object([value])
321 *
322 * Constructor
323 *
324 * @param newObj is the new object instantiated with the new operator
325 * @param self self reference
326 * @param value value of object to be instantiated
327 * @return the new NativeObject
328 */
329 @Constructor
330 public static Object construct(final boolean newObj, final Object self, final Object value) {
331 final JSType type = JSType.of(value);
333 // Object(null), Object(undefined), Object() are same as "new Object()"
335 if (newObj || (type == JSType.NULL || type == JSType.UNDEFINED)) {
336 switch (type) {
337 case BOOLEAN:
338 case NUMBER:
339 case STRING:
340 return Global.toObject(value);
341 case OBJECT:
342 case FUNCTION:
343 return value;
344 case NULL:
345 case UNDEFINED:
346 // fall through..
347 default:
348 break;
349 }
351 return Global.newEmptyInstance();
352 }
354 return Global.toObject(value);
355 }
357 /**
358 * ECMA 15.2.4.2 Object.prototype.toString ( )
359 *
360 * @param self self reference
361 * @return ToString of object
362 */
363 @Function(attributes = Attribute.NOT_ENUMERABLE)
364 public static Object toString(final Object self) {
365 return ScriptRuntime.builtinObjectToString(self);
366 }
368 /**
369 * ECMA 15.2.4.3 Object.prototype.toLocaleString ( )
370 *
371 * @param self self reference
372 * @return localized ToString
373 */
374 @Function(attributes = Attribute.NOT_ENUMERABLE)
375 public static Object toLocaleString(final Object self) {
376 final Object obj = JSType.toScriptObject(self);
377 if (obj instanceof ScriptObject) {
378 final ScriptObject sobj = (ScriptObject)self;
379 try {
380 final Object toString = TO_STRING.getGetter().invokeExact(sobj);
382 if (toString instanceof ScriptFunction) {
383 return TO_STRING.getInvoker().invokeExact(toString, sobj);
384 }
385 } catch (final RuntimeException | Error e) {
386 throw e;
387 } catch (final Throwable t) {
388 throw new RuntimeException(t);
389 }
391 throw typeError("not.a.function", "toString");
392 }
394 return ScriptRuntime.builtinObjectToString(self);
395 }
397 /**
398 * ECMA 15.2.4.4 Object.prototype.valueOf ( )
399 *
400 * @param self self reference
401 * @return value of object
402 */
403 @Function(attributes = Attribute.NOT_ENUMERABLE)
404 public static Object valueOf(final Object self) {
405 return Global.toObject(self);
406 }
408 /**
409 * ECMA 15.2.4.5 Object.prototype.hasOwnProperty (V)
410 *
411 * @param self self reference
412 * @param v property to check for
413 * @return true if property exists in object
414 */
415 @Function(attributes = Attribute.NOT_ENUMERABLE)
416 public static Object hasOwnProperty(final Object self, final Object v) {
417 final String str = JSType.toString(v);
418 final Object obj = Global.toObject(self);
420 return (obj instanceof ScriptObject) && ((ScriptObject)obj).hasOwnProperty(str);
421 }
423 /**
424 * ECMA 15.2.4.6 Object.prototype.isPrototypeOf (V)
425 *
426 * @param self self reference
427 * @param v v prototype object to check against
428 * @return true if object is prototype of v
429 */
430 @Function(attributes = Attribute.NOT_ENUMERABLE)
431 public static Object isPrototypeOf(final Object self, final Object v) {
432 if (!(v instanceof ScriptObject)) {
433 return false;
434 }
436 final Object obj = Global.toObject(self);
437 ScriptObject proto = (ScriptObject)v;
439 do {
440 proto = proto.getProto();
441 if (proto == obj) {
442 return true;
443 }
444 } while (proto != null);
446 return false;
447 }
449 /**
450 * ECMA 15.2.4.7 Object.prototype.propertyIsEnumerable (V)
451 *
452 * @param self self reference
453 * @param v property to check if enumerable
454 * @return true if property is enumerable
455 */
456 @Function(attributes = Attribute.NOT_ENUMERABLE)
457 public static Object propertyIsEnumerable(final Object self, final Object v) {
458 final String str = JSType.toString(v);
459 final Object obj = Global.toObject(self);
461 if (obj instanceof ScriptObject) {
462 final jdk.nashorn.internal.runtime.Property property = ((ScriptObject)obj).getMap().findProperty(str);
463 return property != null && property.isEnumerable();
464 }
466 return false;
467 }
468 }