Index: src/v8natives.js |
diff --git a/src/v8natives.js b/src/v8natives.js |
index dee3032378302955eead197498780304a5ff3195..de80067866b3e95d878b9452d7e0eb8fd9ac202c 100644 |
--- a/src/v8natives.js |
+++ b/src/v8natives.js |
@@ -1517,53 +1517,51 @@ function FunctionToString() { |
// ES5 15.3.4.5 |
function FunctionBind(this_arg) { // Length is 1. |
if (!IS_SPEC_FUNCTION(this)) { |
- throw new $TypeError('Bind must be called on a function'); |
- } |
- // this_arg is not an argument that should be bound. |
- var argc_bound = (%_ArgumentsLength() || 1) - 1; |
- var fn = this; |
- |
- if (argc_bound == 0) { |
- var result = function() { |
- if (%_IsConstructCall()) { |
- // %NewObjectFromBound implicitly uses arguments passed to this |
- // function. We do not pass the arguments object explicitly to avoid |
- // materializing it and guarantee that this function will be optimized. |
- return %NewObjectFromBound(fn, null); |
- } |
- return %Apply(fn, this_arg, arguments, 0, %_ArgumentsLength()); |
- }; |
- } else { |
- var bound_args = new InternalArray(argc_bound); |
- for(var i = 0; i < argc_bound; i++) { |
- bound_args[i] = %_Arguments(i+1); |
+ throw new $TypeError('Bind must be called on a function'); |
+ } |
+ var boundFunction = function () { |
+ // This function must not use any object literals (Object, Array, RegExp), |
+ // since the literals-array is being used to store the bound data. |
+ if (%_IsConstructCall()) { |
+ return %NewObjectFromBound(boundFunction); |
} |
+ var bindings = %BoundFunctionGetBindings(boundFunction); |
- var result = function() { |
- // If this is a construct call we use a special runtime method |
- // to generate the actual object using the bound function. |
- if (%_IsConstructCall()) { |
- // %NewObjectFromBound implicitly uses arguments passed to this |
- // function. We do not pass the arguments object explicitly to avoid |
- // materializing it and guarantee that this function will be optimized. |
- return %NewObjectFromBound(fn, bound_args); |
- } |
- |
- // Combine the args we got from the bind call with the args |
- // given as argument to the invocation. |
+ var argc = %_ArgumentsLength(); |
+ if (argc == 0) { |
+ return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2); |
+ } |
+ if (bindings.length === 2) { |
+ return %Apply(bindings[0], bindings[1], arguments, 0, argc); |
+ } |
+ var bound_argc = bindings.length - 2; |
+ var argv = new InternalArray(bound_argc + argc); |
+ for (var i = 0; i < bound_argc; i++) { |
+ argv[i] = bindings[i + 2]; |
+ } |
+ for (var j = 0; j < argc; j++) { |
+ argv[i++] = %_Arguments(j); |
+ } |
+ return %Apply(bindings[0], bindings[1], argv, 0, bound_argc + argc); |
+ }; |
+ |
+ %FunctionRemovePrototype(boundFunction); |
+ var new_length = 0; |
+ if (%_ClassOf(this) == "Function") { |
+ // Function or FunctionProxy. |
+ var old_length = this.length; |
+ // FunctionProxies might provide a non-UInt32 value. If so, ignore it. |
+ if ((typeof old_length === "number") && |
+ ((old_length >>> 0) === old_length)) { |
var argc = %_ArgumentsLength(); |
- var args = new InternalArray(argc + argc_bound); |
- // Add bound arguments. |
- for (var i = 0; i < argc_bound; i++) { |
- args[i] = bound_args[i]; |
- } |
- // Add arguments from call. |
- for (var i = 0; i < argc; i++) { |
- args[argc_bound + i] = %_Arguments(i); |
- } |
- return %Apply(fn, this_arg, args, 0, argc + argc_bound); |
- }; |
+ if (argc > 0) argc--; // Don't count the thisArg as parameter. |
+ new_length = old_length - argc; |
+ if (new_length < 0) new_length = 0; |
+ } |
} |
+ // This runtime function finds any remaining arguments on the stack, |
+ // so we don't pass the arguments object. |
+ var result = %FunctionBindArguments(boundFunction, this, this_arg, new_length); |
// We already have caller and arguments properties on functions, |
// which are non-configurable. It therefore makes no sence to |
@@ -1571,17 +1569,7 @@ function FunctionBind(this_arg) { // Length is 1. |
// that bind should make these throw a TypeError if get or set |
// is called and make them non-enumerable and non-configurable. |
// To be consistent with our normal functions we leave this as it is. |
- |
- %FunctionRemovePrototype(result); |
- %FunctionSetBound(result); |
- // Set the correct length. If this is a function proxy, this.length might |
- // throw, or return a bogus result. Leave length alone in that case. |
- // TODO(rossberg): This is underspecified in the current proxy proposal. |
- try { |
- var old_length = ToInteger(this.length); |
- var length = (old_length - argc_bound) > 0 ? old_length - argc_bound : 0; |
- %BoundFunctionSetLength(result, length); |
- } catch(x) {} |
+ // TODO(lrn): Do set these to be thrower. |
return result; |
} |