258
259 @Override
260 public Object getLength() {
261 final long length = JSType.toUint32(getArray().length());
262 if (length < Integer.MAX_VALUE) {
263 return (int)length;
264 }
265 return length;
266 }
267
268 private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) {
269 // Step 3a
270 if (!desc.has(VALUE)) {
271 return super.defineOwnProperty("length", desc, reject);
272 }
273
274 // Step 3b
275 final PropertyDescriptor newLenDesc = desc;
276
277 // Step 3c and 3d - get new length and convert to long
278 final long newLen = NativeArray.validLength(newLenDesc.getValue(), true);
279
280 // Step 3e
281 newLenDesc.setValue(newLen);
282
283 // Step 3f
284 // increasing array length - just need to set new length value (and attributes if any) and return
285 if (newLen >= oldLen) {
286 return super.defineOwnProperty("length", newLenDesc, reject);
287 }
288
289 // Step 3g
290 if (!oldLenDesc.isWritable()) {
291 if (reject) {
292 throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
293 }
294 return false;
295 }
296
297 // Step 3h and 3i
298 final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable();
331 final ScriptObject newDesc = Global.newEmptyInstance();
332 newDesc.set(WRITABLE, false, 0);
333 return super.defineOwnProperty("length", newDesc, false);
334 }
335
336 return true;
337 }
338
339 /**
340 * ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw )
341 */
342 @Override
343 public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
344 final PropertyDescriptor desc = toPropertyDescriptor(Global.instance(), propertyDesc);
345
346 // never be undefined as "length" is always defined and can't be deleted for arrays
347 // Step 1
348 final PropertyDescriptor oldLenDesc = (PropertyDescriptor) super.getOwnPropertyDescriptor("length");
349
350 // Step 2
351 // get old length and convert to long
352 final long oldLen = NativeArray.validLength(oldLenDesc.getValue(), true);
353
354 // Step 3
355 if ("length".equals(key)) {
356 // check for length being made non-writable
357 final boolean result = defineLength(oldLen, oldLenDesc, desc, reject);
358 if (desc.has(WRITABLE) && !desc.isWritable()) {
359 setIsLengthNotWritable();
360 }
361 return result;
362 }
363
364 // Step 4a
365 final int index = ArrayIndex.getArrayIndex(key);
366 if (ArrayIndex.isValidArrayIndex(index)) {
367 final long longIndex = ArrayIndex.toLongIndex(index);
368 // Step 4b
369 // setting an element beyond current length, but 'length' is not writable
370 if (longIndex >= oldLen && !oldLenDesc.isWritable()) {
371 if (reject) {
372 throw typeError("property.not.writable", Long.toString(longIndex), ScriptRuntime.safeToString(this));
454 * @param self self reference
455 * @return the length of the object
456 */
457 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
458 public static Object length(final Object self) {
459 if (isArray(self)) {
460 return JSType.toUint32(((ScriptObject) self).getArray().length());
461 }
462
463 return 0;
464 }
465
466 /**
467 * Length setter
468 * @param self self reference
469 * @param length new length property
470 */
471 @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
472 public static void length(final Object self, final Object length) {
473 if (isArray(self)) {
474 ((ScriptObject)self).setLength(validLength(length, true));
475 }
476 }
477
478 /**
479 * Prototype length getter
480 * @param self self reference
481 * @return the length of the object
482 */
483 @Getter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
484 public static Object getProtoLength(final Object self) {
485 return length(self); // Same as instance getter but we can't make nasgen use the same method for prototype
486 }
487
488 /**
489 * Prototype length setter
490 * @param self self reference
491 * @param length new length property
492 */
493 @Setter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
494 public static void setProtoLength(final Object self, final Object length) {
495 length(self, length); // Same as instance setter but we can't make nasgen use the same method for prototype
496 }
497
498 static long validLength(final Object length, final boolean reject) {
499 final double doubleLength = JSType.toNumber(length);
500 if (!Double.isNaN(doubleLength) && JSType.isRepresentableAsLong(doubleLength)) {
501 final long len = (long) doubleLength;
502 if (len >= 0 && len <= JSType.MAX_UINT) {
503 return len;
504 }
505 }
506 if (reject) {
507 throw rangeError("inappropriate.array.length", ScriptRuntime.safeToString(length));
508 }
509 return -1;
510 }
511
512 /**
513 * ECMA 15.4.4.2 Array.prototype.toString ( )
514 *
515 * @param self self reference
516 * @return string representation of array
517 */
518 @Function(attributes = Attribute.NOT_ENUMERABLE)
519 public static Object toString(final Object self) {
520 final Object obj = Global.toObject(self);
521 if (obj instanceof ScriptObject) {
522 final InvokeByName joinInvoker = getJOIN();
523 final ScriptObject sobj = (ScriptObject)obj;
524 try {
525 final Object join = joinInvoker.getGetter().invokeExact(sobj);
526 if (Bootstrap.isCallable(join)) {
527 return joinInvoker.getInvoker().invokeExact(join, sobj);
528 }
529 } catch (final RuntimeException | Error e) {
|
258
259 @Override
260 public Object getLength() {
261 final long length = JSType.toUint32(getArray().length());
262 if (length < Integer.MAX_VALUE) {
263 return (int)length;
264 }
265 return length;
266 }
267
268 private boolean defineLength(final long oldLen, final PropertyDescriptor oldLenDesc, final PropertyDescriptor desc, final boolean reject) {
269 // Step 3a
270 if (!desc.has(VALUE)) {
271 return super.defineOwnProperty("length", desc, reject);
272 }
273
274 // Step 3b
275 final PropertyDescriptor newLenDesc = desc;
276
277 // Step 3c and 3d - get new length and convert to long
278 final long newLen = NativeArray.validLength(newLenDesc.getValue());
279
280 // Step 3e
281 newLenDesc.setValue(newLen);
282
283 // Step 3f
284 // increasing array length - just need to set new length value (and attributes if any) and return
285 if (newLen >= oldLen) {
286 return super.defineOwnProperty("length", newLenDesc, reject);
287 }
288
289 // Step 3g
290 if (!oldLenDesc.isWritable()) {
291 if (reject) {
292 throw typeError("property.not.writable", "length", ScriptRuntime.safeToString(this));
293 }
294 return false;
295 }
296
297 // Step 3h and 3i
298 final boolean newWritable = !newLenDesc.has(WRITABLE) || newLenDesc.isWritable();
331 final ScriptObject newDesc = Global.newEmptyInstance();
332 newDesc.set(WRITABLE, false, 0);
333 return super.defineOwnProperty("length", newDesc, false);
334 }
335
336 return true;
337 }
338
339 /**
340 * ECMA 15.4.5.1 [[DefineOwnProperty]] ( P, Desc, Throw )
341 */
342 @Override
343 public boolean defineOwnProperty(final String key, final Object propertyDesc, final boolean reject) {
344 final PropertyDescriptor desc = toPropertyDescriptor(Global.instance(), propertyDesc);
345
346 // never be undefined as "length" is always defined and can't be deleted for arrays
347 // Step 1
348 final PropertyDescriptor oldLenDesc = (PropertyDescriptor) super.getOwnPropertyDescriptor("length");
349
350 // Step 2
351 // get old length and convert to long. Always a Long/Uint32 but we take the safe road.
352 final long oldLen = JSType.toUint32(oldLenDesc.getValue());
353
354 // Step 3
355 if ("length".equals(key)) {
356 // check for length being made non-writable
357 final boolean result = defineLength(oldLen, oldLenDesc, desc, reject);
358 if (desc.has(WRITABLE) && !desc.isWritable()) {
359 setIsLengthNotWritable();
360 }
361 return result;
362 }
363
364 // Step 4a
365 final int index = ArrayIndex.getArrayIndex(key);
366 if (ArrayIndex.isValidArrayIndex(index)) {
367 final long longIndex = ArrayIndex.toLongIndex(index);
368 // Step 4b
369 // setting an element beyond current length, but 'length' is not writable
370 if (longIndex >= oldLen && !oldLenDesc.isWritable()) {
371 if (reject) {
372 throw typeError("property.not.writable", Long.toString(longIndex), ScriptRuntime.safeToString(this));
454 * @param self self reference
455 * @return the length of the object
456 */
457 @Getter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
458 public static Object length(final Object self) {
459 if (isArray(self)) {
460 return JSType.toUint32(((ScriptObject) self).getArray().length());
461 }
462
463 return 0;
464 }
465
466 /**
467 * Length setter
468 * @param self self reference
469 * @param length new length property
470 */
471 @Setter(attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
472 public static void length(final Object self, final Object length) {
473 if (isArray(self)) {
474 ((ScriptObject)self).setLength(validLength(length));
475 }
476 }
477
478 /**
479 * Prototype length getter
480 * @param self self reference
481 * @return the length of the object
482 */
483 @Getter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
484 public static Object getProtoLength(final Object self) {
485 return length(self); // Same as instance getter but we can't make nasgen use the same method for prototype
486 }
487
488 /**
489 * Prototype length setter
490 * @param self self reference
491 * @param length new length property
492 */
493 @Setter(name = "length", where = Where.PROTOTYPE, attributes = Attribute.NOT_ENUMERABLE | Attribute.NOT_CONFIGURABLE)
494 public static void setProtoLength(final Object self, final Object length) {
495 length(self, length); // Same as instance setter but we can't make nasgen use the same method for prototype
496 }
497
498 static long validLength(final Object length) {
499 // ES5 15.4.5.1, steps 3.c and 3.d require two ToNumber conversions here
500 final double doubleLength = JSType.toNumber(length);
501 if (doubleLength != JSType.toUint32(length)) {
502 throw rangeError("inappropriate.array.length", ScriptRuntime.safeToString(length));
503 }
504 return (long) doubleLength;
505 }
506
507 /**
508 * ECMA 15.4.4.2 Array.prototype.toString ( )
509 *
510 * @param self self reference
511 * @return string representation of array
512 */
513 @Function(attributes = Attribute.NOT_ENUMERABLE)
514 public static Object toString(final Object self) {
515 final Object obj = Global.toObject(self);
516 if (obj instanceof ScriptObject) {
517 final InvokeByName joinInvoker = getJOIN();
518 final ScriptObject sobj = (ScriptObject)obj;
519 try {
520 final Object join = joinInvoker.getGetter().invokeExact(sobj);
521 if (Bootstrap.isCallable(join)) {
522 return joinInvoker.getInvoker().invokeExact(join, sobj);
523 }
524 } catch (final RuntimeException | Error e) {
|