| 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;
|
| }
|
|
|
|
|