blob: 9ce6e7a80b2316f3607c5860f5f5638d03c9e7f6 [file] [log] [blame]
/*
* Copyright (C) 2017 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "JSDOMConvertStrings.h"
namespace WebCore {
// Implementations of the abstract operations defined at
// https://heycam.github.io/webidl/#legacy-platform-object-abstract-ops
enum class OverrideBuiltins {
No,
Yes
};
// An implementation of the 'named property visibility algorithm'
// https://heycam.github.io/webidl/#dfn-named-property-visibility
template<OverrideBuiltins overrideBuiltins, class JSClass>
static bool isVisibleNamedProperty(JSC::ExecState& state, JSClass& thisObject, JSC::PropertyName propertyName)
{
// FIXME: It seems unfortunate that have to do two lookups for the property name,
// one for isSupportedPropertyName and one by the user of this algorithm to access
// that property. It would be nice if we could smuggle the result, or an iterator
// out so the duplicate lookup could be avoided.
// NOTE: While it is not specified, a Symbol can never be a 'supported property
// name' so we check that first.
if (propertyName.isSymbol())
return false;
auto& impl = thisObject.wrapped();
// 1. If P is not a supported property name of O, then return false.
if (!impl.isSupportedPropertyName(propertyNameToString(propertyName)))
return false;
// 2. If O has an own property named P, then return false.
JSC::PropertySlot slot { &thisObject, JSC::PropertySlot::InternalMethodType::VMInquiry };
if (JSC::JSObject::getOwnPropertySlot(&thisObject, &state, propertyName, slot))
return false;
// 3. If O implements an interface that has the [OverrideBuiltins] extended attribute, then return true.
if (overrideBuiltins == OverrideBuiltins::Yes)
return true;
// 4. Initialize prototype to be the value of the internal [[Prototype]] property of O.
// 5. While prototype is not null:
// 1. If prototype is not a named properties object, and prototype has an own property named P, then return false.
// FIXME: Implement checking for 'named properties object'.
// 2. Set prototype to be the value of the internal [[Prototype]] property of prototype.
auto prototype = thisObject.getPrototypeDirect(state.vm());
if (prototype.isObject() && JSC::asObject(prototype)->getPropertySlot(&state, propertyName, slot))
return false;
// 6. Return true.
return true;
}
// An implementation of the 'named property visibility algorithm' augmented to replace the
// 'supported property name' check with direct access to the implementation value returned
// for the property name, via passed in functor. This allows us to avoid two looking up the
// the property name twice; once for 'named property visibility algorithm' check, and then
// again when the value is needed.
template<OverrideBuiltins overrideBuiltins, class JSClass, class Functor>
static auto accessVisibleNamedProperty(JSC::ExecState& state, JSClass& thisObject, JSC::PropertyName propertyName, Functor&& itemAccessor) -> decltype(itemAccessor(thisObject, propertyName))
{
// NOTE: While it is not specified, a Symbol can never be a 'supported property
// name' so we check that first.
if (propertyName.isSymbol())
return WTF::nullopt;
// 1. If P is not a supported property name of O, then return false.
auto result = itemAccessor(thisObject, propertyName);
if (!result)
return WTF::nullopt;
// 2. If O has an own property named P, then return false.
JSC::PropertySlot slot { &thisObject, JSC::PropertySlot::InternalMethodType::VMInquiry };
if (JSC::JSObject::getOwnPropertySlot(&thisObject, &state, propertyName, slot))
return WTF::nullopt;
// 3. If O implements an interface that has the [OverrideBuiltins] extended attribute, then return true.
if (overrideBuiltins == OverrideBuiltins::Yes && !worldForDOMObject(thisObject).shouldDisableOverrideBuiltinsBehavior())
return result;
// 4. Initialize prototype to be the value of the internal [[Prototype]] property of O.
// 5. While prototype is not null:
// 1. If prototype is not a named properties object, and prototype has an own property named P, then return false.
// FIXME: Implement checking for 'named properties object'.
// 2. Set prototype to be the value of the internal [[Prototype]] property of prototype.
auto prototype = thisObject.getPrototypeDirect(state.vm());
if (prototype.isObject() && JSC::asObject(prototype)->getPropertySlot(&state, propertyName, slot))
return WTF::nullopt;
// 6. Return true.
return result;
}
}