Make bound functions have poisoned .caller and .arguments.
Also makes func.caller return null if the caller is a bound function, matching JSC. Fix bug preventing poisoned setters from triggering. TEST=mjsunit/function-bind, mjsunit/strict-mode Review URL: http://codereview.chromium.org/8333019 git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@9681 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
feeb0b0211
commit
cefbb1e7f8
@ -759,7 +759,12 @@ MaybeObject* Accessors::FunctionGetCaller(Object* object, void*) {
|
||||
caller = potential_caller;
|
||||
potential_caller = it.next();
|
||||
}
|
||||
|
||||
// If caller is bound, return null. This is compatible with JSC, and
|
||||
// allows us to make bound functions use the strict function map
|
||||
// and its associated throwing caller and arguments.
|
||||
if (caller->shared()->bound()) {
|
||||
return isolate->heap()->null_value();
|
||||
}
|
||||
return CheckNonStrictCallerOrThrow(isolate, caller);
|
||||
}
|
||||
|
||||
|
@ -522,7 +522,7 @@ Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
|
||||
? 4
|
||||
: 5);
|
||||
PropertyAttributes attributes = static_cast<PropertyAttributes>(
|
||||
DONT_ENUM | DONT_DELETE | READ_ONLY);
|
||||
DONT_ENUM | DONT_DELETE);
|
||||
|
||||
{ // length
|
||||
Handle<Foreign> foreign = factory()->NewForeign(&Accessors::FunctionLength);
|
||||
@ -547,8 +547,8 @@ Handle<DescriptorArray> Genesis::ComputeStrictFunctionInstanceDescriptor(
|
||||
|
||||
// prototype
|
||||
if (prototypeMode != DONT_ADD_PROTOTYPE) {
|
||||
if (prototypeMode == ADD_WRITEABLE_PROTOTYPE) {
|
||||
attributes = static_cast<PropertyAttributes>(attributes & ~READ_ONLY);
|
||||
if (prototypeMode != ADD_WRITEABLE_PROTOTYPE) {
|
||||
attributes = static_cast<PropertyAttributes>(attributes | READ_ONLY);
|
||||
}
|
||||
Handle<Foreign> foreign =
|
||||
factory()->NewForeign(&Accessors::FunctionPrototype);
|
||||
|
@ -1413,6 +1413,7 @@ MaybeObject* StoreIC::Store(State state,
|
||||
return TypeError("strict_read_only_property", object, name);
|
||||
}
|
||||
// Ignore other stores where the receiver is not a JSObject.
|
||||
// TODO(1475): Must check prototype chains of object wrappers.
|
||||
return *value;
|
||||
}
|
||||
|
||||
@ -1444,7 +1445,6 @@ MaybeObject* StoreIC::Store(State state,
|
||||
// Lookup the property locally in the receiver.
|
||||
if (FLAG_use_ic && !receiver->IsJSGlobalProxy()) {
|
||||
LookupResult lookup(isolate());
|
||||
|
||||
if (LookupForWrite(*receiver, *name, &lookup)) {
|
||||
// Generate a stub for this store.
|
||||
UpdateCaches(&lookup, state, strict_mode, receiver, name, value);
|
||||
|
@ -1520,6 +1520,8 @@ function FunctionBind(this_arg) { // Length is 1.
|
||||
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()) {
|
||||
|
@ -263,3 +263,34 @@ assertEquals(["foo", 0, undefined], s());
|
||||
|
||||
s = soo.bind(true);
|
||||
assertEquals([true, 0, undefined], s());
|
||||
|
||||
// Test that .arguments and .caller are poisoned according to the ES5 spec.
|
||||
|
||||
// Check that property descriptors are correct (unconfigurable, unenumerable,
|
||||
// and both get and set is the ThrowTypeError function).
|
||||
var cdesc = Object.getOwnPropertyDescriptor(f, "caller");
|
||||
var adesc = Object.getOwnPropertyDescriptor(f, "arguments");
|
||||
|
||||
assertFalse(cdesc.enumerable);
|
||||
assertFalse(cdesc.configurable);
|
||||
|
||||
assertFalse(adesc.enumerable);
|
||||
assertFalse(adesc.configurable);
|
||||
|
||||
assertSame(cdesc.get, cdesc.set);
|
||||
assertSame(cdesc.get, adesc.get);
|
||||
assertSame(cdesc.get, adesc.set);
|
||||
|
||||
assertTrue(cdesc.get instanceof Function);
|
||||
assertEquals(0, cdesc.get.length);
|
||||
assertThrows(cdesc.get, TypeError);
|
||||
|
||||
assertThrows(function() { return f.caller; }, TypeError);
|
||||
assertThrows(function() { f.caller = 42; }, TypeError);
|
||||
assertThrows(function() { return f.arguments; }, TypeError);
|
||||
assertThrows(function() { f.arguments = 42; }, TypeError);
|
||||
|
||||
// Shouldn't throw. Accessing the functions caller must throw if
|
||||
// the caller is strict and the callee isn't. A bound function is built-in,
|
||||
// but not considered strict.
|
||||
(function foo() { return foo.caller; }).bind()();
|
||||
|
@ -1051,14 +1051,20 @@ function CheckPillDescriptor(func, name) {
|
||||
}
|
||||
assertThrows(function() { strict.caller; }, TypeError);
|
||||
assertThrows(function() { strict.arguments; }, TypeError);
|
||||
assertThrows(function() { strict.caller = 42; }, TypeError);
|
||||
assertThrows(function() { strict.arguments = 42; }, TypeError);
|
||||
|
||||
var another = new Function("'use strict'");
|
||||
assertThrows(function() { another.caller; }, TypeError);
|
||||
assertThrows(function() { another.arguments; }, TypeError);
|
||||
assertThrows(function() { another.caller = 42; }, TypeError);
|
||||
assertThrows(function() { another.arguments = 42; }, TypeError);
|
||||
|
||||
var third = (function() { "use strict"; return function() {}; })();
|
||||
assertThrows(function() { third.caller; }, TypeError);
|
||||
assertThrows(function() { third.arguments; }, TypeError);
|
||||
assertThrows(function() { third.caller = 42; }, TypeError);
|
||||
assertThrows(function() { third.arguments = 42; }, TypeError);
|
||||
|
||||
CheckPillDescriptor(strict, "caller");
|
||||
CheckPillDescriptor(strict, "arguments");
|
||||
|
@ -30,10 +30,6 @@ def FAIL_OK = FAIL, OKAY
|
||||
|
||||
############################### BUGS ###################################
|
||||
|
||||
# A bound function should fail on access to 'caller' and 'arguments'.
|
||||
S15.3.4.5_A1: FAIL
|
||||
S15.3.4.5_A2: FAIL
|
||||
|
||||
# '__proto__' should be treated as a normal property in JSON.
|
||||
S15.12.2_A1: FAIL
|
||||
|
||||
|
@ -30,10 +30,6 @@ def FAIL_OK = FAIL, OKAY
|
||||
|
||||
############################### BUGS ###################################
|
||||
|
||||
# A bound function should fail on access to 'caller' and 'arguments'.
|
||||
S15.3.4.5_A1: FAIL
|
||||
S15.3.4.5_A2: FAIL
|
||||
|
||||
# '__proto__' should be treated as a normal property in JSON.
|
||||
S15.12.2_A1: FAIL
|
||||
|
||||
@ -43,9 +39,6 @@ S8.7_A5_T2: FAIL
|
||||
# V8 Bug: http://code.google.com/p/v8/issues/detail?id=1624
|
||||
S10.4.2.1_A1: FAIL
|
||||
|
||||
# V8 Bug.
|
||||
S13.2.3_A1: FAIL
|
||||
|
||||
# V8 Bug: http://code.google.com/p/v8/issues/detail?id=1530
|
||||
S15.3.3.1_A4: FAIL
|
||||
|
||||
@ -128,12 +121,6 @@ S15.3.3.1_A4: FAIL
|
||||
15.2.3.7-6-a-176: FAIL
|
||||
15.2.3.7-6-a-177: FAIL
|
||||
|
||||
# V8 Bug: http://code.google.com/p/v8/issues/detail?id=893
|
||||
15.3.4.5-20-2: FAIL
|
||||
15.3.4.5-20-3: FAIL
|
||||
15.3.4.5-21-2: FAIL
|
||||
15.3.4.5-21-3: FAIL
|
||||
|
||||
# Invalid test cases (recent change adding var changes semantics)
|
||||
S8.3_A1_T1: FAIL
|
||||
S15.3_A3_T1: FAIL
|
||||
|
Loading…
Reference in New Issue
Block a user