Roll V8 back to 3.6
Roll back to V8 3.6 to fix x86 build, we don't have ucontext.h.
This reverts commits:
5d4cdbf7a67d3662fa0bee4efdb7edd8daec9b0b
c7cc028aaeedbbfa11c11d0b7b243b3d9e837ed9
592a9fc1d8ea420377a2e7efd0600e20b058be2b
Bug: 5688872
Change-Id: Ic961bb5e65b778e98bbfb71cce71d99fa949e995
diff --git a/src/v8natives.js b/src/v8natives.js
index f1e8084..588bdb2 100644
--- a/src/v8natives.js
+++ b/src/v8natives.js
@@ -1,4 +1,4 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
+// Copyright 2011 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
@@ -28,18 +28,18 @@
// This file relies on the fact that the following declarations have been made
//
// in runtime.js:
-// var $Object = global.Object;
-// var $Boolean = global.Boolean;
-// var $Number = global.Number;
-// var $Function = global.Function;
-// var $Array = global.Array;
-// var $NaN = 0/0;
+// const $Object = global.Object;
+// const $Boolean = global.Boolean;
+// const $Number = global.Number;
+// const $Function = global.Function;
+// const $Array = global.Array;
+// const $NaN = 0/0;
//
// in math.js:
-// var $floor = MathFloor
+// const $floor = MathFloor
-var $isNaN = GlobalIsNaN;
-var $isFinite = GlobalIsFinite;
+const $isNaN = GlobalIsNaN;
+const $isFinite = GlobalIsFinite;
// ----------------------------------------------------------------------------
@@ -60,6 +60,18 @@
%ToFastProperties(object);
}
+// Emulates JSC by installing functions on a hidden prototype that
+// lies above the current object/prototype. This lets you override
+// functions on String.prototype etc. and then restore the old function
+// with delete. See http://code.google.com/p/chromium/issues/detail?id=1717
+function InstallFunctionsOnHiddenPrototype(object, attributes, functions) {
+ %CheckIsBootstrapping();
+ var hidden_prototype = new $Object();
+ %SetHiddenPrototype(object, hidden_prototype);
+ InstallFunctions(hidden_prototype, attributes, functions);
+}
+
+
// Prevents changes to the prototype of a built-infunction.
// The "prototype" property of the function object is made non-configurable,
// and the prototype object is made non-extensible. The latter prevents
@@ -127,9 +139,8 @@
// The spec says ToString should be evaluated before ToInt32.
string = TO_STRING_INLINE(string);
radix = TO_INT32(radix);
- if (!(radix == 0 || (2 <= radix && radix <= 36))) {
+ if (!(radix == 0 || (2 <= radix && radix <= 36)))
return $NaN;
- }
}
if (%_HasCachedArrayIndex(string) &&
@@ -151,23 +162,28 @@
function GlobalEval(x) {
if (!IS_STRING(x)) return x;
+ var receiver = this;
var global_receiver = %GlobalReceiver(global);
+
+ if (receiver == null && !IS_UNDETECTABLE(receiver)) {
+ receiver = global_receiver;
+ }
+
+ var this_is_global_receiver = (receiver === global_receiver);
var global_is_detached = (global === global_receiver);
// For consistency with JSC we require the global object passed to
// eval to be the global object from which 'eval' originated. This
// is not mandated by the spec.
- // We only throw if the global has been detached, since we need the
- // receiver as this-value for the call.
- if (global_is_detached) {
- throw new $EvalError('The "this" value passed to eval must ' +
+ if (!this_is_global_receiver || global_is_detached) {
+ throw new $EvalError('The "this" object passed to eval must ' +
'be the global object from which eval originated');
}
var f = %CompileString(x);
if (!IS_FUNCTION(f)) return f;
- return %_CallFunction(global_receiver, f);
+ return %_CallFunction(receiver, f);
}
@@ -177,14 +193,13 @@
function SetUpGlobal() {
%CheckIsBootstrapping();
// ECMA 262 - 15.1.1.1.
- %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetProperty(global, "NaN", $NaN, DONT_ENUM | DONT_DELETE);
// ECMA-262 - 15.1.1.2.
- %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetProperty(global, "Infinity", 1/0, DONT_ENUM | DONT_DELETE);
// ECMA-262 - 15.1.1.3.
- %SetProperty(global, "undefined", void 0,
- DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetProperty(global, "undefined", void 0, DONT_ENUM | DONT_DELETE);
// Set up non-enumerable function on the global object.
InstallFunctions(global, DONT_ENUM, $Array(
@@ -284,8 +299,7 @@
receiver = %GlobalReceiver(global);
}
if (!IS_SPEC_FUNCTION(fun)) {
- throw new $TypeError(
- 'Object.prototype.__defineGetter__: Expecting function');
+ throw new $TypeError('Object.prototype.__defineGetter__: Expecting function');
}
var desc = new PropertyDescriptor();
desc.setGet(fun);
@@ -331,9 +345,8 @@
function ObjectKeys(obj) {
- if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.keys"]);
- }
+ if (!IS_SPEC_OBJECT(obj))
+ throw MakeTypeError("obj_ctor_property_non_object", ["keys"]);
if (%IsJSProxy(obj)) {
var handler = %GetHandler(obj);
var names = CallTrap0(handler, "keys", DerivedKeysTrap);
@@ -359,7 +372,6 @@
// ES5 8.10.3.
function IsGenericDescriptor(desc) {
- if (IS_UNDEFINED(desc)) return false;
return !(IsAccessorDescriptor(desc) || IsDataDescriptor(desc));
}
@@ -464,7 +476,7 @@
// For Harmony proxies.
function ToCompletePropertyDescriptor(obj) {
- var desc = ToPropertyDescriptor(obj);
+ var desc = ToPropertyDescriptor(obj)
if (IsGenericDescriptor(desc) || IsDataDescriptor(desc)) {
if (!desc.hasValue()) desc.setValue(void 0);
if (!desc.hasWritable()) desc.setWritable(false);
@@ -660,21 +672,6 @@
}
-// ES5 section 8.12.7.
-function Delete(obj, p, should_throw) {
- var desc = GetOwnProperty(obj, p);
- if (IS_UNDEFINED(desc)) return true;
- if (desc.isConfigurable()) {
- %DeleteProperty(obj, p, 0);
- return true;
- } else if (should_throw) {
- throw MakeTypeError("define_disallowed", [p]);
- } else {
- return;
- }
-}
-
-
// Harmony proxies.
function DefineProxyProperty(obj, p, attributes, should_throw) {
var handler = %GetHandler(obj);
@@ -692,7 +689,12 @@
// ES5 8.12.9.
-function DefineObjectProperty(obj, p, desc, should_throw) {
+function DefineOwnProperty(obj, p, desc, should_throw) {
+ if (%IsJSProxy(obj)) {
+ var attributes = FromGenericPropertyDescriptor(desc);
+ return DefineProxyProperty(obj, p, attributes, should_throw);
+ }
+
var current_or_access = %GetOwnProperty(ToObject(obj), ToString(p));
// A false value here means that access checks failed.
if (current_or_access === false) return void 0;
@@ -706,7 +708,7 @@
if (should_throw) {
throw MakeTypeError("define_disallowed", [p]);
} else {
- return false;
+ return;
}
}
@@ -736,7 +738,7 @@
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return false;
+ return;
}
}
// Step 8
@@ -746,7 +748,7 @@
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return false;
+ return;
}
}
// Step 10a
@@ -755,7 +757,7 @@
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return false;
+ return;
}
}
if (!current.isWritable() && desc.hasValue() &&
@@ -763,7 +765,7 @@
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return false;
+ return;
}
}
}
@@ -773,14 +775,14 @@
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return false;
+ return;
}
}
if (desc.hasGetter() && !SameValue(desc.getGet(),current.getGet())) {
if (should_throw) {
throw MakeTypeError("redefine_disallowed", [p]);
} else {
- return false;
+ return;
}
}
}
@@ -834,6 +836,10 @@
}
%DefineOrRedefineDataProperty(obj, p, value, flag);
+ } else if (IsGenericDescriptor(desc)) {
+ // Step 12 - updating an existing accessor property with generic
+ // descriptor. Changing flags only.
+ %DefineOrRedefineAccessorProperty(obj, p, GETTER, current.getGet(), flag);
} else {
// There are 3 cases that lead here:
// Step 4b - defining a new accessor property.
@@ -841,113 +847,30 @@
// property.
// Step 12 - updating an existing accessor property with an accessor
// descriptor.
- var getter = desc.hasGetter() ? desc.getGet() : null;
- var setter = desc.hasSetter() ? desc.getSet() : null;
- %DefineOrRedefineAccessorProperty(obj, p, getter, setter, flag);
+ if (desc.hasGetter()) {
+ %DefineOrRedefineAccessorProperty(obj, p, GETTER, desc.getGet(), flag);
+ }
+ if (desc.hasSetter()) {
+ %DefineOrRedefineAccessorProperty(obj, p, SETTER, desc.getSet(), flag);
+ }
}
return true;
}
-// ES5 section 15.4.5.1.
-function DefineArrayProperty(obj, p, desc, should_throw) {
- // Note that the length of an array is not actually stored as part of the
- // property, hence we use generated code throughout this function instead of
- // DefineObjectProperty() to modify its value.
-
- // Step 3 - Special handling for length property.
- if (p == "length") {
- var length = obj.length;
- if (!desc.hasValue()) {
- return DefineObjectProperty(obj, "length", desc, should_throw);
- }
- var new_length = ToUint32(desc.getValue());
- if (new_length != ToNumber(desc.getValue())) {
- throw new $RangeError('defineProperty() array length out of range');
- }
- var length_desc = GetOwnProperty(obj, "length");
- if (new_length != length && !length_desc.isWritable()) {
- if (should_throw) {
- throw MakeTypeError("redefine_disallowed", [p]);
- } else {
- return false;
- }
- }
- var threw = false;
- while (new_length < length--) {
- if (!Delete(obj, ToString(length), false)) {
- new_length = length + 1;
- threw = true;
- break;
- }
- }
- // Make sure the below call to DefineObjectProperty() doesn't overwrite
- // any magic "length" property by removing the value.
- obj.length = new_length;
- desc.value_ = void 0;
- desc.hasValue_ = false;
- if (!DefineObjectProperty(obj, "length", desc, should_throw) || threw) {
- if (should_throw) {
- throw MakeTypeError("redefine_disallowed", [p]);
- } else {
- return false;
- }
- }
- return true;
- }
-
- // Step 4 - Special handling for array index.
- var index = ToUint32(p);
- if (index == ToNumber(p) && index != 4294967295) {
- var length = obj.length;
- var length_desc = GetOwnProperty(obj, "length");
- if ((index >= length && !length_desc.isWritable()) ||
- !DefineObjectProperty(obj, p, desc, true)) {
- if (should_throw) {
- throw MakeTypeError("define_disallowed", [p]);
- } else {
- return false;
- }
- }
- if (index >= length) {
- obj.length = index + 1;
- }
- return true;
- }
-
- // Step 5 - Fallback to default implementation.
- return DefineObjectProperty(obj, p, desc, should_throw);
-}
-
-
-// ES5 section 8.12.9, ES5 section 15.4.5.1 and Harmony proxies.
-function DefineOwnProperty(obj, p, desc, should_throw) {
- if (%IsJSProxy(obj)) {
- var attributes = FromGenericPropertyDescriptor(desc);
- return DefineProxyProperty(obj, p, attributes, should_throw);
- } else if (IS_ARRAY(obj)) {
- return DefineArrayProperty(obj, p, desc, should_throw);
- } else {
- return DefineObjectProperty(obj, p, desc, should_throw);
- }
-}
-
-
// ES5 section 15.2.3.2.
function ObjectGetPrototypeOf(obj) {
- if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.getPrototypeOf"]);
- }
+ if (!IS_SPEC_OBJECT(obj))
+ throw MakeTypeError("obj_ctor_property_non_object", ["getPrototypeOf"]);
return %GetPrototype(obj);
}
// ES5 section 15.2.3.3
function ObjectGetOwnPropertyDescriptor(obj, p) {
- if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object",
- ["Object.getOwnPropertyDescriptor"]);
- }
+ if (!IS_SPEC_OBJECT(obj))
+ throw MakeTypeError("obj_ctor_property_non_object",
+ ["getOwnPropertyDescriptor"]);
var desc = GetOwnProperty(obj, p);
return FromPropertyDescriptor(desc);
}
@@ -960,14 +883,14 @@
}
var n = ToUint32(obj.length);
var array = new $Array(n);
- var names = {}; // TODO(rossberg): use sets once they are ready.
+ var names = {}
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]);
+ throw MakeTypeError("proxy_repeated_prop_name", [obj, trap, s])
}
array[index] = s;
- names[s] = 0;
+ names.s = 0;
}
return array;
}
@@ -975,9 +898,9 @@
// ES5 section 15.2.3.4.
function ObjectGetOwnPropertyNames(obj) {
- if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.getOwnPropertyNames"]);
- }
+ if (!IS_SPEC_OBJECT(obj))
+ throw MakeTypeError("obj_ctor_property_non_object", ["getOwnPropertyNames"]);
+
// Special handling for proxies.
if (%IsJSProxy(obj)) {
var handler = %GetHandler(obj);
@@ -994,9 +917,8 @@
if (%GetInterceptorInfo(obj) & 1) {
var indexedInterceptorNames =
%GetIndexedInterceptorElementNames(obj);
- if (indexedInterceptorNames) {
+ if (indexedInterceptorNames)
propertyNames = propertyNames.concat(indexedInterceptorNames);
- }
}
// Find all the named properties.
@@ -1022,9 +944,8 @@
// We need to check for the exact property value since for intrinsic
// properties like toString if(propertySet["toString"]) will always
// succeed.
- if (propertySet[name] === true) {
+ if (propertySet[name] === true)
continue;
- }
propertySet[name] = true;
propertyNames[j++] = name;
}
@@ -1049,7 +970,7 @@
// ES5 section 15.2.3.6.
function ObjectDefineProperty(obj, p, attributes) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.defineProperty"]);
+ throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]);
}
var name = ToString(p);
if (%IsJSProxy(obj)) {
@@ -1100,17 +1021,14 @@
// ES5 section 15.2.3.7.
function ObjectDefineProperties(obj, properties) {
- if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.defineProperties"]);
- }
+ if (!IS_SPEC_OBJECT(obj))
+ 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++) {
- descriptors.push(ToPropertyDescriptor(props[names[i]]));
- }
- for (var i = 0; i < names.length; i++) {
- DefineOwnProperty(obj, names[i], descriptors[i], true);
+ var name = names[i];
+ var desc = ToPropertyDescriptor(props[name]);
+ DefineOwnProperty(obj, name, desc, true);
}
return obj;
}
@@ -1124,20 +1042,12 @@
throw MakeTypeError("handler_returned_undefined", [handler, "fix"]);
}
- if (%IsJSFunctionProxy(obj)) {
+ if (IS_SPEC_FUNCTION(obj)) {
var callTrap = %GetCallTrap(obj);
var constructTrap = %GetConstructTrap(obj);
var code = DelegateCallAndConstruct(callTrap, constructTrap);
%Fix(obj); // becomes a regular function
%SetCode(obj, code);
- // TODO(rossberg): What about length and other properties? Not specified.
- // We just put in some half-reasonable defaults for now.
- var prototype = new $Object();
- $Object.defineProperty(prototype, "constructor",
- {value: obj, writable: true, enumerable: false, configurable: true});
- // TODO(v8:1530): defineProperty does not handle prototype and length.
- %FunctionSetPrototype(obj, prototype);
- obj.length = 0;
} else {
%Fix(obj);
}
@@ -1148,7 +1058,7 @@
// ES5 section 15.2.3.8.
function ObjectSeal(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.seal"]);
+ throw MakeTypeError("obj_ctor_property_non_object", ["seal"]);
}
if (%IsJSProxy(obj)) {
ProxyFix(obj);
@@ -1170,7 +1080,7 @@
// ES5 section 15.2.3.9.
function ObjectFreeze(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.freeze"]);
+ throw MakeTypeError("obj_ctor_property_non_object", ["freeze"]);
}
if (%IsJSProxy(obj)) {
ProxyFix(obj);
@@ -1193,7 +1103,7 @@
// ES5 section 15.2.3.10
function ObjectPreventExtension(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.preventExtension"]);
+ throw MakeTypeError("obj_ctor_property_non_object", ["preventExtension"]);
}
if (%IsJSProxy(obj)) {
ProxyFix(obj);
@@ -1206,7 +1116,7 @@
// ES5 section 15.2.3.11
function ObjectIsSealed(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.isSealed"]);
+ throw MakeTypeError("obj_ctor_property_non_object", ["isSealed"]);
}
if (%IsJSProxy(obj)) {
return false;
@@ -1227,7 +1137,7 @@
// ES5 section 15.2.3.12
function ObjectIsFrozen(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.isFrozen"]);
+ throw MakeTypeError("obj_ctor_property_non_object", ["isFrozen"]);
}
if (%IsJSProxy(obj)) {
return false;
@@ -1249,7 +1159,7 @@
// ES5 section 15.2.3.13
function ObjectIsExtensible(obj) {
if (!IS_SPEC_OBJECT(obj)) {
- throw MakeTypeError("called_on_non_object", ["Object.isExtensible"]);
+ throw MakeTypeError("obj_ctor_property_non_object", ["isExtensible"]);
}
if (%IsJSProxy(obj)) {
return true;
@@ -1258,16 +1168,6 @@
}
-// Harmony egal.
-function ObjectIs(obj1, obj2) {
- if (obj1 === obj2) {
- return (obj1 !== 0) || (1 / obj1 === 1 / obj2);
- } else {
- return (obj1 !== obj1) && (obj2 !== obj2);
- }
-}
-
-
%SetCode($Object, function(x) {
if (%_IsConstructCall()) {
if (x == null) return this;
@@ -1307,7 +1207,6 @@
"getPrototypeOf", ObjectGetPrototypeOf,
"getOwnPropertyDescriptor", ObjectGetOwnPropertyDescriptor,
"getOwnPropertyNames", ObjectGetOwnPropertyNames,
- "is", ObjectIs,
"isExtensible", ObjectIsExtensible,
"isFrozen", ObjectIsFrozen,
"isSealed", ObjectIsSealed,
@@ -1338,9 +1237,8 @@
function BooleanValueOf() {
// NOTE: Both Boolean objects and values can enter here as
// 'this'. This is not as dictated by ECMA-262.
- if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this)) {
+ if (!IS_BOOLEAN(this) && !IS_BOOLEAN_WRAPPER(this))
throw new $TypeError('Boolean.prototype.valueOf is not generic');
- }
return %_ValueOf(this);
}
@@ -1380,9 +1278,8 @@
// 'this'. This is not as dictated by ECMA-262.
var number = this;
if (!IS_NUMBER(this)) {
- if (!IS_NUMBER_WRAPPER(this)) {
+ if (!IS_NUMBER_WRAPPER(this))
throw new $TypeError('Number.prototype.toString is not generic');
- }
// Get the value of this number in case it's an object.
number = %_ValueOf(this);
}
@@ -1415,9 +1312,8 @@
function NumberValueOf() {
// NOTE: Both Number objects and values can enter here as
// 'this'. This is not as dictated by ECMA-262.
- if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this)) {
+ if (!IS_NUMBER(this) && !IS_NUMBER_WRAPPER(this))
throw new $TypeError('Number.prototype.valueOf is not generic');
- }
return %_ValueOf(this);
}
@@ -1443,8 +1339,7 @@
if (!IS_UNDEFINED(fractionDigits)) {
f = TO_INTEGER(fractionDigits);
if (f < 0 || f > 20) {
- throw new $RangeError(
- "toExponential() argument must be between 0 and 20");
+ throw new $RangeError("toExponential() argument must be between 0 and 20");
}
}
if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
@@ -1472,18 +1367,6 @@
}
-// Harmony isFinite.
-function NumberIsFinite(number) {
- return IS_NUMBER(number) && NUMBER_IS_FINITE(number);
-}
-
-
-// Harmony isNaN.
-function NumberIsNaN(number) {
- return IS_NUMBER(number) && NUMBER_IS_NAN(number);
-}
-
-
// ----------------------------------------------------------------------------
function SetUpNumber() {
@@ -1500,8 +1383,7 @@
DONT_ENUM | DONT_DELETE | READ_ONLY);
// ECMA-262 section 15.7.3.2.
- %SetProperty($Number, "MIN_VALUE", 5e-324,
- DONT_ENUM | DONT_DELETE | READ_ONLY);
+ %SetProperty($Number, "MIN_VALUE", 5e-324, DONT_ENUM | DONT_DELETE | READ_ONLY);
// ECMA-262 section 15.7.3.3.
%SetProperty($Number, "NaN", $NaN, DONT_ENUM | DONT_DELETE | READ_ONLY);
@@ -1528,10 +1410,6 @@
"toExponential", NumberToExponential,
"toPrecision", NumberToPrecision
));
- InstallFunctions($Number, DONT_ENUM, $Array(
- "isFinite", NumberIsFinite,
- "isNaN", NumberIsNaN
- ));
}
SetUpNumber();
@@ -1577,54 +1455,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');
}
- 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);
+ // this_arg is not an argument that should be bound.
+ var argc_bound = (%_ArgumentsLength() || 1) - 1;
+ var fn = this;
- var argc = %_ArgumentsLength();
- if (argc == 0) {
- return %Apply(bindings[0], bindings[1], bindings, 2, bindings.length - 2);
+ 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);
}
- 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 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) argc--; // Don't count the thisArg as parameter.
- new_length = old_length - argc;
- if (new_length < 0) new_length = 0;
- }
+ 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);
+ };
}
- // 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
@@ -1632,7 +1509,17 @@
// 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.
- // TODO(lrn): Do set these to be thrower.
+
+ %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) {}
return result;
}