| {# | |
| # 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 %} |