blob: 325ea4145d545a877e6e4f15755b185788521b7c [file] [log] [blame]
{#
# Copyright 2016 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#}
{% macro create_interface_object(interface_object_class_name, interface_object_name) -%}
// Class that defines a JS Object representing this interface's Interface Object
// https://www.w3.org/TR/WebIDL/#interface-object
class {{binding_class}}::{{interface_object_class_name}} : public ConstructorBase {
public:
// Get the Interface Object. Will create a new Interface Object if necessary,
// otherwise it will return the cached one.
static JSC::JSObject* GetInstance(JSC::ExecState* exec);
DECLARE_CLASSINFO();
// Needed when JSC::OverridesGetOwnPropertySlot StructureFlag is set
// Must be public so that it can be accessible from getStaticValueSlot<>.
static bool getOwnPropertySlot(JSC::JSCell* cell, JSC::ExecState* exec,
JSC::PropertyName property_name,
JSC::PropertySlot& slot) {
{{interface_object_class_name}}* this_object = JSC::jsCast<{{interface_object_class_name}}*>(cell);
ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
// Same process as JSC::getStaticPropertySlot<>, which is defined in Lookup.h
// Since JSFunction::getOwnPropertySlot is protected, we can't call it from
// the helper function.
const JSC::HashEntry* entry =
GetPropertyTable(exec)->entry(exec, property_name);
if (!entry) // not found, forward to parent
return Base::getOwnPropertySlot(this_object, exec, property_name, slot);
if (entry->attributes() & JSC::Function)
return setUpStaticFunctionSlot(exec, entry, this_object, property_name, slot);
slot.setCacheableCustom(this_object, entry->propertyGetter());
return true;
}
// static override. Needed to support setting a property.
static void put(JSC::JSCell* cell, JSC::ExecState* exec_state,
JSC::PropertyName property_name, JSC::JSValue value,
JSC::PutPropertySlot& slot) {
{{interface_object_class_name}}* this_object = JSC::jsCast<{{interface_object_class_name}}*>(cell);
ASSERT_GC_OBJECT_INHERITS(this_object, &s_info);
bool found_property = JSC::lookupPut<{{interface_object_class_name}}>(
exec_state, property_name, value, GetPropertyTable(exec_state),
this_object, slot.isStrictMode());
DLOG_IF(INFO, !found_property) << "Did not find property named " <<
WTF::String(property_name.publicName()).utf8().data() <<
" to set on interface object for {{binding_class}}";
if (!found_property) {
BaseClass::put(cell, exec_state, property_name, value, slot);
}
}
// static override. This prevents this object from being called as a normal
// function, throwing a TypeError if the user attempts to do so.
static JSC::CallType getCallData(JSC::JSCell*, JSC::CallData&) {
return JSC::CallTypeNone;
}
{% if not constructor %}
// static override. This prevents this object from being called as a
// constructor, throwing a TypeError if the user attempts to do so.
//
// This method is defined when no constructors are defined on the IDL.
static JSC::ConstructType getConstructData(JSC::JSCell*, JSC::ConstructData&) {
return JSC::ConstructTypeNone;
}
{% endif %}
private:
typedef ConstructorBase BaseClass;
static const unsigned StructureFlags =
JSC::ImplementsHasInstance |
JSC::OverridesGetOwnPropertySlot |
BaseClass::StructureFlags;
{{interface_object_class_name}}(JSC::ExecState* exec_state, JSC::JSGlobalObject* global_object, JSC::Structure* structure)
: BaseClass(exec_state, global_object, structure) { }
void finishCreation(JSC::ExecState* exec_state,
JSC::NativeExecutable* native_executable, int length,
const String& name);
static const JSC::HashTable* GetPropertyTable(JSC::ExecState* exec_state);
static const JSC::HashTableValue property_table_values[];
static const JSC::HashTable property_table_prototype;
};
const JSC::HashTableValue {{binding_class}}::{{interface_object_class_name}}::property_table_values[] = {
// static functions will also go here.
{% for attribute in static_attributes %}
{% if attribute.conditional %}
#if defined({{attribute.conditional}})
{% endif %}
{ "{{attribute.idl_name}}",
JSC::DontDelete {{'| JSC::ReadOnly' if attribute.is_read_only}},
reinterpret_cast<intptr_t>(getJS{{attribute.idl_name}}),
{% if attribute.is_read_only %}
0,
{% else %}
reinterpret_cast<intptr_t>(setJS{{attribute.idl_name}}),
{% endif %}
JSC::NoIntrinsic
},
{% if attribute.conditional %}
#endif // defined({{attribute.conditional}})
{% endif %}
{% endfor %}
{% for operation in static_operations %}
{% if operation.conditional %}
#if defined({{operation.conditional}})
{% endif %}
{ "{{operation.idl_name}}",
JSC::DontDelete | JSC::Function,
reinterpret_cast<intptr_t>(staticFunctionJS{{operation.idl_name}}),
static_cast<intptr_t>({{operation.length}}),
JSC::NoIntrinsic
},
{% if operation.conditional %}
#endif // defined({{operation.conditional}})
{% endif %}
{% endfor %}
{% for constant in constants %}
{ "{{constant.idl_name}}",
JSC::DontDelete | JSC::ReadOnly,
reinterpret_cast<intptr_t>(getJS{{constant.idl_name}}),
0,
JSC::NoIntrinsic
},
{% endfor %}
{ 0, 0, 0, 0, static_cast<JSC::Intrinsic>(0) }
}; // {{binding_class}}::{{interface_object_class_name}}::property_table_values
// static
const JSC::HashTable
{{binding_class}}::{{interface_object_class_name}}::property_table_prototype = {
{% set num_properties = constants|length + static_attributes|length + static_operations|length %}
// Sizes will be calculated based on the number of static functions as well.
{{ calculate_jsc_lookup_size(num_properties) }}, // compactSize
{{ calculate_jsc_lookup_size_mask(num_properties) }}, // compactSizeMask
property_table_values,
NULL // table allocated at runtime
}; // {{binding_class}}::{{interface_object_class_name}}::property_table_prototype
// static
const JSC::HashTable*
{{binding_class}}::{{interface_object_class_name}}::GetPropertyTable(
JSC::ExecState* exec_state) {
return ThreadLocalHashTable::GetInstance()->GetHashTable(
{{binding_class}}::{{interface_object_class_name}}::s_classinfo(),
property_table_prototype);
}
const JSC::ClassInfo {{binding_class}}::{{interface_object_class_name}}::s_info = {
"{{interface_name}}Constructor", // className
BaseClass::s_classinfo(), // parentClass
NULL, // static hash-table of properties (not used)
GetPropertyTable, // function pointer to get hash-table of properties
CREATE_METHOD_TABLE({{binding_class}}::{{interface_object_class_name}})
}; // {{binding_class}}::{{interface_object_class_name}}::s_info
void {{binding_class}}::{{interface_object_class_name}}::finishCreation(
JSC::ExecState* exec_state, JSC::NativeExecutable* native_executable,
int length, const String& name) {
BaseClass::finishCreation(exec_state, native_executable, length, name);
ASSERT(inherits(&s_info));
// Add a 'prototype' property whose value is the prototype object.
putDirect(exec_state->globalData(),
exec_state->propertyNames().prototype,
{{binding_class}}::GetPrototype(exec_state->lexicalGlobalObject()),
JSC::DontDelete | JSC::ReadOnly | JSC::DontEnum);
DCHECK(hasOwnProperty(exec_state, JSC::Identifier(exec_state, "prototype")));
}
// static
JSC::JSObject* {{binding_class}}::{{interface_object_class_name}}::GetInstance(
JSC::ExecState* exec_state) {
JSCGlobalObject* global_object =
static_cast<JSCGlobalObject*>(exec_state->lexicalGlobalObject());
ASSERT_GC_OBJECT_INHERITS(global_object, JSCGlobalObject::s_classinfo());
// Try to get the cached interface object, and create a new one if needed.
JSC::JSObject* interface_object = global_object->object_cache()->GetCachedConstructor(&s_info);
if (interface_object == NULL) {
JSC::JSGlobalData& global_data = global_object->globalData();
JSC::JSObject* parent_prototype = global_object->functionPrototype();
JSC::TypeInfo type_info(JSC::ObjectType, StructureFlags);
JSC::Structure* structure = JSC::Structure::create(
global_data,
global_object,
JSC::JSValue(parent_prototype),
type_info,
&s_info);
{% if constructor %}
const int kNumArguments = {{constructor.length}};
JSC::NativeExecutable* executable = global_data.getHostFunction(NULL, &constructorJS{{impl_class}});
{% else %}
const int kNumArguments = 0;
// NativeExecutable must be non-null even if this is not actually callable.
JSC::NativeExecutable* executable = global_data.getHostFunction(NULL, NULL);
{% endif %}
// Create the new interface object.
{{interface_object_class_name}}* new_interface_object =
new (NotNull, JSC::allocateCell<{{interface_object_class_name}}>(global_data.heap))
{{interface_object_class_name}}(exec_state, global_object, structure);
new_interface_object->finishCreation(exec_state, executable, kNumArguments, "{{interface_object_name}}");
// Add the interface object to the cache.
global_object->object_cache()->CacheConstructor(&s_info, new_interface_object);
interface_object = new_interface_object;
}
DCHECK_EQ(global_object->object_cache()->GetCachedConstructor(&s_info), interface_object);
return interface_object;
}
// End of {{binding_class}}::{{interface_object_class_name}} class
{% endmacro %}