1/*
2 * Copyright (C) 2015, 2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "JSCustomGetterSetterFunction.h"
28
29#include "CustomGetterSetter.h"
30#include "GetterSetter.h"
31#include "JSCInlines.h"
32#include "JSGlobalObject.h"
33
34namespace JSC {
35
36const ClassInfo JSCustomGetterSetterFunction::s_info = { "Function", &Base::s_info, nullptr, nullptr, CREATE_METHOD_TABLE(JSCustomGetterSetterFunction) };
37
38EncodedJSValue JSC_HOST_CALL JSCustomGetterSetterFunction::customGetterSetterFunctionCall(ExecState* exec)
39{
40 VM& vm = exec->vm();
41 auto scope = DECLARE_THROW_SCOPE(vm);
42
43 JSCustomGetterSetterFunction* customGetterSetterFunction = jsCast<JSCustomGetterSetterFunction*>(exec->jsCallee());
44 CustomGetterSetter* customGetterSetter = customGetterSetterFunction->customGetterSetter();
45 JSValue thisValue = exec->thisValue();
46
47 if (customGetterSetterFunction->isSetter()) {
48 CustomGetterSetter::CustomSetter setter = customGetterSetter->setter();
49 ASSERT(setter);
50 callCustomSetter(exec, setter, true, thisValue, exec->argument(0));
51 return JSValue::encode(jsUndefined());
52 }
53
54 if (customGetterSetter->inherits<DOMAttributeGetterSetter>(vm)) {
55 auto domAttribute = jsCast<DOMAttributeGetterSetter*>(customGetterSetter)->domAttribute();
56 if (!thisValue.inherits(vm, domAttribute.classInfo))
57 return throwVMDOMAttributeGetterTypeError(exec, scope, domAttribute.classInfo, customGetterSetterFunction->propertyName());
58 }
59
60 return customGetterSetter->getter()(exec, JSValue::encode(thisValue), customGetterSetterFunction->propertyName());
61}
62
63JSCustomGetterSetterFunction::JSCustomGetterSetterFunction(VM& vm, JSGlobalObject* globalObject, Structure* structure, const Type type, const PropertyName& propertyName)
64 : Base(vm, globalObject, structure)
65 , m_type(type)
66 , m_propertyName(propertyName)
67{
68}
69
70JSCustomGetterSetterFunction* JSCustomGetterSetterFunction::create(VM& vm, JSGlobalObject* globalObject, CustomGetterSetter* getterSetter, const Type type, const PropertyName& propertyName)
71{
72 ASSERT(type == Type::Getter ? !!getterSetter->getter() : !!getterSetter->setter());
73
74 const char* prefix = (type == Type::Getter) ? "get " : "set ";
75 String name = makeString(prefix, String(propertyName.publicName()));
76
77 NativeExecutable* executable = vm.getHostFunction(customGetterSetterFunctionCall, callHostFunctionAsConstructor, String(propertyName.publicName()));
78
79 Structure* structure = globalObject->customGetterSetterFunctionStructure();
80 JSCustomGetterSetterFunction* function = new (NotNull, allocateCell<JSCustomGetterSetterFunction>(vm.heap)) JSCustomGetterSetterFunction(vm, globalObject, structure, type, propertyName);
81
82 // Can't do this during initialization because getHostFunction might do a GC allocation.
83 function->finishCreation(vm, executable, getterSetter, name);
84 return function;
85}
86
87void JSCustomGetterSetterFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
88{
89 JSCustomGetterSetterFunction* thisObject = jsCast<JSCustomGetterSetterFunction*>(cell);
90 ASSERT_GC_OBJECT_INHERITS(thisObject, info());
91 Base::visitChildren(thisObject, visitor);
92
93 visitor.append(thisObject->m_getterSetter);
94}
95
96void JSCustomGetterSetterFunction::finishCreation(VM& vm, NativeExecutable* executable, CustomGetterSetter* getterSetter, const String& name)
97{
98 Base::finishCreation(vm, executable, isSetter(), name);
99 ASSERT(inherits(vm, info()));
100 ASSERT(getterSetter);
101 m_getterSetter.set(vm, this, getterSetter);
102}
103
104} // namespace JSC
105