Changeset 107498 in webkit


Ignore:
Timestamp:
Feb 11, 2012 6:47:50 PM (12 years ago)
Author:
barraclough@apple.com
Message:

Move special proto property to Object.prototype
https://bugs.webkit.org/show_bug.cgi?id=78409

Reviewed by Oliver Hunt.

Re-implement this as a regular accessor property. This has three key benefits:
1) It makes it possible for objects to be given properties named proto.
2) Object.prototype.proto can be deleted, preventing object prototypes from being changed.
3) This largely removes the magic used the implement proto, it can just be made a regular accessor property.

Source/JavaScriptCore:

  • parser/Parser.cpp:

(JSC::::parseFunctionInfo):

  • No need to prohibit functions named proto.
  • runtime/JSGlobalObject.cpp:

(JSC::JSGlobalObject::reset):

  • Add proto accessor to Object.prototype.
  • runtime/JSGlobalObjectFunctions.cpp:

(JSC::globalFuncProtoGetter):
(JSC::globalFuncProtoSetter):

  • Definition of the proto accessor functions.
  • runtime/JSGlobalObjectFunctions.h:
    • Declaration of the proto accessor functions.
  • runtime/JSObject.cpp:

(JSC::JSObject::put):

  • Remove the special handling for proto, there is still a check to allow for a fast guard for accessors excluding proto.

(JSC::JSObject::putDirectAccessor):

  • Track on the structure whether an object contains accessors other than one for proto.

(JSC::JSObject::defineOwnProperty):

  • No need to prohibit definition of own properties named proto.
  • runtime/JSObject.h:

(JSC::JSObject::inlineGetOwnPropertySlot):

  • Remove the special handling for proto.

(JSC::JSValue::get):

  • Remove the special handling for proto.
  • runtime/JSString.cpp:

(JSC::JSString::getOwnPropertySlot):

  • Remove the special handling for proto.
  • runtime/JSValue.h:

(JSValue):

  • Made synthesizePrototype public (this may be needed by the proto getter).
  • runtime/ObjectConstructor.cpp:

(JSC::objectConstructorGetPrototypeOf):

  • Perform the security check & call prototype() directly.
  • runtime/Structure.cpp:

(JSC::Structure::Structure):

  • Added 'ExcludingProto' variant of the 'hasGetterSetterProperties' state.
  • runtime/Structure.h:

(JSC::Structure::hasGetterSetterPropertiesExcludingProto):
(JSC::Structure::setHasGetterSetterProperties):
(Structure):

  • Added 'ExcludingProto' variant of the 'hasGetterSetterProperties' state.

Source/WebCore:

  • bindings/js/JSDOMWindowBase.cpp:

(WebCore::JSDOMWindowBase::allowsAccessFrom):
(WebCore):

  • expose allowsAccessFrom check to JSC.
  • bindings/js/JSDOMWindowBase.h:

(JSDOMWindowBase):

  • expose allowsAccessFrom check to JSC.

LayoutTests:

  • fast/js/Object-getOwnPropertyNames-expected.txt:
  • fast/js/cyclic-prototypes-expected.txt:
  • fast/js/parser-syntax-check-expected.txt:
  • fast/js/preventExtensions-expected.txt:
  • fast/js/prototypes-expected.txt:
    • Update results
  • fast/js/script-tests/Object-getOwnPropertyNames.js:
    • proto is now a property of Object Prototype.
  • fast/js/script-tests/cyclic-prototypes.js:
    • setting an object's prototype to null removes proto setter, future usage won't set prototype.
  • fast/js/script-tests/parser-syntax-check.js:
    • Allow functions named proto
  • fast/js/script-tests/preventExtensions.js:
    • Setting proto should not throw.
  • fast/js/script-tests/prototypes.js:
    • Objects may contained own properties named proto, add new test cases.
