OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); | 300 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); |
301 } | 301 } |
302 | 302 |
303 | 303 |
304 function IsInconsistentDescriptor(desc) { | 304 function IsInconsistentDescriptor(desc) { |
305 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); | 305 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); |
306 } | 306 } |
307 | 307 |
308 // ES5 8.10.4 | 308 // ES5 8.10.4 |
309 function FromPropertyDescriptor(desc) { | 309 function FromPropertyDescriptor(desc) { |
310 if(IS_UNDEFINED(desc)) return desc; | 310 if (IS_UNDEFINED(desc)) return desc; |
311 var obj = new $Object(); | 311 var obj = new $Object(); |
312 if (IsDataDescriptor(desc)) { | 312 if (IsDataDescriptor(desc)) { |
313 obj.value = desc.getValue(); | 313 obj.value = desc.getValue(); |
314 obj.writable = desc.isWritable(); | 314 obj.writable = desc.isWritable(); |
315 } | 315 } |
316 if (IsAccessorDescriptor(desc)) { | 316 if (IsAccessorDescriptor(desc)) { |
317 obj.get = desc.getGet(); | 317 obj.get = desc.getGet(); |
318 obj.set = desc.getSet(); | 318 obj.set = desc.getSet(); |
319 } | 319 } |
320 obj.enumerable = desc.isEnumerable(); | 320 obj.enumerable = desc.isEnumerable(); |
321 obj.configurable = desc.isConfigurable(); | 321 obj.configurable = desc.isConfigurable(); |
322 return obj; | 322 return obj; |
323 } | 323 } |
324 | 324 |
325 // ES5 8.10.5. | 325 // ES5 8.10.5. |
326 function ToPropertyDescriptor(obj) { | 326 function ToPropertyDescriptor(obj) { |
327 if (!IS_OBJECT(obj)) { | 327 if (!IS_OBJECT(obj)) { |
328 throw MakeTypeError("property_desc_object", [obj]); | 328 throw MakeTypeError("property_desc_object", [obj]); |
329 } | 329 } |
330 var desc = new PropertyDescriptor(); | 330 var desc = new PropertyDescriptor(); |
331 | 331 |
332 if ("enumerable" in obj) { | 332 if ("enumerable" in obj) { |
333 desc.setEnumerable(ToBoolean(obj.enumerable)); | 333 desc.setEnumerable(ToBoolean(obj.enumerable)); |
334 } | 334 } |
335 | 335 |
336 | |
337 if ("configurable" in obj) { | 336 if ("configurable" in obj) { |
338 desc.setConfigurable(ToBoolean(obj.configurable)); | 337 desc.setConfigurable(ToBoolean(obj.configurable)); |
339 } | 338 } |
340 | 339 |
341 if ("value" in obj) { | 340 if ("value" in obj) { |
342 desc.setValue(obj.value); | 341 desc.setValue(obj.value); |
343 } | 342 } |
344 | 343 |
345 if ("writable" in obj) { | 344 if ("writable" in obj) { |
346 desc.setWritable(ToBoolean(obj.writable)); | 345 desc.setWritable(ToBoolean(obj.writable)); |
(...skipping 23 matching lines...) Expand all Loading... |
370 | 369 |
371 | 370 |
372 function PropertyDescriptor() { | 371 function PropertyDescriptor() { |
373 // Initialize here so they are all in-object and have the same map. | 372 // Initialize here so they are all in-object and have the same map. |
374 // Default values from ES5 8.6.1. | 373 // Default values from ES5 8.6.1. |
375 this.value_ = void 0; | 374 this.value_ = void 0; |
376 this.hasValue_ = false; | 375 this.hasValue_ = false; |
377 this.writable_ = false; | 376 this.writable_ = false; |
378 this.hasWritable_ = false; | 377 this.hasWritable_ = false; |
379 this.enumerable_ = false; | 378 this.enumerable_ = false; |
| 379 this.hasEnumerable_ = false; |
380 this.configurable_ = false; | 380 this.configurable_ = false; |
| 381 this.hasConfigurable_ = false; |
381 this.get_ = void 0; | 382 this.get_ = void 0; |
382 this.hasGetter_ = false; | 383 this.hasGetter_ = false; |
383 this.set_ = void 0; | 384 this.set_ = void 0; |
384 this.hasSetter_ = false; | 385 this.hasSetter_ = false; |
385 } | 386 } |
386 | 387 |
387 | 388 |
388 PropertyDescriptor.prototype.setValue = function(value) { | 389 PropertyDescriptor.prototype.setValue = function(value) { |
389 this.value_ = value; | 390 this.value_ = value; |
390 this.hasValue_ = true; | 391 this.hasValue_ = true; |
391 } | 392 } |
392 | 393 |
393 | 394 |
394 PropertyDescriptor.prototype.getValue = function() { | 395 PropertyDescriptor.prototype.getValue = function() { |
395 return this.value_; | 396 return this.value_; |
396 } | 397 } |
397 | 398 |
398 | 399 |
| 400 PropertyDescriptor.prototype.hasValue = function() { |
| 401 return this.hasValue_; |
| 402 } |
| 403 |
| 404 |
399 PropertyDescriptor.prototype.setEnumerable = function(enumerable) { | 405 PropertyDescriptor.prototype.setEnumerable = function(enumerable) { |
400 this.enumerable_ = enumerable; | 406 this.enumerable_ = enumerable; |
| 407 this.hasEnumerable_ = true; |
401 } | 408 } |
402 | 409 |
403 | 410 |
404 PropertyDescriptor.prototype.isEnumerable = function () { | 411 PropertyDescriptor.prototype.isEnumerable = function () { |
405 return this.enumerable_; | 412 return this.enumerable_; |
406 } | 413 } |
407 | 414 |
408 | 415 |
| 416 PropertyDescriptor.prototype.hasEnumerable = function() { |
| 417 return this.hasEnumerable_; |
| 418 } |
| 419 |
| 420 |
409 PropertyDescriptor.prototype.setWritable = function(writable) { | 421 PropertyDescriptor.prototype.setWritable = function(writable) { |
410 this.writable_ = writable; | 422 this.writable_ = writable; |
411 this.hasWritable_ = true; | 423 this.hasWritable_ = true; |
412 } | 424 } |
413 | 425 |
414 | 426 |
415 PropertyDescriptor.prototype.isWritable = function() { | 427 PropertyDescriptor.prototype.isWritable = function() { |
416 return this.writable_; | 428 return this.writable_; |
417 } | 429 } |
418 | 430 |
419 | 431 |
420 PropertyDescriptor.prototype.setConfigurable = function(configurable) { | 432 PropertyDescriptor.prototype.setConfigurable = function(configurable) { |
421 this.configurable_ = configurable; | 433 this.configurable_ = configurable; |
| 434 this.hasConfigurable_ = true; |
| 435 } |
| 436 |
| 437 |
| 438 PropertyDescriptor.prototype.hasConfigurable = function() { |
| 439 return this.hasConfigurable_; |
422 } | 440 } |
423 | 441 |
424 | 442 |
425 PropertyDescriptor.prototype.isConfigurable = function() { | 443 PropertyDescriptor.prototype.isConfigurable = function() { |
426 return this.configurable_; | 444 return this.configurable_; |
427 } | 445 } |
428 | 446 |
429 | 447 |
430 PropertyDescriptor.prototype.setGet = function(get) { | 448 PropertyDescriptor.prototype.setGet = function(get) { |
431 this.get_ = get; | 449 this.get_ = get; |
432 this.hasGetter_ = true; | 450 this.hasGetter_ = true; |
433 } | 451 } |
434 | 452 |
435 | 453 |
436 PropertyDescriptor.prototype.getGet = function() { | 454 PropertyDescriptor.prototype.getGet = function() { |
437 return this.get_; | 455 return this.get_; |
438 } | 456 } |
439 | 457 |
440 | 458 |
| 459 PropertyDescriptor.prototype.hasGetter = function() { |
| 460 return this.hasGetter_; |
| 461 } |
| 462 |
| 463 |
441 PropertyDescriptor.prototype.setSet = function(set) { | 464 PropertyDescriptor.prototype.setSet = function(set) { |
442 this.set_ = set; | 465 this.set_ = set; |
443 this.hasSetter_ = true; | 466 this.hasSetter_ = true; |
444 } | 467 } |
445 | 468 |
446 | 469 |
447 PropertyDescriptor.prototype.getSet = function() { | 470 PropertyDescriptor.prototype.getSet = function() { |
448 return this.set_; | 471 return this.set_; |
449 } | 472 } |
450 | 473 |
451 | 474 |
| 475 PropertyDescriptor.prototype.hasSetter = function() { |
| 476 return this.hasSetter_; |
| 477 } |
| 478 |
| 479 |
| 480 |
452 // ES5 section 8.12.1. | 481 // ES5 section 8.12.1. |
453 function GetOwnProperty(obj, p) { | 482 function GetOwnProperty(obj, p) { |
454 var desc = new PropertyDescriptor(); | 483 var desc = new PropertyDescriptor(); |
455 | 484 |
456 // An array with: | 485 // An array with: |
457 // obj is a data property [false, value, Writeable, Enumerable, Configurable] | 486 // obj is a data property [false, value, Writeable, Enumerable, Configurable] |
458 // obj is an accessor [true, Get, Set, Enumerable, Configurable] | 487 // obj is an accessor [true, Get, Set, Enumerable, Configurable] |
459 var props = %GetOwnProperty(ToObject(obj), ToString(p)); | 488 var props = %GetOwnProperty(ToObject(obj), ToString(p)); |
460 | 489 |
461 if (IS_UNDEFINED(props)) | 490 if (IS_UNDEFINED(props)) return void 0; |
462 return void 0; | |
463 | 491 |
464 // This is an accessor | 492 // This is an accessor |
465 if (props[0]) { | 493 if (props[0]) { |
466 desc.setGet(props[1]); | 494 desc.setGet(props[1]); |
467 desc.setSet(props[2]); | 495 desc.setSet(props[2]); |
468 } else { | 496 } else { |
469 desc.setValue(props[1]); | 497 desc.setValue(props[1]); |
470 desc.setWritable(props[2]); | 498 desc.setWritable(props[2]); |
471 } | 499 } |
472 desc.setEnumerable(props[3]); | 500 desc.setEnumerable(props[3]); |
473 desc.setConfigurable(props[4]); | 501 desc.setConfigurable(props[4]); |
474 | 502 |
475 return desc; | 503 return desc; |
476 } | 504 } |
477 | 505 |
478 | 506 |
479 // ES5 8.12.9. This version cannot cope with the property p already | 507 // ES5 section 8.12.2. |
480 // being present on obj. | 508 function GetProperty(obj, p) { |
| 509 var prop = GetOwnProperty(obj); |
| 510 if (!IS_UNDEFINED(prop)) return prop; |
| 511 var proto = obj.__proto__; |
| 512 if (IS_NULL(proto)) return void 0; |
| 513 return GetProperty(proto, p); |
| 514 } |
| 515 |
| 516 |
| 517 // ES5 section 8.12.6 |
| 518 function HasProperty(obj, p) { |
| 519 var desc = GetProperty(obj, p); |
| 520 return IS_UNDEFINED(desc) ? false : true; |
| 521 } |
| 522 |
| 523 |
| 524 // ES5 8.12.9. |
481 function DefineOwnProperty(obj, p, desc, should_throw) { | 525 function DefineOwnProperty(obj, p, desc, should_throw) { |
482 var flag = desc.isEnumerable() ? 0 : DONT_ENUM; | 526 var current = GetOwnProperty(obj, p); |
483 if (IsDataDescriptor(desc)) { | 527 var extensible = %IsExtensible(ToObject(obj)); |
484 flag |= desc.isWritable() ? 0 : (DONT_DELETE | READ_ONLY); | 528 |
485 %SetProperty(obj, p, desc.getValue(), flag); | 529 // Error handling according to spec. |
| 530 // Step 3 |
| 531 if (IS_UNDEFINED(current) && !extensible) |
| 532 throw MakeTypeError("define_disallowed", ["defineProperty"]); |
| 533 |
| 534 if (!IS_UNDEFINED(current) && !current.isConfigurable()) { |
| 535 // Step 7 |
| 536 if (desc.isConfigurable() || desc.isEnumerable() != current.isEnumerable()) |
| 537 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); |
| 538 // Step 9 |
| 539 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) |
| 540 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); |
| 541 // Step 10 |
| 542 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { |
| 543 if (!current.isWritable() && desc.isWritable()) |
| 544 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); |
| 545 if (!current.isWritable() && desc.hasValue() && |
| 546 !SameValue(desc.getValue(), current.getValue())) { |
| 547 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); |
| 548 } |
| 549 } |
| 550 // Step 11 |
| 551 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { |
| 552 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())){ |
| 553 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); |
| 554 } |
| 555 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) |
| 556 throw MakeTypeError("redefine_disallowed", ["defineProperty"]); |
| 557 } |
| 558 } |
| 559 |
| 560 // Send flags - enumerable and configurable are common - writable is |
| 561 // only send to the data descriptor. |
| 562 // Take special care if enumerable and configurable is not defined on |
| 563 // desc (we need to preserve the existing values from current). |
| 564 var flag = NONE; |
| 565 if (desc.hasEnumerable()) { |
| 566 flag |= desc.isEnumerable() ? 0 : DONT_ENUM; |
| 567 } else if (!IS_UNDEFINED(current)) { |
| 568 flag |= current.isEnumerable() ? 0 : DONT_ENUM; |
486 } else { | 569 } else { |
487 if (IS_FUNCTION(desc.getGet())) %DefineAccessor(obj, p, GETTER, desc.getGet(
), flag); | 570 flag |= DONT_ENUM; |
488 if (IS_FUNCTION(desc.getSet())) %DefineAccessor(obj, p, SETTER, desc.getSet(
), flag); | 571 } |
| 572 |
| 573 if (desc.hasConfigurable()) { |
| 574 flag |= desc.isConfigurable() ? 0 : DONT_DELETE; |
| 575 } else if (!IS_UNDEFINED(current)) { |
| 576 flag |= current.isConfigurable() ? 0 : DONT_DELETE; |
| 577 } else |
| 578 flag |= DONT_DELETE; |
| 579 |
| 580 if (IsDataDescriptor(desc) || IsGenericDescriptor(desc)) { |
| 581 flag |= desc.isWritable() ? 0 : READ_ONLY; |
| 582 %DefineOrRedefineDataProperty(obj, p, desc.getValue(), flag); |
| 583 } else { |
| 584 if (desc.hasGetter() && IS_FUNCTION(desc.getGet())) { |
| 585 %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag); |
| 586 } |
| 587 if (desc.hasSetter() && IS_FUNCTION(desc.getSet())) { |
| 588 %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag); |
| 589 } |
489 } | 590 } |
490 return true; | 591 return true; |
491 } | 592 } |
492 | 593 |
493 | 594 |
494 // ES5 section 15.2.3.2. | 595 // ES5 section 15.2.3.2. |
495 function ObjectGetPrototypeOf(obj) { | 596 function ObjectGetPrototypeOf(obj) { |
496 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) | 597 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) |
497 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]); | 598 throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]); |
498 return obj.__proto__; | 599 return obj.__proto__; |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
551 if (!IS_OBJECT(proto) && !IS_NULL(proto)) { | 652 if (!IS_OBJECT(proto) && !IS_NULL(proto)) { |
552 throw MakeTypeError("proto_object_or_null", [proto]); | 653 throw MakeTypeError("proto_object_or_null", [proto]); |
553 } | 654 } |
554 var obj = new $Object(); | 655 var obj = new $Object(); |
555 obj.__proto__ = proto; | 656 obj.__proto__ = proto; |
556 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); | 657 if (!IS_UNDEFINED(properties)) ObjectDefineProperties(obj, properties); |
557 return obj; | 658 return obj; |
558 } | 659 } |
559 | 660 |
560 | 661 |
561 // ES5 section 15.2.3.7. This version cannot cope with the properies already | 662 // ES5 section 15.2.3.6. |
562 // being present on obj. Therefore it is not exposed as | 663 function ObjectDefineProperty(obj, p, attributes) { |
563 // Object.defineProperties yet. | 664 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) |
| 665 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]); |
| 666 var name = ToString(p); |
| 667 var desc = ToPropertyDescriptor(attributes); |
| 668 DefineOwnProperty(obj, name, desc, true); |
| 669 return obj; |
| 670 } |
| 671 |
| 672 |
| 673 // ES5 section 15.2.3.7. |
564 function ObjectDefineProperties(obj, properties) { | 674 function ObjectDefineProperties(obj, properties) { |
| 675 if ((!IS_OBJECT(obj) || IS_NULL_OR_UNDEFINED(obj)) && !IS_FUNCTION(obj)) |
| 676 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); |
565 var props = ToObject(properties); | 677 var props = ToObject(properties); |
566 var key_values = []; | 678 var key_values = []; |
567 for (var key in props) { | 679 for (var key in props) { |
568 if (%HasLocalProperty(props, key)) { | 680 if (%HasLocalProperty(props, key)) { |
569 key_values.push(key); | 681 key_values.push(key); |
570 var value = props[key]; | 682 var value = props[key]; |
571 var desc = ToPropertyDescriptor(value); | 683 var desc = ToPropertyDescriptor(value); |
572 key_values.push(desc); | 684 key_values.push(desc); |
573 } | 685 } |
574 } | 686 } |
(...skipping 29 matching lines...) Expand all Loading... |
604 "isPrototypeOf", ObjectIsPrototypeOf, | 716 "isPrototypeOf", ObjectIsPrototypeOf, |
605 "propertyIsEnumerable", ObjectPropertyIsEnumerable, | 717 "propertyIsEnumerable", ObjectPropertyIsEnumerable, |
606 "__defineGetter__", ObjectDefineGetter, | 718 "__defineGetter__", ObjectDefineGetter, |
607 "__lookupGetter__", ObjectLookupGetter, | 719 "__lookupGetter__", ObjectLookupGetter, |
608 "__defineSetter__", ObjectDefineSetter, | 720 "__defineSetter__", ObjectDefineSetter, |
609 "__lookupSetter__", ObjectLookupSetter | 721 "__lookupSetter__", ObjectLookupSetter |
610 )); | 722 )); |
611 InstallFunctions($Object, DONT_ENUM, $Array( | 723 InstallFunctions($Object, DONT_ENUM, $Array( |
612 "keys", ObjectKeys, | 724 "keys", ObjectKeys, |
613 "create", ObjectCreate, | 725 "create", ObjectCreate, |
| 726 "defineProperty", ObjectDefineProperty, |
| 727 "defineProperties", ObjectDefineProperties, |
614 "getPrototypeOf", ObjectGetPrototypeOf, | 728 "getPrototypeOf", ObjectGetPrototypeOf, |
615 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, | 729 "getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor, |
616 "getOwnPropertyNames", ObjectGetOwnPropertyNames | 730 "getOwnPropertyNames", ObjectGetOwnPropertyNames |
617 )); | 731 )); |
618 } | 732 } |
619 | 733 |
620 SetupObject(); | 734 SetupObject(); |
621 | 735 |
622 | 736 |
623 // ---------------------------------------------------------------------------- | 737 // ---------------------------------------------------------------------------- |
(...skipping 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
874 | 988 |
875 // ---------------------------------------------------------------------------- | 989 // ---------------------------------------------------------------------------- |
876 | 990 |
877 function SetupFunction() { | 991 function SetupFunction() { |
878 InstallFunctions($Function.prototype, DONT_ENUM, $Array( | 992 InstallFunctions($Function.prototype, DONT_ENUM, $Array( |
879 "toString", FunctionToString | 993 "toString", FunctionToString |
880 )); | 994 )); |
881 } | 995 } |
882 | 996 |
883 SetupFunction(); | 997 SetupFunction(); |
OLD | NEW |