Index: src/v8natives.js |
=================================================================== |
--- src/v8natives.js (revision 9808) |
+++ src/v8natives.js (working copy) |
@@ -373,6 +373,7 @@ |
// ES5 8.10.3. |
function IsGenericDescriptor(desc) { |
+ if (IS_UNDEFINED(desc)) return false; |
return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc)); |
} |
@@ -704,7 +705,7 @@ |
if (should_throw) { |
throw MakeTypeError("define_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
@@ -734,7 +735,7 @@ |
if (should_throw) { |
throw MakeTypeError("redefine_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
// Step 8 |
@@ -744,7 +745,7 @@ |
if (should_throw) { |
throw MakeTypeError("redefine_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
// Step 10a |
@@ -753,7 +754,7 @@ |
if (should_throw) { |
throw MakeTypeError("redefine_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
if (!current.isWritable() && desc.hasValue() && |
@@ -761,7 +762,7 @@ |
if (should_throw) { |
throw MakeTypeError("redefine_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
} |
@@ -771,14 +772,14 @@ |
if (should_throw) { |
throw MakeTypeError("redefine_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) { |
if (should_throw) { |
throw MakeTypeError("redefine_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
} |
@@ -881,7 +882,7 @@ |
if (should_throw) { |
throw MakeTypeError("define_disallowed", [p]); |
} else { |
- return; |
+ return false; |
} |
} |
if (index >= length) { |
@@ -936,14 +937,14 @@ |
} |
var n = ToUint32(obj.length); |
var array = new $Array(n); |
- var names = {} |
+ var names = {} // TODO(rossberg): use sets once they are ready. |
for (var index = 0; index < n; index++) { |
var s = ToString(obj[index]); |
if (s in names) { |
throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s]) |
} |
array[index] = s; |
- names.s = 0; |
+ names[s] = 0; |
} |
return array; |
} |
@@ -1078,11 +1079,13 @@ |
throw MakeTypeError("obj_ctor_property_non_object", ["defineProperties"]); |
var props = ToObject(properties); |
var names = GetOwnEnumerablePropertyNames(props); |
+ var descriptors = new InternalArray(); |
for (var i = 0; i < names.length; i++) { |
- var name = names[i]; |
- var desc = ToPropertyDescriptor(props[name]); |
- DefineOwnProperty(obj, name, desc, true); |
+ descriptors.push(ToPropertyDescriptor(props[names[i]])); |
} |
+ for (var i = 0; i < names.length; i++) { |
+ DefineOwnProperty(obj, names[i], descriptors[i], true); |
+ } |
return obj; |
} |
@@ -1517,53 +1520,53 @@ |
// 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'); |
+ 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; |
+ var boundFunction = function () { |
+ // Poison .arguments and .caller, but is otherwise not detectable. |
+ "use strict"; |
+ // 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); |
- 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); |
+ 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); |
+ }; |
- 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. |
+ %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 +1574,7 @@ |
// 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; |
} |