| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 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 355 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 | 366 |
| 367 // ES5 8.10.2. | 367 // ES5 8.10.2. |
| 368 function IsDataDescriptor(desc) { | 368 function IsDataDescriptor(desc) { |
| 369 if (IS_UNDEFINED(desc)) return false; | 369 if (IS_UNDEFINED(desc)) return false; |
| 370 return desc.hasValue() || desc.hasWritable(); | 370 return desc.hasValue() || desc.hasWritable(); |
| 371 } | 371 } |
| 372 | 372 |
| 373 | 373 |
| 374 // ES5 8.10.3. | 374 // ES5 8.10.3. |
| 375 function IsGenericDescriptor(desc) { | 375 function IsGenericDescriptor(desc) { |
| 376 if (IS_UNDEFINED(desc)) return false; |
| 376 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); | 377 return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); |
| 377 } | 378 } |
| 378 | 379 |
| 379 | 380 |
| 380 function IsInconsistentDescriptor(desc) { | 381 function IsInconsistentDescriptor(desc) { |
| 381 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); | 382 return IsAccessorDescriptor(desc) && IsDataDescriptor(desc); |
| 382 } | 383 } |
| 383 | 384 |
| 384 | 385 |
| 385 // ES5 8.10.4 | 386 // ES5 8.10.4 |
| (...skipping 311 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 697 | 698 |
| 698 var current = ConvertDescriptorArrayToDescriptor(current_or_access); | 699 var current = ConvertDescriptorArrayToDescriptor(current_or_access); |
| 699 var extensible = %IsExtensible(ToObject(obj)); | 700 var extensible = %IsExtensible(ToObject(obj)); |
| 700 | 701 |
| 701 // Error handling according to spec. | 702 // Error handling according to spec. |
| 702 // Step 3 | 703 // Step 3 |
| 703 if (IS_UNDEFINED(current) && !extensible) { | 704 if (IS_UNDEFINED(current) && !extensible) { |
| 704 if (should_throw) { | 705 if (should_throw) { |
| 705 throw MakeTypeError("define_disallowed", [p]); | 706 throw MakeTypeError("define_disallowed", [p]); |
| 706 } else { | 707 } else { |
| 707 return; | 708 return false; |
| 708 } | 709 } |
| 709 } | 710 } |
| 710 | 711 |
| 711 if (!IS_UNDEFINED(current)) { | 712 if (!IS_UNDEFINED(current)) { |
| 712 // Step 5 and 6 | 713 // Step 5 and 6 |
| 713 if ((IsGenericDescriptor(desc) || | 714 if ((IsGenericDescriptor(desc) || |
| 714 IsDataDescriptor(desc) == IsDataDescriptor(current)) && | 715 IsDataDescriptor(desc) == IsDataDescriptor(current)) && |
| 715 (!desc.hasEnumerable() || | 716 (!desc.hasEnumerable() || |
| 716 SameValue(desc.isEnumerable(), current.isEnumerable())) && | 717 SameValue(desc.isEnumerable(), current.isEnumerable())) && |
| 717 (!desc.hasConfigurable() || | 718 (!desc.hasConfigurable() || |
| 718 SameValue(desc.isConfigurable(), current.isConfigurable())) && | 719 SameValue(desc.isConfigurable(), current.isConfigurable())) && |
| 719 (!desc.hasWritable() || | 720 (!desc.hasWritable() || |
| 720 SameValue(desc.isWritable(), current.isWritable())) && | 721 SameValue(desc.isWritable(), current.isWritable())) && |
| 721 (!desc.hasValue() || | 722 (!desc.hasValue() || |
| 722 SameValue(desc.getValue(), current.getValue())) && | 723 SameValue(desc.getValue(), current.getValue())) && |
| 723 (!desc.hasGetter() || | 724 (!desc.hasGetter() || |
| 724 SameValue(desc.getGet(), current.getGet())) && | 725 SameValue(desc.getGet(), current.getGet())) && |
| 725 (!desc.hasSetter() || | 726 (!desc.hasSetter() || |
| 726 SameValue(desc.getSet(), current.getSet()))) { | 727 SameValue(desc.getSet(), current.getSet()))) { |
| 727 return true; | 728 return true; |
| 728 } | 729 } |
| 729 if (!current.isConfigurable()) { | 730 if (!current.isConfigurable()) { |
| 730 // Step 7 | 731 // Step 7 |
| 731 if (desc.isConfigurable() || | 732 if (desc.isConfigurable() || |
| 732 (desc.hasEnumerable() && | 733 (desc.hasEnumerable() && |
| 733 desc.isEnumerable() != current.isEnumerable())) { | 734 desc.isEnumerable() != current.isEnumerable())) { |
| 734 if (should_throw) { | 735 if (should_throw) { |
| 735 throw MakeTypeError("redefine_disallowed", [p]); | 736 throw MakeTypeError("redefine_disallowed", [p]); |
| 736 } else { | 737 } else { |
| 737 return; | 738 return false; |
| 738 } | 739 } |
| 739 } | 740 } |
| 740 // Step 8 | 741 // Step 8 |
| 741 if (!IsGenericDescriptor(desc)) { | 742 if (!IsGenericDescriptor(desc)) { |
| 742 // Step 9a | 743 // Step 9a |
| 743 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) { | 744 if (IsDataDescriptor(current) != IsDataDescriptor(desc)) { |
| 744 if (should_throw) { | 745 if (should_throw) { |
| 745 throw MakeTypeError("redefine_disallowed", [p]); | 746 throw MakeTypeError("redefine_disallowed", [p]); |
| 746 } else { | 747 } else { |
| 747 return; | 748 return false; |
| 748 } | 749 } |
| 749 } | 750 } |
| 750 // Step 10a | 751 // Step 10a |
| 751 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { | 752 if (IsDataDescriptor(current) && IsDataDescriptor(desc)) { |
| 752 if (!current.isWritable() && desc.isWritable()) { | 753 if (!current.isWritable() && desc.isWritable()) { |
| 753 if (should_throw) { | 754 if (should_throw) { |
| 754 throw MakeTypeError("redefine_disallowed", [p]); | 755 throw MakeTypeError("redefine_disallowed", [p]); |
| 755 } else { | 756 } else { |
| 756 return; | 757 return false; |
| 757 } | 758 } |
| 758 } | 759 } |
| 759 if (!current.isWritable() && desc.hasValue() && | 760 if (!current.isWritable() && desc.hasValue() && |
| 760 !SameValue(desc.getValue(), current.getValue())) { | 761 !SameValue(desc.getValue(), current.getValue())) { |
| 761 if (should_throw) { | 762 if (should_throw) { |
| 762 throw MakeTypeError("redefine_disallowed", [p]); | 763 throw MakeTypeError("redefine_disallowed", [p]); |
| 763 } else { | 764 } else { |
| 764 return; | 765 return false; |
| 765 } | 766 } |
| 766 } | 767 } |
| 767 } | 768 } |
| 768 // Step 11 | 769 // Step 11 |
| 769 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { | 770 if (IsAccessorDescriptor(desc) && IsAccessorDescriptor(current)) { |
| 770 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) { | 771 if (desc.hasSetter() && !SameValue(desc.getSet(), current.getSet())) { |
| 771 if (should_throw) { | 772 if (should_throw) { |
| 772 throw MakeTypeError("redefine_disallowed", [p]); | 773 throw MakeTypeError("redefine_disallowed", [p]); |
| 773 } else { | 774 } else { |
| 774 return; | 775 return false; |
| 775 } | 776 } |
| 776 } | 777 } |
| 777 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) { | 778 if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) { |
| 778 if (should_throw) { | 779 if (should_throw) { |
| 779 throw MakeTypeError("redefine_disallowed", [p]); | 780 throw MakeTypeError("redefine_disallowed", [p]); |
| 780 } else { | 781 } else { |
| 781 return; | 782 return false; |
| 782 } | 783 } |
| 783 } | 784 } |
| 784 } | 785 } |
| 785 } | 786 } |
| 786 } | 787 } |
| 787 } | 788 } |
| 788 | 789 |
| 789 // Send flags - enumerable and configurable are common - writable is | 790 // Send flags - enumerable and configurable are common - writable is |
| 790 // only send to the data descriptor. | 791 // only send to the data descriptor. |
| 791 // Take special care if enumerable and configurable is not defined on | 792 // Take special care if enumerable and configurable is not defined on |
| (...skipping 82 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 874 } | 875 } |
| 875 | 876 |
| 876 // Step 4 - Special handling for array index. | 877 // Step 4 - Special handling for array index. |
| 877 var index = ToUint32(p); | 878 var index = ToUint32(p); |
| 878 if (index == ToNumber(p) && index != 4294967295) { | 879 if (index == ToNumber(p) && index != 4294967295) { |
| 879 if ((index >= length && !length_desc.isWritable()) || | 880 if ((index >= length && !length_desc.isWritable()) || |
| 880 !DefineObjectProperty(obj, p, desc, true)) { | 881 !DefineObjectProperty(obj, p, desc, true)) { |
| 881 if (should_throw) { | 882 if (should_throw) { |
| 882 throw MakeTypeError("define_disallowed", [p]); | 883 throw MakeTypeError("define_disallowed", [p]); |
| 883 } else { | 884 } else { |
| 884 return; | 885 return false; |
| 885 } | 886 } |
| 886 } | 887 } |
| 887 if (index >= length) { | 888 if (index >= length) { |
| 888 // TODO(mstarzinger): We should actually set the value of the property | 889 // TODO(mstarzinger): We should actually set the value of the property |
| 889 // descriptor here and pass it to DefineObjectProperty(). Take a look at | 890 // descriptor here and pass it to DefineObjectProperty(). Take a look at |
| 890 // ES5 section 15.4.5.1, step 4.e.i and 4.e.ii for details. | 891 // ES5 section 15.4.5.1, step 4.e.i and 4.e.ii for details. |
| 891 obj.length = index + 1; | 892 obj.length = index + 1; |
| 892 } | 893 } |
| 893 return true; | 894 return true; |
| 894 } | 895 } |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 929 } | 930 } |
| 930 | 931 |
| 931 | 932 |
| 932 // For Harmony proxies | 933 // For Harmony proxies |
| 933 function ToStringArray(obj, trap) { | 934 function ToStringArray(obj, trap) { |
| 934 if (!IS_SPEC_OBJECT(obj)) { | 935 if (!IS_SPEC_OBJECT(obj)) { |
| 935 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]); | 936 throw MakeTypeError("proxy_non_object_prop_names", [obj, trap]); |
| 936 } | 937 } |
| 937 var n = ToUint32(obj.length); | 938 var n = ToUint32(obj.length); |
| 938 var array = new $Array(n); | 939 var array = new $Array(n); |
| 939 var names = {} | 940 var names = {} // TODO(rossberg): use sets once they are ready. |
| 940 for (var index = 0; index < n; index++) { | 941 for (var index = 0; index < n; index++) { |
| 941 var s = ToString(obj[index]); | 942 var s = ToString(obj[index]); |
| 942 if (s in names) { | 943 if (s in names) { |
| 943 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]) | 944 throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]) |
| 944 } | 945 } |
| 945 array[index] = s; | 946 array[index] = s; |
| 946 names.s = 0; | 947 names[s] = 0; |
| 947 } | 948 } |
| 948 return array; | 949 return array; |
| 949 } | 950 } |
| 950 | 951 |
| 951 | 952 |
| 952 // ES5 section 15.2.3.4. | 953 // ES5 section 15.2.3.4. |
| 953 function ObjectGetOwnPropertyNames(obj) { | 954 function ObjectGetOwnPropertyNames(obj) { |
| 954 if (!IS_SPEC_OBJECT(obj)) | 955 if (!IS_SPEC_OBJECT(obj)) |
| 955 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"])
; | 956 throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"])
; |
| 956 | 957 |
| (...skipping 114 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1071 return names; | 1072 return names; |
| 1072 } | 1073 } |
| 1073 | 1074 |
| 1074 | 1075 |
| 1075 // ES5 section 15.2.3.7. | 1076 // ES5 section 15.2.3.7. |
| 1076 function ObjectDefineProperties(obj, properties) { | 1077 function ObjectDefineProperties(obj, properties) { |
| 1077 if (!IS_SPEC_OBJECT(obj)) | 1078 if (!IS_SPEC_OBJECT(obj)) |
| 1078 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); | 1079 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); |
| 1079 var props = ToObject(properties); | 1080 var props = ToObject(properties); |
| 1080 var names = GetOwnEnumerablePropertyNames(props); | 1081 var names = GetOwnEnumerablePropertyNames(props); |
| 1082 var descriptors = new InternalArray(); |
| 1081 for (var i = 0; i < names.length; i++) { | 1083 for (var i = 0; i < names.length; i++) { |
| 1082 var name = names[i]; | 1084 descriptors.push(ToPropertyDescriptor(props[names[i]])); |
| 1083 var desc = ToPropertyDescriptor(props[name]); | 1085 } |
| 1084 DefineOwnProperty(obj, name, desc, true); | 1086 for (var i = 0; i < names.length; i++) { |
| 1087 DefineOwnProperty(obj, names[i], descriptors[i], true); |
| 1085 } | 1088 } |
| 1086 return obj; | 1089 return obj; |
| 1087 } | 1090 } |
| 1088 | 1091 |
| 1089 | 1092 |
| 1090 // Harmony proxies. | 1093 // Harmony proxies. |
| 1091 function ProxyFix(obj) { | 1094 function ProxyFix(obj) { |
| 1092 var handler = %GetHandler(obj); | 1095 var handler = %GetHandler(obj); |
| 1093 var props = CallTrap0(handler, "fix", void 0); | 1096 var props = CallTrap0(handler, "fix", void 0); |
| 1094 if (IS_UNDEFINED(props)) { | 1097 if (IS_UNDEFINED(props)) { |
| (...skipping 415 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1510 | 1513 |
| 1511 | 1514 |
| 1512 function FunctionToString() { | 1515 function FunctionToString() { |
| 1513 return FunctionSourceString(this); | 1516 return FunctionSourceString(this); |
| 1514 } | 1517 } |
| 1515 | 1518 |
| 1516 | 1519 |
| 1517 // ES5 15.3.4.5 | 1520 // ES5 15.3.4.5 |
| 1518 function FunctionBind(this_arg) { // Length is 1. | 1521 function FunctionBind(this_arg) { // Length is 1. |
| 1519 if (!IS_SPEC_FUNCTION(this)) { | 1522 if (!IS_SPEC_FUNCTION(this)) { |
| 1520 throw new $TypeError('Bind must be called on a function'); | 1523 throw new $TypeError('Bind must be called on a function'); |
| 1521 } | 1524 } |
| 1522 // this_arg is not an argument that should be bound. | 1525 var boundFunction = function () { |
| 1523 var argc_bound = (%_ArgumentsLength() || 1) - 1; | 1526 // Poison .arguments and .caller, but is otherwise not detectable. |
| 1524 var fn = this; | 1527 "use strict"; |
| 1528 // This function must not use any object literals (Object, Array, RegExp), |
| 1529 // since the literals-array is being used to store the bound data. |
| 1530 if (%_IsConstructCall()) { |
| 1531 return %NewObjectFromBound(boundFunction); |
| 1532 } |
| 1533 var bindings = %BoundFunctionGetBindings(boundFunction); |
| 1525 | 1534 |
| 1526 if (argc_bound == 0) { | 1535 var argc = %_ArgumentsLength(); |
| 1527 var result = function() { | 1536 if (argc == 0) { |
| 1528 if (%_IsConstructCall()) { | 1537 return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2); |
| 1529 // %NewObjectFromBound implicitly uses arguments passed to this | |
| 1530 // function. We do not pass the arguments object explicitly to avoid | |
| 1531 // materializing it and guarantee that this function will be optimized. | |
| 1532 return %NewObjectFromBound(fn, null); | |
| 1533 } | |
| 1534 return %Apply(fn, this_arg, arguments, 0, %_ArgumentsLength()); | |
| 1535 }; | |
| 1536 } else { | |
| 1537 var bound_args = new InternalArray(argc_bound); | |
| 1538 for(var i = 0; i < argc_bound; i++) { | |
| 1539 bound_args[i] = %_Arguments(i+1); | |
| 1540 } | 1538 } |
| 1539 if (bindings.length === 2) { |
| 1540 return %Apply(bindings[0], bindings[1], arguments, 0, argc); |
| 1541 } |
| 1542 var bound_argc = bindings.length - 2; |
| 1543 var argv = new InternalArray(bound_argc + argc); |
| 1544 for (var i = 0; i < bound_argc; i++) { |
| 1545 argv[i] = bindings[i + 2]; |
| 1546 } |
| 1547 for (var j = 0; j < argc; j++) { |
| 1548 argv[i++] = %_Arguments(j); |
| 1549 } |
| 1550 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc); |
| 1551 }; |
| 1541 | 1552 |
| 1542 var result = function() { | 1553 %FunctionRemovePrototype(boundFunction); |
| 1543 // If this is a construct call we use a special runtime method | 1554 var new_length = 0; |
| 1544 // to generate the actual object using the bound function. | 1555 if (%_ClassOf(this) == "Function") { |
| 1545 if (%_IsConstructCall()) { | 1556 // Function or FunctionProxy. |
| 1546 // %NewObjectFromBound implicitly uses arguments passed to this | 1557 var old_length = this.length; |
| 1547 // function. We do not pass the arguments object explicitly to avoid | 1558 // FunctionProxies might provide a non-UInt32 value. If so, ignore it. |
| 1548 // materializing it and guarantee that this function will be optimized. | 1559 if ((typeof old_length === "number") && |
| 1549 return %NewObjectFromBound(fn, bound_args); | 1560 ((old_length >>> 0) === old_length)) { |
| 1550 } | |
| 1551 | |
| 1552 // Combine the args we got from the bind call with the args | |
| 1553 // given as argument to the invocation. | |
| 1554 var argc = %_ArgumentsLength(); | 1561 var argc = %_ArgumentsLength(); |
| 1555 var args = new InternalArray(argc + argc_bound); | 1562 if (argc > 0) argc--; // Don't count the thisArg as parameter. |
| 1556 // Add bound arguments. | 1563 new_length = old_length - argc; |
| 1557 for (var i = 0; i < argc_bound; i++) { | 1564 if (new_length < 0) new_length = 0; |
| 1558 args[i] = bound_args[i]; | 1565 } |
| 1559 } | |
| 1560 // Add arguments from call. | |
| 1561 for (var i = 0; i < argc; i++) { | |
| 1562 args[argc_bound + i] = %_Arguments(i); | |
| 1563 } | |
| 1564 return %Apply(fn, this_arg, args, 0, argc + argc_bound); | |
| 1565 }; | |
| 1566 } | 1566 } |
| 1567 // This runtime function finds any remaining arguments on the stack, |
| 1568 // so we don't pass the arguments object. |
| 1569 var result = %FunctionBindArguments(boundFunction, this, this_arg, new_length)
; |
| 1567 | 1570 |
| 1568 // We already have caller and arguments properties on functions, | 1571 // We already have caller and arguments properties on functions, |
| 1569 // which are non-configurable. It therefore makes no sence to | 1572 // which are non-configurable. It therefore makes no sence to |
| 1570 // try to redefine these as defined by the spec. The spec says | 1573 // try to redefine these as defined by the spec. The spec says |
| 1571 // that bind should make these throw a TypeError if get or set | 1574 // that bind should make these throw a TypeError if get or set |
| 1572 // is called and make them non-enumerable and non-configurable. | 1575 // is called and make them non-enumerable and non-configurable. |
| 1573 // To be consistent with our normal functions we leave this as it is. | 1576 // To be consistent with our normal functions we leave this as it is. |
| 1574 | 1577 // TODO(lrn): Do set these to be thrower. |
| 1575 %FunctionRemovePrototype(result); | |
| 1576 %FunctionSetBound(result); | |
| 1577 // Set the correct length. If this is a function proxy, this.length might | |
| 1578 // throw, or return a bogus result. Leave length alone in that case. | |
| 1579 // TODO(rossberg): This is underspecified in the current proxy proposal. | |
| 1580 try { | |
| 1581 var old_length = ToInteger(this.length); | |
| 1582 var length = (old_length - argc_bound) > 0 ? old_length - argc_bound : 0; | |
| 1583 %BoundFunctionSetLength(result, length); | |
| 1584 } catch(x) {} | |
| 1585 return result; | 1578 return result; |
| 1586 } | 1579 } |
| 1587 | 1580 |
| 1588 | 1581 |
| 1589 function NewFunction(arg1) { // length == 1 | 1582 function NewFunction(arg1) { // length == 1 |
| 1590 var n = %_ArgumentsLength(); | 1583 var n = %_ArgumentsLength(); |
| 1591 var p = ''; | 1584 var p = ''; |
| 1592 if (n > 1) { | 1585 if (n > 1) { |
| 1593 p = new InternalArray(n - 1); | 1586 p = new InternalArray(n - 1); |
| 1594 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); | 1587 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 1614 | 1607 |
| 1615 function SetUpFunction() { | 1608 function SetUpFunction() { |
| 1616 %CheckIsBootstrapping(); | 1609 %CheckIsBootstrapping(); |
| 1617 InstallFunctions($Function.prototype, DONT_ENUM, $Array( | 1610 InstallFunctions($Function.prototype, DONT_ENUM, $Array( |
| 1618 "bind", FunctionBind, | 1611 "bind", FunctionBind, |
| 1619 "toString", FunctionToString | 1612 "toString", FunctionToString |
| 1620 )); | 1613 )); |
| 1621 } | 1614 } |
| 1622 | 1615 |
| 1623 SetUpFunction(); | 1616 SetUpFunction(); |
| OLD | NEW |