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 1499 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1510 | 1510 |
1511 | 1511 |
1512 function FunctionToString() { | 1512 function FunctionToString() { |
1513 return FunctionSourceString(this); | 1513 return FunctionSourceString(this); |
1514 } | 1514 } |
1515 | 1515 |
1516 | 1516 |
1517 // ES5 15.3.4.5 | 1517 // ES5 15.3.4.5 |
1518 function FunctionBind(this_arg) { // Length is 1. | 1518 function FunctionBind(this_arg) { // Length is 1. |
1519 if (!IS_SPEC_FUNCTION(this)) { | 1519 if (!IS_SPEC_FUNCTION(this)) { |
1520 throw new $TypeError('Bind must be called on a function'); | 1520 throw new $TypeError('Bind must be called on a function'); |
1521 } | 1521 } |
1522 // this_arg is not an argument that should be bound. | 1522 var boundFunction = function () { |
1523 var argc_bound = (%_ArgumentsLength() || 1) - 1; | 1523 // This function must not use any object literals (Object, Array, RegExp), |
1524 var fn = this; | 1524 // since the literals-array is being used to store the bound data. |
| 1525 if (%_IsConstructCall()) { |
| 1526 return %NewObjectFromBound(boundFunction); |
| 1527 } |
| 1528 var bindings = %BoundFunctionGetBindings(boundFunction); |
1525 | 1529 |
1526 if (argc_bound == 0) { | 1530 var argc = %_ArgumentsLength(); |
1527 var result = function() { | 1531 if (argc == 0) { |
1528 if (%_IsConstructCall()) { | 1532 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 } | 1533 } |
| 1534 if (bindings.length === 2) { |
| 1535 return %Apply(bindings[0], bindings[1], arguments, 0, argc); |
| 1536 } |
| 1537 var bound_argc = bindings.length - 2; |
| 1538 var argv = new InternalArray(bound_argc + argc); |
| 1539 for (var i = 0; i < bound_argc; i++) { |
| 1540 argv[i] = bindings[i + 2]; |
| 1541 } |
| 1542 for (var j = 0; j < argc; j++) { |
| 1543 argv[i++] = %_Arguments(j); |
| 1544 } |
| 1545 return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc); |
| 1546 }; |
1541 | 1547 |
1542 var result = function() { | 1548 %FunctionRemovePrototype(boundFunction); |
1543 // If this is a construct call we use a special runtime method | 1549 var new_length = 0; |
1544 // to generate the actual object using the bound function. | 1550 if (%_ClassOf(this) == "Function") { |
1545 if (%_IsConstructCall()) { | 1551 // Function or FunctionProxy. |
1546 // %NewObjectFromBound implicitly uses arguments passed to this | 1552 var old_length = this.length; |
1547 // function. We do not pass the arguments object explicitly to avoid | 1553 // FunctionProxies might provide a non-UInt32 value. If so, ignore it. |
1548 // materializing it and guarantee that this function will be optimized. | 1554 if ((typeof old_length === "number") && |
1549 return %NewObjectFromBound(fn, bound_args); | 1555 ((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(); | 1556 var argc = %_ArgumentsLength(); |
1555 var args = new InternalArray(argc + argc_bound); | 1557 if (argc > 0) argc--; // Don't count the thisArg as parameter. |
1556 // Add bound arguments. | 1558 new_length = old_length - argc; |
1557 for (var i = 0; i < argc_bound; i++) { | 1559 if (new_length < 0) new_length = 0; |
1558 args[i] = bound_args[i]; | 1560 } |
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 } | 1561 } |
| 1562 // This runtime function finds any remaining arguments on the stack, |
| 1563 // so we don't pass the arguments object. |
| 1564 var result = %FunctionBindArguments(boundFunction, this, this_arg, new_length)
; |
1567 | 1565 |
1568 // We already have caller and arguments properties on functions, | 1566 // We already have caller and arguments properties on functions, |
1569 // which are non-configurable. It therefore makes no sence to | 1567 // which are non-configurable. It therefore makes no sence to |
1570 // try to redefine these as defined by the spec. The spec says | 1568 // 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 | 1569 // that bind should make these throw a TypeError if get or set |
1572 // is called and make them non-enumerable and non-configurable. | 1570 // is called and make them non-enumerable and non-configurable. |
1573 // To be consistent with our normal functions we leave this as it is. | 1571 // To be consistent with our normal functions we leave this as it is. |
1574 | 1572 // 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; | 1573 return result; |
1586 } | 1574 } |
1587 | 1575 |
1588 | 1576 |
1589 function NewFunction(arg1) { // length == 1 | 1577 function NewFunction(arg1) { // length == 1 |
1590 var n = %_ArgumentsLength(); | 1578 var n = %_ArgumentsLength(); |
1591 var p = ''; | 1579 var p = ''; |
1592 if (n > 1) { | 1580 if (n > 1) { |
1593 p = new InternalArray(n - 1); | 1581 p = new InternalArray(n - 1); |
1594 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); | 1582 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); |
(...skipping 19 matching lines...) Expand all Loading... |
1614 | 1602 |
1615 function SetUpFunction() { | 1603 function SetUpFunction() { |
1616 %CheckIsBootstrapping(); | 1604 %CheckIsBootstrapping(); |
1617 InstallFunctions($Function.prototype, DONT_ENUM, $Array( | 1605 InstallFunctions($Function.prototype, DONT_ENUM, $Array( |
1618 "bind", FunctionBind, | 1606 "bind", FunctionBind, |
1619 "toString", FunctionToString | 1607 "toString", FunctionToString |
1620 )); | 1608 )); |
1621 } | 1609 } |
1622 | 1610 |
1623 SetUpFunction(); | 1611 SetUpFunction(); |
OLD | NEW |