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 |