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