| 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 250 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 261 return %IsPropertyEnumerable(ToObject(this), P); | 261 return %IsPropertyEnumerable(ToObject(this), P); |
| 262 } | 262 } |
| 263 | 263 |
| 264 | 264 |
| 265 // Extensions for providing property getters and setters. | 265 // Extensions for providing property getters and setters. |
| 266 function ObjectDefineGetter(name, fun) { | 266 function ObjectDefineGetter(name, fun) { |
| 267 var receiver = this; | 267 var receiver = this; |
| 268 if (receiver == null && !IS_UNDETECTABLE(receiver)) { | 268 if (receiver == null && !IS_UNDETECTABLE(receiver)) { |
| 269 receiver = %GlobalReceiver(global); | 269 receiver = %GlobalReceiver(global); |
| 270 } | 270 } |
| 271 if (!IS_FUNCTION(fun)) { | 271 if (!IS_SPEC_FUNCTION(fun)) { |
| 272 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function'
); | 272 throw new $TypeError('Object.prototype.__defineGetter__: Expecting function'
); |
| 273 } | 273 } |
| 274 var desc = new PropertyDescriptor(); | 274 var desc = new PropertyDescriptor(); |
| 275 desc.setGet(fun); | 275 desc.setGet(fun); |
| 276 desc.setEnumerable(true); | 276 desc.setEnumerable(true); |
| 277 desc.setConfigurable(true); | 277 desc.setConfigurable(true); |
| 278 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false); | 278 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false); |
| 279 } | 279 } |
| 280 | 280 |
| 281 | 281 |
| 282 function ObjectLookupGetter(name) { | 282 function ObjectLookupGetter(name) { |
| 283 var receiver = this; | 283 var receiver = this; |
| 284 if (receiver == null && !IS_UNDETECTABLE(receiver)) { | 284 if (receiver == null && !IS_UNDETECTABLE(receiver)) { |
| 285 receiver = %GlobalReceiver(global); | 285 receiver = %GlobalReceiver(global); |
| 286 } | 286 } |
| 287 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER); | 287 return %LookupAccessor(ToObject(receiver), ToString(name), GETTER); |
| 288 } | 288 } |
| 289 | 289 |
| 290 | 290 |
| 291 function ObjectDefineSetter(name, fun) { | 291 function ObjectDefineSetter(name, fun) { |
| 292 var receiver = this; | 292 var receiver = this; |
| 293 if (receiver == null && !IS_UNDETECTABLE(receiver)) { | 293 if (receiver == null && !IS_UNDETECTABLE(receiver)) { |
| 294 receiver = %GlobalReceiver(global); | 294 receiver = %GlobalReceiver(global); |
| 295 } | 295 } |
| 296 if (!IS_FUNCTION(fun)) { | 296 if (!IS_SPEC_FUNCTION(fun)) { |
| 297 throw new $TypeError( | 297 throw new $TypeError( |
| 298 'Object.prototype.__defineSetter__: Expecting function'); | 298 'Object.prototype.__defineSetter__: Expecting function'); |
| 299 } | 299 } |
| 300 var desc = new PropertyDescriptor(); | 300 var desc = new PropertyDescriptor(); |
| 301 desc.setSet(fun); | 301 desc.setSet(fun); |
| 302 desc.setEnumerable(true); | 302 desc.setEnumerable(true); |
| 303 desc.setConfigurable(true); | 303 desc.setConfigurable(true); |
| 304 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false); | 304 DefineOwnProperty(ToObject(receiver), ToString(name), desc, false); |
| 305 } | 305 } |
| 306 | 306 |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 399 if ("value" in obj) { | 399 if ("value" in obj) { |
| 400 desc.setValue(obj.value); | 400 desc.setValue(obj.value); |
| 401 } | 401 } |
| 402 | 402 |
| 403 if ("writable" in obj) { | 403 if ("writable" in obj) { |
| 404 desc.setWritable(ToBoolean(obj.writable)); | 404 desc.setWritable(ToBoolean(obj.writable)); |
| 405 } | 405 } |
| 406 | 406 |
| 407 if ("get" in obj) { | 407 if ("get" in obj) { |
| 408 var get = obj.get; | 408 var get = obj.get; |
| 409 if (!IS_UNDEFINED(get) && !IS_FUNCTION(get)) { | 409 if (!IS_UNDEFINED(get) && !IS_SPEC_FUNCTION(get)) { |
| 410 throw MakeTypeError("getter_must_be_callable", [get]); | 410 throw MakeTypeError("getter_must_be_callable", [get]); |
| 411 } | 411 } |
| 412 desc.setGet(get); | 412 desc.setGet(get); |
| 413 } | 413 } |
| 414 | 414 |
| 415 if ("set" in obj) { | 415 if ("set" in obj) { |
| 416 var set = obj.set; | 416 var set = obj.set; |
| 417 if (!IS_UNDEFINED(set) && !IS_FUNCTION(set)) { | 417 if (!IS_UNDEFINED(set) && !IS_SPEC_FUNCTION(set)) { |
| 418 throw MakeTypeError("setter_must_be_callable", [set]); | 418 throw MakeTypeError("setter_must_be_callable", [set]); |
| 419 } | 419 } |
| 420 desc.setSet(set); | 420 desc.setSet(set); |
| 421 } | 421 } |
| 422 | 422 |
| 423 if (IsInconsistentDescriptor(desc)) { | 423 if (IsInconsistentDescriptor(desc)) { |
| 424 throw MakeTypeError("value_and_accessor", [obj]); | 424 throw MakeTypeError("value_and_accessor", [obj]); |
| 425 } | 425 } |
| 426 return desc; | 426 return desc; |
| 427 } | 427 } |
| (...skipping 163 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 591 | 591 |
| 592 | 592 |
| 593 // For Harmony proxies. | 593 // For Harmony proxies. |
| 594 function GetTrap(handler, name, defaultTrap) { | 594 function GetTrap(handler, name, defaultTrap) { |
| 595 var trap = handler[name]; | 595 var trap = handler[name]; |
| 596 if (IS_UNDEFINED(trap)) { | 596 if (IS_UNDEFINED(trap)) { |
| 597 if (IS_UNDEFINED(defaultTrap)) { | 597 if (IS_UNDEFINED(defaultTrap)) { |
| 598 throw MakeTypeError("handler_trap_missing", [handler, name]); | 598 throw MakeTypeError("handler_trap_missing", [handler, name]); |
| 599 } | 599 } |
| 600 trap = defaultTrap; | 600 trap = defaultTrap; |
| 601 } else if (!IS_FUNCTION(trap)) { | 601 } else if (!IS_SPEC_FUNCTION(trap)) { |
| 602 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]); | 602 throw MakeTypeError("handler_trap_must_be_callable", [handler, name]); |
| 603 } | 603 } |
| 604 return trap; | 604 return trap; |
| 605 } | 605 } |
| 606 | 606 |
| 607 | 607 |
| 608 function CallTrap0(handler, name, defaultTrap) { | 608 function CallTrap0(handler, name, defaultTrap) { |
| 609 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap)); | 609 return %_CallFunction(handler, GetTrap(handler, name, defaultTrap)); |
| 610 } | 610 } |
| 611 | 611 |
| (...skipping 365 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 977 // ES5 section 15.2.3.6. | 977 // ES5 section 15.2.3.6. |
| 978 function ObjectDefineProperty(obj, p, attributes) { | 978 function ObjectDefineProperty(obj, p, attributes) { |
| 979 if (!IS_SPEC_OBJECT(obj)) { | 979 if (!IS_SPEC_OBJECT(obj)) { |
| 980 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]); | 980 throw MakeTypeError("obj_ctor_property_non_object", ["defineProperty"]); |
| 981 } | 981 } |
| 982 var name = ToString(p); | 982 var name = ToString(p); |
| 983 if (%IsJSProxy(obj)) { | 983 if (%IsJSProxy(obj)) { |
| 984 // Clone the attributes object for protection. | 984 // Clone the attributes object for protection. |
| 985 // TODO(rossberg): not spec'ed yet, so not sure if this should involve | 985 // TODO(rossberg): not spec'ed yet, so not sure if this should involve |
| 986 // non-own properties as it does (or non-enumerable ones, as it doesn't?). | 986 // non-own properties as it does (or non-enumerable ones, as it doesn't?). |
| 987 var attributesClone = {} | 987 var attributesClone = {}; |
| 988 for (var a in attributes) { | 988 for (var a in attributes) { |
| 989 attributesClone[a] = attributes[a]; | 989 attributesClone[a] = attributes[a]; |
| 990 } | 990 } |
| 991 DefineProxyProperty(obj, name, attributesClone, true); | 991 DefineProxyProperty(obj, name, attributesClone, true); |
| 992 // The following would implement the spec as in the current proposal, | 992 // The following would implement the spec as in the current proposal, |
| 993 // but after recent comments on es-discuss, is most likely obsolete. | 993 // but after recent comments on es-discuss, is most likely obsolete. |
| 994 /* | 994 /* |
| 995 var defineObj = FromGenericPropertyDescriptor(desc); | 995 var defineObj = FromGenericPropertyDescriptor(desc); |
| 996 var names = ObjectGetOwnPropertyNames(attributes); | 996 var names = ObjectGetOwnPropertyNames(attributes); |
| 997 var standardNames = | 997 var standardNames = |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1038 } | 1038 } |
| 1039 | 1039 |
| 1040 | 1040 |
| 1041 // Harmony proxies. | 1041 // Harmony proxies. |
| 1042 function ProxyFix(obj) { | 1042 function ProxyFix(obj) { |
| 1043 var handler = %GetHandler(obj); | 1043 var handler = %GetHandler(obj); |
| 1044 var props = CallTrap0(handler, "fix", void 0); | 1044 var props = CallTrap0(handler, "fix", void 0); |
| 1045 if (IS_UNDEFINED(props)) { | 1045 if (IS_UNDEFINED(props)) { |
| 1046 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]); | 1046 throw MakeTypeError("handler_returned_undefined", [handler, "fix"]); |
| 1047 } | 1047 } |
| 1048 %Fix(obj); | 1048 |
| 1049 if (IS_SPEC_FUNCTION(obj)) { |
| 1050 var callTrap = %GetCallTrap(obj); |
| 1051 var constructTrap = %GetConstructTrap(obj); |
| 1052 var code = DelegateCallAndConstruct(callTrap, constructTrap); |
| 1053 %Fix(obj); // becomes a regular function |
| 1054 %SetCode(obj, code); |
| 1055 } else { |
| 1056 %Fix(obj); |
| 1057 } |
| 1049 ObjectDefineProperties(obj, props); | 1058 ObjectDefineProperties(obj, props); |
| 1050 } | 1059 } |
| 1051 | 1060 |
| 1052 | 1061 |
| 1053 // ES5 section 15.2.3.8. | 1062 // ES5 section 15.2.3.8. |
| 1054 function ObjectSeal(obj) { | 1063 function ObjectSeal(obj) { |
| 1055 if (!IS_SPEC_OBJECT(obj)) { | 1064 if (!IS_SPEC_OBJECT(obj)) { |
| 1056 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]); | 1065 throw MakeTypeError("obj_ctor_property_non_object", ["seal"]); |
| 1057 } | 1066 } |
| 1058 if (%IsJSProxy(obj)) { | 1067 if (%IsJSProxy(obj)) { |
| (...skipping 347 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1406 | 1415 |
| 1407 SetupNumber(); | 1416 SetupNumber(); |
| 1408 | 1417 |
| 1409 | 1418 |
| 1410 // ---------------------------------------------------------------------------- | 1419 // ---------------------------------------------------------------------------- |
| 1411 // Function | 1420 // Function |
| 1412 | 1421 |
| 1413 $Function.prototype.constructor = $Function; | 1422 $Function.prototype.constructor = $Function; |
| 1414 | 1423 |
| 1415 function FunctionSourceString(func) { | 1424 function FunctionSourceString(func) { |
| 1425 while (%IsJSFunctionProxy(func)) { |
| 1426 func = %GetCallTrap(func); |
| 1427 } |
| 1428 |
| 1416 if (!IS_FUNCTION(func)) { | 1429 if (!IS_FUNCTION(func)) { |
| 1417 throw new $TypeError('Function.prototype.toString is not generic'); | 1430 throw new $TypeError('Function.prototype.toString is not generic'); |
| 1418 } | 1431 } |
| 1419 | 1432 |
| 1420 var source = %FunctionGetSourceCode(func); | 1433 var source = %FunctionGetSourceCode(func); |
| 1421 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) { | 1434 if (!IS_STRING(source) || %FunctionIsBuiltin(func)) { |
| 1422 var name = %FunctionGetName(func); | 1435 var name = %FunctionGetName(func); |
| 1423 if (name) { | 1436 if (name) { |
| 1424 // Mimic what KJS does. | 1437 // Mimic what KJS does. |
| 1425 return 'function ' + name + '() { [native code] }'; | 1438 return 'function ' + name + '() { [native code] }'; |
| 1426 } else { | 1439 } else { |
| 1427 return 'function () { [native code] }'; | 1440 return 'function () { [native code] }'; |
| 1428 } | 1441 } |
| 1429 } | 1442 } |
| 1430 | 1443 |
| 1431 var name = %FunctionNameShouldPrintAsAnonymous(func) | 1444 var name = %FunctionNameShouldPrintAsAnonymous(func) |
| 1432 ? 'anonymous' | 1445 ? 'anonymous' |
| 1433 : %FunctionGetName(func); | 1446 : %FunctionGetName(func); |
| 1434 return 'function ' + name + source; | 1447 return 'function ' + name + source; |
| 1435 } | 1448 } |
| 1436 | 1449 |
| 1437 | 1450 |
| 1438 function FunctionToString() { | 1451 function FunctionToString() { |
| 1439 return FunctionSourceString(this); | 1452 return FunctionSourceString(this); |
| 1440 } | 1453 } |
| 1441 | 1454 |
| 1442 | 1455 |
| 1443 // ES5 15.3.4.5 | 1456 // ES5 15.3.4.5 |
| 1444 function FunctionBind(this_arg) { // Length is 1. | 1457 function FunctionBind(this_arg) { // Length is 1. |
| 1445 if (!IS_FUNCTION(this)) { | 1458 if (!IS_SPEC_FUNCTION(this)) { |
| 1446 throw new $TypeError('Bind must be called on a function'); | 1459 throw new $TypeError('Bind must be called on a function'); |
| 1447 } | 1460 } |
| 1448 // this_arg is not an argument that should be bound. | 1461 // this_arg is not an argument that should be bound. |
| 1449 var argc_bound = (%_ArgumentsLength() || 1) - 1; | 1462 var argc_bound = (%_ArgumentsLength() || 1) - 1; |
| 1450 var fn = this; | 1463 var fn = this; |
| 1464 |
| 1451 if (argc_bound == 0) { | 1465 if (argc_bound == 0) { |
| 1452 var result = function() { | 1466 var result = function() { |
| 1453 if (%_IsConstructCall()) { | 1467 if (%_IsConstructCall()) { |
| 1454 // %NewObjectFromBound implicitly uses arguments passed to this | 1468 // %NewObjectFromBound implicitly uses arguments passed to this |
| 1455 // function. We do not pass the arguments object explicitly to avoid | 1469 // function. We do not pass the arguments object explicitly to avoid |
| 1456 // materializing it and guarantee that this function will be optimized. | 1470 // materializing it and guarantee that this function will be optimized. |
| 1457 return %NewObjectFromBound(fn, null); | 1471 return %NewObjectFromBound(fn, null); |
| 1458 } | 1472 } |
| 1459 | 1473 return %Apply(fn, this_arg, arguments, 0, %_ArgumentsLength()); |
| 1460 return fn.apply(this_arg, arguments); | |
| 1461 }; | 1474 }; |
| 1462 } else { | 1475 } else { |
| 1463 var bound_args = new InternalArray(argc_bound); | 1476 var bound_args = new InternalArray(argc_bound); |
| 1464 for(var i = 0; i < argc_bound; i++) { | 1477 for(var i = 0; i < argc_bound; i++) { |
| 1465 bound_args[i] = %_Arguments(i+1); | 1478 bound_args[i] = %_Arguments(i+1); |
| 1466 } | 1479 } |
| 1467 | 1480 |
| 1468 var result = function() { | 1481 var result = function() { |
| 1469 // If this is a construct call we use a special runtime method | 1482 // If this is a construct call we use a special runtime method |
| 1470 // to generate the actual object using the bound function. | 1483 // to generate the actual object using the bound function. |
| 1471 if (%_IsConstructCall()) { | 1484 if (%_IsConstructCall()) { |
| 1472 // %NewObjectFromBound implicitly uses arguments passed to this | 1485 // %NewObjectFromBound implicitly uses arguments passed to this |
| 1473 // function. We do not pass the arguments object explicitly to avoid | 1486 // function. We do not pass the arguments object explicitly to avoid |
| 1474 // materializing it and guarantee that this function will be optimized. | 1487 // materializing it and guarantee that this function will be optimized. |
| 1475 return %NewObjectFromBound(fn, bound_args); | 1488 return %NewObjectFromBound(fn, bound_args); |
| 1476 } | 1489 } |
| 1477 | 1490 |
| 1478 // Combine the args we got from the bind call with the args | 1491 // Combine the args we got from the bind call with the args |
| 1479 // given as argument to the invocation. | 1492 // given as argument to the invocation. |
| 1480 var argc = %_ArgumentsLength(); | 1493 var argc = %_ArgumentsLength(); |
| 1481 var args = new InternalArray(argc + argc_bound); | 1494 var args = new InternalArray(argc + argc_bound); |
| 1482 // Add bound arguments. | 1495 // Add bound arguments. |
| 1483 for (var i = 0; i < argc_bound; i++) { | 1496 for (var i = 0; i < argc_bound; i++) { |
| 1484 args[i] = bound_args[i]; | 1497 args[i] = bound_args[i]; |
| 1485 } | 1498 } |
| 1486 // Add arguments from call. | 1499 // Add arguments from call. |
| 1487 for (var i = 0; i < argc; i++) { | 1500 for (var i = 0; i < argc; i++) { |
| 1488 args[argc_bound + i] = %_Arguments(i); | 1501 args[argc_bound + i] = %_Arguments(i); |
| 1489 } | 1502 } |
| 1490 return fn.apply(this_arg, args); | 1503 return %Apply(fn, this_arg, args, 0, argc + argc_bound); |
| 1491 }; | 1504 }; |
| 1492 } | 1505 } |
| 1493 | 1506 |
| 1494 // We already have caller and arguments properties on functions, | 1507 // We already have caller and arguments properties on functions, |
| 1495 // which are non-configurable. It therefore makes no sence to | 1508 // which are non-configurable. It therefore makes no sence to |
| 1496 // try to redefine these as defined by the spec. The spec says | 1509 // try to redefine these as defined by the spec. The spec says |
| 1497 // that bind should make these throw a TypeError if get or set | 1510 // that bind should make these throw a TypeError if get or set |
| 1498 // is called and make them non-enumerable and non-configurable. | 1511 // is called and make them non-enumerable and non-configurable. |
| 1499 // To be consistent with our normal functions we leave this as it is. | 1512 // To be consistent with our normal functions we leave this as it is. |
| 1500 | 1513 |
| 1501 // Set the correct length. | |
| 1502 var length = (this.length - argc_bound) > 0 ? this.length - argc_bound : 0; | |
| 1503 %FunctionRemovePrototype(result); | 1514 %FunctionRemovePrototype(result); |
| 1504 %FunctionSetBound(result); | 1515 %FunctionSetBound(result); |
| 1505 %BoundFunctionSetLength(result, length); | 1516 // Set the correct length. If this is a function proxy, this.length might |
| 1517 // throw, or return a bogus result. Leave length alone in that case. |
| 1518 // TODO(rossberg): This is underspecified in the current proxy proposal. |
| 1519 try { |
| 1520 var old_length = ToInteger(this.length); |
| 1521 var length = (old_length - argc_bound) > 0 ? old_length - argc_bound : 0; |
| 1522 %BoundFunctionSetLength(result, length); |
| 1523 } catch(x) {} |
| 1506 return result; | 1524 return result; |
| 1507 } | 1525 } |
| 1508 | 1526 |
| 1509 | 1527 |
| 1510 function NewFunction(arg1) { // length == 1 | 1528 function NewFunction(arg1) { // length == 1 |
| 1511 var n = %_ArgumentsLength(); | 1529 var n = %_ArgumentsLength(); |
| 1512 var p = ''; | 1530 var p = ''; |
| 1513 if (n > 1) { | 1531 if (n > 1) { |
| 1514 p = new InternalArray(n - 1); | 1532 p = new InternalArray(n - 1); |
| 1515 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); | 1533 for (var i = 0; i < n - 1; i++) p[i] = %_Arguments(i); |
| (...skipping 18 matching lines...) Expand all Loading... |
| 1534 // ---------------------------------------------------------------------------- | 1552 // ---------------------------------------------------------------------------- |
| 1535 | 1553 |
| 1536 function SetupFunction() { | 1554 function SetupFunction() { |
| 1537 InstallFunctions($Function.prototype, DONT_ENUM, $Array( | 1555 InstallFunctions($Function.prototype, DONT_ENUM, $Array( |
| 1538 "bind", FunctionBind, | 1556 "bind", FunctionBind, |
| 1539 "toString", FunctionToString | 1557 "toString", FunctionToString |
| 1540 )); | 1558 )); |
| 1541 } | 1559 } |
| 1542 | 1560 |
| 1543 SetupFunction(); | 1561 SetupFunction(); |
| OLD | NEW |