Location:
trunk
Files:
29 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r107496 r107498  
     12012-02-10  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Move special __proto__ property to Object.prototype
     4        https://bugs.webkit.org/show_bug.cgi?id=78409
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Re-implement this as a regular accessor property.  This has three key benefits:
     9        1) It makes it possible for objects to be given properties named __proto__.
     10        2) Object.prototype.__proto__ can be deleted, preventing object prototypes from being changed.
     11        3) This largely removes the magic used the implement __proto__, it can just be made a regular accessor property.
     12
     13        * fast/js/Object-getOwnPropertyNames-expected.txt:
     14        * fast/js/cyclic-prototypes-expected.txt:
     15        * fast/js/parser-syntax-check-expected.txt:
     16        * fast/js/preventExtensions-expected.txt:
     17        * fast/js/prototypes-expected.txt:
     18            - Update results
     19        * fast/js/script-tests/Object-getOwnPropertyNames.js:
     20            - __proto__ is now a property of Object Prototype.
     21        * fast/js/script-tests/cyclic-prototypes.js:
     22            - setting an object's prototype to null removes __proto__ setter, future usage won't set prototype.
     23        * fast/js/script-tests/parser-syntax-check.js:
     24            - Allow functions named __proto__
     25        * fast/js/script-tests/preventExtensions.js:
     26            - Setting __proto__ should not throw.
     27        * fast/js/script-tests/prototypes.js:
     28            - Objects may contained own properties named __proto__, add new test cases.
     29
    1302012-02-11  Filip Pizlo  <fpizlo@apple.com>
    231
  • trunk/LayoutTests/fast/js/Object-getOwnPropertyNames-expected.txt

    r95867 r107498  
    4242PASS getSortedOwnPropertyNames(encodeURIComponent) is ['length', 'name']
    4343PASS getSortedOwnPropertyNames(Object) is ['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal']
    44 PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']
     44PASS getSortedOwnPropertyNames(Object.prototype) is ['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']
    4545PASS getSortedOwnPropertyNames(Function) is ['length', 'name', 'prototype']
    4646PASS getSortedOwnPropertyNames(Function.prototype) is ['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']
  • trunk/LayoutTests/fast/js/cyclic-prototypes-expected.txt

    r21336 r107498  
    44
    55
    6 PASS o1.__proto__ = o3 threw exception Error: cyclic __proto__ value.
     6PASS o1.__proto__ = o3; threw exception Error: cyclic __proto__ value.
     7PASS ({}).hasOwnProperty.call(o1, '__proto__') is false
     8PASS ({}).hasOwnProperty.call(o1, '__proto__') is true
     9PASS Object.getPrototypeOf(o1) is null
    710PASS successfullyParsed is true
    811
  • trunk/LayoutTests/fast/js/parser-syntax-check-expected.txt

    r106297 r107498  
    542542PASS Invalid: "for(var a,b '"
    543543PASS Invalid: "function f() { for(var a,b ' }"
    544 PASS Invalid: "function __proto__(){}"
    545 PASS Invalid: "function f() { function __proto__(){} }"
    546 PASS Invalid: "(function __proto__(){})"
    547 PASS Invalid: "function f() { (function __proto__(){}) }"
    548 PASS Invalid: "'use strict'; function __proto__(){}"
    549 PASS Invalid: "function f() { 'use strict'; function __proto__(){} }"
    550 PASS Invalid: "'use strict'; (function __proto__(){})"
    551 PASS Invalid: "function f() { 'use strict'; (function __proto__(){}) }"
     544PASS Valid:  "function __proto__(){}"
     545PASS Valid:  "function f() { function __proto__(){} }"
     546PASS Valid:  "(function __proto__(){})"
     547PASS Valid:  "function f() { (function __proto__(){}) }"
     548PASS Valid:  "'use strict'; function __proto__(){}"
     549PASS Valid:  "function f() { 'use strict'; function __proto__(){} }"
     550PASS Valid:  "'use strict'; (function __proto__(){})"
     551PASS Valid:  "function f() { 'use strict'; (function __proto__(){}) }"
    552552PASS Valid:   "if (0) $foo; "
    553553PASS Valid:   "function f() { if (0) $foo;  }"
  • trunk/LayoutTests/fast/js/preventExtensions-expected.txt

    r93048 r107498  
    1313PASS Object.preventExtensions(Math.sin) is Math.sin
    1414PASS var o = {}; Object.preventExtensions(o); o.__proto__ = { newProp: "Should not see this" }; o.newProp; is undefined.
    15 PASS "use strict"; var o = {}; Object.preventExtensions(o); o.__proto__ = { newProp: "Should not see this" }; threw exception TypeError: Attempted to assign to readonly property..
     15PASS "use strict"; var o = {}; Object.preventExtensions(o); o.__proto__ = { newProp: "Should not see this" }; o.newProp; is undefined.
    1616PASS Object.preventExtensions(Math); Math.sqrt(4) is 2
    1717PASS successfullyParsed is true
  • trunk/LayoutTests/fast/js/prototypes-expected.txt

    r98998 r107498  
    5454PASS Object.__proto__.isPrototypeOf(Number) is true
    5555PASS Object.__proto__.isPrototypeOf(String) is true
    56 PASS var wasSet = false; var o = { }; o.__defineGetter__("__proto__", function() { wasSet = true }); o.__proto__; wasSet; is false
    57 PASS var wasSet = false; var o = { }; o.__defineSetter__("__proto__", function() { wasSet = true }); o.__proto__ = {}; wasSet; is false
    58 PASS var wasSet = false; var o = { }; Object.defineProperty(o, "__proto__", { "get": function() { wasSet = true } }); o.__proto__; wasSet; is false
     56PASS var wasSet = false; var o = { }; o.__defineGetter__("__proto__", function() { wasSet = true }); o.__proto__; wasSet; is true
     57PASS var wasSet = false; var o = { }; o.__defineSetter__("__proto__", function() { wasSet = true }); o.__proto__ = {}; wasSet; is true
     58PASS var wasSet = false; var o = { }; Object.defineProperty(o, "__proto__", { "get": function() { wasSet = true } }); o.__proto__; wasSet; is true
    5959PASS var wasSet = false; var o = { }; Object.defineProperty(o, "__proto__", { "__proto__": function(x) { wasSet = true } }); o.__proto__ = {}; wasSet; is false
     60PASS var o = {}; o.__proto__ = { x:true }; o.x is true
     61PASS var o = {}; o.__proto__ = { x:true }; o.hasOwnProperty('__proto__') is false
     62PASS var o = {}; o.__proto__ = { x:true }; o.x is undefined.
     63PASS var o = {}; o.__proto__ = { x:true }; o.hasOwnProperty('__proto__') is true
    6064PASS successfullyParsed is true
    6165
  • trunk/LayoutTests/fast/js/script-tests/Object-getOwnPropertyNames.js

    r98407 r107498  
    5050// Built-in ECMA objects
    5151    "Object": "['create', 'defineProperties', 'defineProperty', 'freeze', 'getOwnPropertyDescriptor', 'getOwnPropertyNames', 'getPrototypeOf', 'isExtensible', 'isFrozen', 'isSealed', 'keys', 'length', 'name', 'preventExtensions', 'prototype', 'seal']",
    52     "Object.prototype": "['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']",
     52    "Object.prototype": "['__defineGetter__', '__defineSetter__', '__lookupGetter__', '__lookupSetter__', '__proto__', 'constructor', 'hasOwnProperty', 'isPrototypeOf', 'propertyIsEnumerable', 'toLocaleString', 'toString', 'valueOf']",
    5353    "Function": "['length', 'name', 'prototype']",
    5454    "Function.prototype": "['apply', 'bind', 'call', 'constructor', 'length', 'name', 'toString']",
  • trunk/LayoutTests/fast/js/script-tests/cyclic-prototypes.js

    r98407 r107498  
    77o3.__proto__ = o2;
    88
    9 o1.__proto__ = null;  // just for sanity's sake
     9// Try to create a cyclical prototype chain.
     10shouldThrow("o1.__proto__ = o3;");
    1011
    11 shouldThrow("o1.__proto__ = o3");
     12// This changes behaviour, since __proto__ is an accessor on Object.prototype.
     13o1.__proto__ = null;
     14
     15shouldBeFalse("({}).hasOwnProperty.call(o1, '__proto__')");
     16o1.__proto__ = o3;
     17shouldBeTrue("({}).hasOwnProperty.call(o1, '__proto__')");
     18shouldBe("Object.getPrototypeOf(o1)", "null");
  • trunk/LayoutTests/fast/js/script-tests/parser-syntax-check.js

    r106297 r107498  
    348348invalid("for(var a,b '");
    349349
    350 invalid("function __proto__(){}")
    351 invalid("(function __proto__(){})")
    352 invalid("'use strict'; function __proto__(){}")
    353 invalid("'use strict'; (function __proto__(){})")
     350valid("function __proto__(){}")
     351valid("(function __proto__(){})")
     352valid("'use strict'; function __proto__(){}")
     353valid("'use strict'; (function __proto__(){})")
    354354
    355355valid("if (0) $foo; ")
  • trunk/LayoutTests/fast/js/script-tests/preventExtensions.js

    r98407 r107498  
    7070
    7171shouldBeUndefined('var o = {}; Object.preventExtensions(o); o.__proto__ = { newProp: "Should not see this" }; o.newProp;');
    72 shouldThrow('"use strict"; var o = {}; Object.preventExtensions(o); o.__proto__ = { newProp: "Should not see this" };');
     72shouldBeUndefined('"use strict"; var o = {}; Object.preventExtensions(o); o.__proto__ = { newProp: "Should not see this" }; o.newProp;');
    7373
    7474// check that we can still access static properties on an object after calling preventExtensions.
  • trunk/LayoutTests/fast/js/script-tests/prototypes.js

    r98998 r107498  
    5656shouldBeTrue("Object.__proto__.isPrototypeOf(String)");
    5757
    58 shouldBeFalse("var wasSet = false; var o = { }; o.__defineGetter__(\"__proto__\", function() { wasSet = true }); o.__proto__; wasSet;");
    59 shouldBeFalse("var wasSet = false; var o = { }; o.__defineSetter__(\"__proto__\", function() { wasSet = true }); o.__proto__ = {}; wasSet;");
    60 shouldBeFalse("var wasSet = false; var o = { }; Object.defineProperty(o, \"__proto__\", { \"get\": function() { wasSet = true } }); o.__proto__; wasSet;");
     58shouldBeTrue("var wasSet = false; var o = { }; o.__defineGetter__(\"__proto__\", function() { wasSet = true }); o.__proto__; wasSet;");
     59shouldBeTrue("var wasSet = false; var o = { }; o.__defineSetter__(\"__proto__\", function() { wasSet = true }); o.__proto__ = {}; wasSet;");
     60shouldBeTrue("var wasSet = false; var o = { }; Object.defineProperty(o, \"__proto__\", { \"get\": function() { wasSet = true } }); o.__proto__; wasSet;");
    6161shouldBeFalse("var wasSet = false; var o = { }; Object.defineProperty(o, \"__proto__\", { \"__proto__\": function(x) { wasSet = true } }); o.__proto__ = {}; wasSet;");
     62
     63// Deleting Object.prototype.__proto__ removes the ability to set the object's prototype.
     64shouldBeTrue("var o = {}; o.__proto__ = { x:true }; o.x");
     65shouldBeFalse("var o = {}; o.__proto__ = { x:true }; o.hasOwnProperty('__proto__')");
     66delete Object.prototype.__proto__;
     67shouldBeUndefined("var o = {}; o.__proto__ = { x:true }; o.x");
     68shouldBeTrue("var o = {}; o.__proto__ = { x:true }; o.hasOwnProperty('__proto__')");
  • trunk/Source/JavaScriptCore/ChangeLog

    r107496 r107498  
     12012-02-11  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Move special __proto__ property to Object.prototype
     4        https://bugs.webkit.org/show_bug.cgi?id=78409
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Re-implement this as a regular accessor property.  This has three key benefits:
     9        1) It makes it possible for objects to be given properties named __proto__.
     10        2) Object.prototype.__proto__ can be deleted, preventing object prototypes from being changed.
     11        3) This largely removes the magic used the implement __proto__, it can just be made a regular accessor property.
     12
     13        * parser/Parser.cpp:
     14        (JSC::::parseFunctionInfo):
     15            - No need to prohibit functions named __proto__.
     16        * runtime/JSGlobalObject.cpp:
     17        (JSC::JSGlobalObject::reset):
     18            - Add __proto__ accessor to Object.prototype.
     19        * runtime/JSGlobalObjectFunctions.cpp:
     20        (JSC::globalFuncProtoGetter):
     21        (JSC::globalFuncProtoSetter):
     22            - Definition of the __proto__ accessor functions.
     23        * runtime/JSGlobalObjectFunctions.h:
     24            - Declaration of the __proto__ accessor functions.
     25        * runtime/JSObject.cpp:
     26        (JSC::JSObject::put):
     27            - Remove the special handling for __proto__, there is still a check to allow for a fast guard for accessors excluding __proto__.
     28        (JSC::JSObject::putDirectAccessor):
     29            - Track on the structure whether an object contains accessors other than one for __proto__.
     30        (JSC::JSObject::defineOwnProperty):
     31            - No need to prohibit definition of own properties named __proto__.
     32        * runtime/JSObject.h:
     33        (JSC::JSObject::inlineGetOwnPropertySlot):
     34            - Remove the special handling for __proto__.
     35        (JSC::JSValue::get):
     36            - Remove the special handling for __proto__.
     37        * runtime/JSString.cpp:
     38        (JSC::JSString::getOwnPropertySlot):
     39            - Remove the special handling for __proto__.
     40        * runtime/JSValue.h:
     41        (JSValue):
     42            - Made synthesizePrototype public (this may be needed by the __proto__ getter).
     43        * runtime/ObjectConstructor.cpp:
     44        (JSC::objectConstructorGetPrototypeOf):
     45            - Perform the security check & call prototype() directly.
     46        * runtime/Structure.cpp:
     47        (JSC::Structure::Structure):
     48            - Added 'ExcludingProto' variant of the 'hasGetterSetterProperties' state.
     49        * runtime/Structure.h:
     50        (JSC::Structure::hasGetterSetterPropertiesExcludingProto):
     51        (JSC::Structure::setHasGetterSetterProperties):
     52        (Structure):
     53            - Added 'ExcludingProto' variant of the 'hasGetterSetterProperties' state.
     54
    1552012-02-11  Filip Pizlo  <fpizlo@apple.com>
    256
  • trunk/Source/JavaScriptCore/parser/Parser.cpp

    r107338 r107498  
    775775    if (match(IDENT)) {
    776776        name = m_token.m_data.ident;
    777         failIfTrueWithMessage(*name == m_globalData->propertyNames->underscoreProto, "Cannot name a function __proto__");
    778777        next();
    779778        if (!nameIsInContainingScope)
  • trunk/Source/JavaScriptCore/runtime/ClassInfo.h

    r106783 r107498  
    9090        typedef bool (*GetOwnPropertyDescriptorFunctionPtr)(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
    9191        GetOwnPropertyDescriptorFunctionPtr getOwnPropertyDescriptor;
     92
     93        typedef bool (*AllowsAccessFromFunctionPtr)(JSObject*, ExecState*);
     94        AllowsAccessFromFunctionPtr allowsAccessFrom;
    9295    };
    9396
     
    131134        &ClassName::defineOwnProperty, \
    132135        &ClassName::getOwnPropertyDescriptor, \
     136        &ClassName::allowsAccessFrom, \
    133137    }, \
    134138    sizeof(ClassName), \
  • trunk/Source/JavaScriptCore/runtime/JSCell.cpp

    r106783 r107498  
    192192}
    193193
     194bool JSCell::allowsAccessFrom(JSObject*, ExecState*)
     195{
     196    ASSERT_NOT_REACHED();
     197    return false;
     198}
     199
    194200bool JSCell::defineOwnProperty(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&, bool)
    195201{
  • trunk/Source/JavaScriptCore/runtime/JSCell.h

    r107445 r107498  
    162162        static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
    163163        static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
     164        static bool allowsAccessFrom(JSObject*, ExecState*);
    164165
    165166    private:
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObject.cpp

    r106783 r107498  
    206206    m_applyFunction.set(exec->globalData(), this, applyFunction);
    207207    m_objectPrototype.set(exec->globalData(), this, ObjectPrototype::create(exec, this, ObjectPrototype::createStructure(exec->globalData(), this, jsNull())));
     208    GetterSetter* protoAccessor = GetterSetter::create(exec);
     209    protoAccessor->setGetter(exec->globalData(), JSFunction::create(exec, this, 0, Identifier(), globalFuncProtoGetter));
     210    protoAccessor->setSetter(exec->globalData(), JSFunction::create(exec, this, 0, Identifier(), globalFuncProtoSetter));
     211    m_objectPrototype->putDirectAccessor(exec->globalData(), exec->propertyNames().underscoreProto, protoAccessor, Accessor | DontEnum);
    208212    m_functionPrototype->structure()->setPrototypeWithoutTransition(exec->globalData(), m_objectPrototype.get());
    209213
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp

    r105698 r107498  
    715715}
    716716
     717EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState* exec)
     718{
     719    if (!exec->thisValue().isObject())
     720        return JSValue::encode(exec->thisValue().synthesizePrototype(exec));
     721
     722    JSObject* thisObject = asObject(exec->thisValue());
     723    if (!thisObject->methodTable()->allowsAccessFrom(thisObject, exec))
     724        return JSValue::encode(jsUndefined());
     725
     726    return JSValue::encode(thisObject->prototype());
     727}
     728
     729EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState* exec)
     730{
     731    JSValue value = exec->argument(0);
     732
     733    // Setting __proto__ of a primitive should have no effect.
     734    if (!exec->thisValue().isObject())
     735        return JSValue::encode(jsUndefined());
     736
     737    JSObject* thisObject = asObject(exec->thisValue());
     738    if (!thisObject->methodTable()->allowsAccessFrom(thisObject, exec))
     739        return JSValue::encode(jsUndefined());
     740
     741    // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
     742    if (!value.isObject() && !value.isNull())
     743        return JSValue::encode(jsUndefined());
     744
     745    if (!thisObject->isExtensible())
     746        return JSValue::encode(jsUndefined());
     747
     748    if (!thisObject->setPrototypeWithCycleCheck(exec->globalData(), value))
     749        throwError(exec, createError(exec, "cyclic __proto__ value"));
     750
     751    return JSValue::encode(jsUndefined());
     752}
     753
    717754} // namespace JSC
  • trunk/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h

    r99436 r107498  
    4949    EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*);
    5050    EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState*);
     51    EncodedJSValue JSC_HOST_CALL globalFuncProtoGetter(ExecState*);
     52    EncodedJSValue JSC_HOST_CALL globalFuncProtoSetter(ExecState*);
    5153
    5254    static const double mantissaOverflowLowerBound = 9007199254740992.0;
  • trunk/Source/JavaScriptCore/runtime/JSObject.cpp

    r107445 r107498  
    133133    JSGlobalData& globalData = exec->globalData();
    134134
    135     if (propertyName == exec->propertyNames().underscoreProto) {
    136         // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
    137         if (!value.isObject() && !value.isNull())
    138             return;
    139 
    140         if (!thisObject->isExtensible()) {
    141             if (slot.isStrictMode())
    142                 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
    143             return;
    144         }
    145            
    146         if (!thisObject->setPrototypeWithCycleCheck(globalData, value))
    147             throwError(exec, createError(exec, "cyclic __proto__ value"));
    148         return;
    149     }
    150 
    151135    // Check if there are any setters or getters in the prototype chain
    152136    JSValue prototype;
    153     for (JSObject* obj = thisObject; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
    154         prototype = obj->prototype();
    155         if (prototype.isNull()) {
    156             if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode())
    157                 throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
    158             return;
    159         }
    160     }
    161    
     137    if (propertyName != exec->propertyNames().underscoreProto) {
     138        for (JSObject* obj = thisObject; !obj->structure()->hasGetterSetterPropertiesExcludingProto(); obj = asObject(prototype)) {
     139            prototype = obj->prototype();
     140            if (prototype.isNull()) {
     141                if (!thisObject->putDirectInternal<PutModePut>(globalData, propertyName, value, 0, slot, getJSFunction(value)) && slot.isStrictMode())
     142                    throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
     143                return;
     144            }
     145        }
     146    }
     147
    162148    unsigned attributes;
    163149    JSCell* specificValue;
     
    216202}
    217203
     204bool JSObject::allowsAccessFrom(JSObject*, ExecState*)
     205{
     206    return true;
     207}
     208
    218209void JSObject::putDirectAccessor(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
    219210{
    220211    ASSERT(value.isGetterSetter() && (attributes & Accessor));
    221     ASSERT(propertyName != globalData.propertyNames->underscoreProto);
    222212
    223213    PutPropertySlot slot;
     
    230220        setStructure(globalData, Structure::attributeChangeTransition(globalData, structure(), propertyName, attributes));
    231221
    232     structure()->setHasGetterSetterProperties(true);
     222    structure()->setHasGetterSetterProperties(propertyName == globalData.propertyNames->underscoreProto);
    233223}
    234224
     
    630620bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
    631621{
    632     // __proto__ is magic; we don't currently support setting it as a regular property.
    633     // Silent filter out calls to set __proto__ at an early stage; pretend all is okay.
    634     if (propertyName == exec->propertyNames().underscoreProto)
    635         return true;
    636 
    637622    // If we have a new property we can just put it on normally
    638623    PropertyDescriptor current;
  • trunk/Source/JavaScriptCore/runtime/JSObject.h

    r107445 r107498  
    105105        JS_EXPORT_PRIVATE static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
    106106        JS_EXPORT_PRIVATE static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
     107        JS_EXPORT_PRIVATE static bool allowsAccessFrom(JSObject*, ExecState*);
    107108
    108109        JS_EXPORT_PRIVATE static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
     
    548549        else
    549550            slot.setValue(this, location->get(), offsetForLocation(location));
    550         return true;
    551     }
    552 
    553     // non-standard Netscape extension
    554     if (propertyName == exec->propertyNames().underscoreProto) {
    555         slot.setValue(prototype());
    556551        return true;
    557552    }
     
    804799    if (UNLIKELY(!isCell())) {
    805800        JSObject* prototype = synthesizePrototype(exec);
    806         if (propertyName == exec->propertyNames().underscoreProto)
    807             return prototype;
    808801        if (!prototype->getPropertySlot(exec, propertyName, slot))
    809802            return jsUndefined();
  • trunk/Source/JavaScriptCore/runtime/JSString.cpp

    r105698 r107498  
    254254    if (thisObject->getStringPropertySlot(exec, propertyName, slot))
    255255        return true;
    256     if (propertyName == exec->propertyNames().underscoreProto) {
    257         slot.setValue(exec->lexicalGlobalObject()->stringPrototype());
    258         return true;
    259     }
    260256    slot.setBase(thisObject);
    261257    JSObject* object;
  • trunk/Source/JavaScriptCore/runtime/JSValue.h

    r106590 r107498  
    235235        char* description();
    236236
     237        JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const;
     238
    237239    private:
    238240        template <class T> JSValue(WriteBarrierBase<T>);
     
    247249        JS_EXPORT_PRIVATE JSObject* toThisObjectSlowCase(ExecState*) const;
    248250
    249         JS_EXPORT_PRIVATE JSObject* synthesizePrototype(ExecState*) const;
    250251        JSObject* synthesizeObject(ExecState*) const;
    251252
  • trunk/Source/JavaScriptCore/runtime/ObjectConstructor.cpp

    r105698 r107498  
    139139    if (!exec->argument(0).isObject())
    140140        return throwVMError(exec, createTypeError(exec, "Requested prototype of a value that is not an object."));
    141        
    142     // This uses JSValue::get() instead of directly accessing the prototype from the object
    143     // (using JSObject::prototype()) in order to allow objects to override the behavior, such
    144     // as returning jsUndefined() for cross-origin access.
    145     return JSValue::encode(exec->argument(0).get(exec, exec->propertyNames().underscoreProto));
     141    JSObject* object = asObject(exec->argument(0));
     142
     143    if (!object->methodTable()->allowsAccessFrom(object, exec))
     144        return JSValue::encode(jsUndefined());
     145
     146    return JSValue::encode(object->prototype());
    146147}
    147148
  • trunk/Source/JavaScriptCore/runtime/Structure.cpp

    r104871 r107498  
    168168    , m_isPinnedPropertyTable(false)
    169169    , m_hasGetterSetterProperties(false)
     170    , m_hasGetterSetterPropertiesExcludingProto(false)
    170171    , m_hasNonEnumerableProperties(false)
    171172    , m_attributesInPrevious(0)
     
    189190    , m_isPinnedPropertyTable(false)
    190191    , m_hasGetterSetterProperties(false)
     192    , m_hasGetterSetterPropertiesExcludingProto(false)
    191193    , m_hasNonEnumerableProperties(false)
    192194    , m_attributesInPrevious(0)
     
    208210    , m_isPinnedPropertyTable(false)
    209211    , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
     212    , m_hasGetterSetterPropertiesExcludingProto(previous->m_hasGetterSetterPropertiesExcludingProto)
    210213    , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
    211214    , m_attributesInPrevious(0)
  • trunk/Source/JavaScriptCore/runtime/Structure.h

    r104900 r107498  
    146146
    147147        bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
    148         void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
     148        bool hasGetterSetterPropertiesExcludingProto() const { return m_hasGetterSetterPropertiesExcludingProto; }
     149        void setHasGetterSetterProperties(bool isProto)
     150        {
     151            m_hasGetterSetterProperties = true;
     152            if (!isProto)
     153                m_hasGetterSetterPropertiesExcludingProto = true;
     154        }
    149155
    150156        bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
     
    283289        bool m_isPinnedPropertyTable : 1;
    284290        bool m_hasGetterSetterProperties : 1;
     291        bool m_hasGetterSetterPropertiesExcludingProto : 1;
    285292        bool m_hasNonEnumerableProperties : 1;
    286293        unsigned m_attributesInPrevious : 7;
  • trunk/Source/WebCore/ChangeLog

    r107497 r107498  
     12012-02-11  Gavin Barraclough  <barraclough@apple.com>
     2
     3        Move special __proto__ property to Object.prototype
     4        https://bugs.webkit.org/show_bug.cgi?id=78409
     5
     6        Reviewed by Oliver Hunt.
     7
     8        Re-implement this as a regular accessor property.  This has three key benefits:
     9        1) It makes it possible for objects to be given properties named __proto__.
     10        2) Object.prototype.__proto__ can be deleted, preventing object prototypes from being changed.
     11        3) This largely removes the magic used the implement __proto__, it can just be made a regular accessor property.
     12
     13        * bindings/js/JSDOMWindowBase.cpp:
     14        (WebCore::JSDOMWindowBase::allowsAccessFrom):
     15        (WebCore):
     16            - expose allowsAccessFrom check to JSC.
     17        * bindings/js/JSDOMWindowBase.h:
     18        (JSDOMWindowBase):
     19            - expose allowsAccessFrom check to JSC.
     20
    1212012-02-11  Benjamin Poulain  <benjamin@webkit.org>
    222
  • trunk/Source/WebCore/bindings/js/JSDOMWindowBase.cpp

    r103083 r107498  
    9393}
    9494
     95bool JSDOMWindowBase::allowsAccessFrom(JSObject* thisObject, ExecState* exec)
     96{
     97    return static_cast<JSDOMWindowBase*>(thisObject)->allowsAccessFrom(exec);
     98}
     99
    95100bool JSDOMWindowBase::supportsProfiling(const JSGlobalObject* object)
    96101{
  • trunk/Source/WebCore/bindings/js/JSDOMWindowBase.h

    r103083 r107498  
    6464        static bool supportsRichSourceInfo(const JSC::JSGlobalObject*);
    6565        static bool shouldInterruptScript(const JSC::JSGlobalObject*);
    66 
     66        static bool allowsAccessFrom(JSC::JSObject*, JSC::ExecState*);
     67       
    6768        bool allowsAccessFrom(JSC::ExecState*) const;
    6869        bool allowsAccessFromNoErrorMessage(JSC::ExecState*) const;
Note: See TracChangeset for help on using the changeset viewer.