From 50bcf89f21c098aa54033733b33cb66c6c56d7ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 12 Apr 2014 22:43:35 +0300 Subject: [PATCH 01/67] Export FUNCTION_TABLE_xxx entries to the global asm object for direct access. See issue #2249. --- emscripten.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/emscripten.py b/emscripten.py index c8122cb9fd61c..3d75335f59e38 100755 --- a/emscripten.py +++ b/emscripten.py @@ -480,6 +480,7 @@ def fix_item(item): asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] + function_tables_arrays = ['FUNCTION_TABLE_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] for sig in last_forwarded_json['Functions']['tables'].iterkeys(): @@ -516,7 +517,7 @@ def fix_item(item): exported_implemented_functions.append('runPostSets') exports = [] if not simple: - for export in exported_implemented_functions + asm_runtime_funcs + function_tables: + for export in exported_implemented_functions + asm_runtime_funcs + function_tables + function_tables_arrays: exports.append("%s: %s" % (export, export)) exports = '{ ' + ', '.join(exports) + ' }' else: @@ -1059,6 +1060,7 @@ def keyfunc(other): asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] + function_tables_arrays = ['FUNCTION_TABLE_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] for sig in last_forwarded_json['Functions']['tables'].iterkeys(): @@ -1095,7 +1097,7 @@ def keyfunc(other): exported_implemented_functions.append('runPostSets') exports = [] if not simple: - for export in exported_implemented_functions + asm_runtime_funcs + function_tables: + for export in exported_implemented_functions + asm_runtime_funcs + function_tables + function_tables_arrays: exports.append("%s: %s" % (export, export)) exports = '{ ' + ', '.join(exports) + ' }' else: From 521216f211165e962664f49be3890e2fc22d8efd Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sat, 12 Apr 2014 21:06:54 -0700 Subject: [PATCH 02/67] checkpoint asm.js-style function lookup by signature string --- src/embind/embind.js | 23 ++++++++++-- system/include/emscripten/bind.h | 64 +++++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 6ec07cd91eccc..232483357fedf 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,4 +1,4 @@ -/*global Module*/ +/*global Module, asm*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64*/ /*global readLatin1String*/ @@ -708,10 +708,27 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp return invokerFunction; } -function __embind_register_function(name, argCount, rawArgTypesAddr, rawInvoker, fn) { +function requireFunction(signature, rawFunction) { + signature = readLatin1String(signature); + var fp; + if (typeof FUNCTION_TABLE === "undefined") { + // asm.js style + fp = asm['FUNCTION_TABLE_' + signature](rawFunction); + } else { + fp = FUNCTION_TABLE[rawFunction]; + } + + if (typeof fp !== "function") { + throwBindingError("unknown function pointer with signature " + signature + ": " + rawFunction); + } + return fp; +} + +function __embind_register_function(name, argCount, rawArgTypesAddr, signature, rawInvoker, fn) { var argTypes = heap32VectorToArray(argCount, rawArgTypesAddr); name = readLatin1String(name); - rawInvoker = FUNCTION_TABLE[rawInvoker]; + + rawInvoker = requireFunction(signature, rawInvoker); exposePublicSymbol(name, function() { throwUnboundTypeError('Cannot call ' + name + ' due to unbound types', argTypes); diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 872f279b610db..8a8b7d69ace8f 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -20,6 +20,8 @@ namespace emscripten { namespace internal { typedef long GenericEnumValue; + typedef void (*GenericFunction)(); + // Implemented in JavaScript. Don't call these directly. extern "C" { void _embind_fatal_error( @@ -70,6 +72,7 @@ namespace emscripten { const char* name, unsigned argCount, TYPEID argTypes[], + const char* signature, GenericFunction invoker, GenericFunction function); @@ -290,6 +293,63 @@ namespace emscripten { }; } + //////////////////////////////////////////////////////////////////////////////// + // SignatureCode, SignatureString + //////////////////////////////////////////////////////////////////////////////// + + namespace internal { + template + struct SignatureCode { + static constexpr char get() { + return 'i'; + } + }; + + template<> + struct SignatureCode { + static constexpr char get() { + return 'v'; + } + }; + + template<> + struct SignatureCode { + static constexpr char get() { + return 'd'; + } + }; + + template<> + struct SignatureCode { + static constexpr char get() { + return 'd'; + } + }; + + template + struct SignatureString; + + template<> + struct SignatureString<> { + char c = 0; + }; + + template + struct SignatureString { + constexpr SignatureString() + : c(SignatureCode::get()) + {} + char c; + SignatureString rest; + }; + + template + const char* getSignature(Return (*)(Args...)) { + static constexpr SignatureString sig; + return &sig.c; + } + } + //////////////////////////////////////////////////////////////////////////////// // FUNCTIONS //////////////////////////////////////////////////////////////////////////////// @@ -302,11 +362,13 @@ namespace emscripten { void function(const char* name, ReturnType (*fn)(Args...), Policies...) { using namespace internal; typename WithPolicies::template ArgTypeList args; + auto invoker = &Invoker::invoke; _embind_register_function( name, args.count, args.types, - reinterpret_cast(&Invoker::invoke), + getSignature(invoker), + reinterpret_cast(invoker), reinterpret_cast(fn)); } From 80731b5e8522feb819edbb439b76c72df1bf800d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sat, 12 Apr 2014 21:53:09 -0700 Subject: [PATCH 03/67] craftInvokerFunction never seems to use classType --- src/embind/embind.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 232483357fedf..e2de9734b5209 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -622,10 +622,6 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp var isClassMethodFunc = (argTypes[1] !== null && classType !== null); - if (!isClassMethodFunc && !FUNCTION_TABLE[cppTargetFunc]) { - throwBindingError('Global function '+humanName+' is not defined!'); - } - // Free functions with signature "void function()" do not need an invoker that marshalls between wire types. // TODO: This omits argument count check - enable only at -O3 or similar. // if (ENABLE_UNSAFE_OPTS && argCount == 2 && argTypes[0].name == "void" && !isClassMethodFunc) { @@ -662,8 +658,8 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp } var dtorStack = needsDestructorStack ? "destructors" : "null"; - var args1 = ["throwBindingError", "classType", "invoker", "fn", "runDestructors", "retType", "classParam"]; - var args2 = [throwBindingError, classType, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; + var args1 = ["throwBindingError", "invoker", "fn", "runDestructors", "retType", "classParam"]; + var args2 = [throwBindingError, cppInvokerFunc, cppTargetFunc, runDestructors, argTypes[0], argTypes[1]]; if (isClassMethodFunc) { invokerFnBody += "var thisWired = classParam.toWireType("+dtorStack+", this);\n"; @@ -713,7 +709,7 @@ function requireFunction(signature, rawFunction) { var fp; if (typeof FUNCTION_TABLE === "undefined") { // asm.js style - fp = asm['FUNCTION_TABLE_' + signature](rawFunction); + fp = asm['FUNCTION_TABLE_' + signature][rawFunction]; } else { fp = FUNCTION_TABLE[rawFunction]; } From c4b76efed701ba8a2e6fb66a5c6de9faa938b672 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sat, 12 Apr 2014 23:10:50 -0700 Subject: [PATCH 04/67] value array and value object signatures --- src/embind/embind.js | 24 +++++--- system/include/emscripten/bind.h | 98 ++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 33 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index e2de9734b5209..2a95c6b1e4e47 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -739,11 +739,11 @@ function __embind_register_function(name, argCount, rawArgTypesAddr, signature, var tupleRegistrations = {}; -function __embind_register_value_array(rawType, name, rawConstructor, rawDestructor) { +function __embind_register_value_array(rawType, name, constructorSignature, rawConstructor, destructorSignature, rawDestructor) { tupleRegistrations[rawType] = { name: readLatin1String(name), - rawConstructor: FUNCTION_TABLE[rawConstructor], - rawDestructor: FUNCTION_TABLE[rawDestructor], + rawConstructor: requireFunction(constructorSignature, rawConstructor), + rawDestructor: requireFunction(destructorSignature, rawDestructor), elements: [], }; } @@ -751,18 +751,20 @@ function __embind_register_value_array(rawType, name, rawConstructor, rawDestruc function __embind_register_value_array_element( rawTupleType, getterReturnType, + getterSignature, getter, getterContext, setterArgumentType, + setterSignature, setter, setterContext ) { tupleRegistrations[rawTupleType].elements.push({ getterReturnType: getterReturnType, - getter: FUNCTION_TABLE[getter], + getter: requireFunction(getterSignature, getter), getterContext: getterContext, setterArgumentType: setterArgumentType, - setter: FUNCTION_TABLE[setter], + setter: requireFunction(setterSignature, setter), setterContext: setterContext, }); } @@ -831,13 +833,15 @@ var structRegistrations = {}; function __embind_register_value_object( rawType, name, + constructorSignature, rawConstructor, + destructorSignature, rawDestructor ) { structRegistrations[rawType] = { name: readLatin1String(name), - rawConstructor: FUNCTION_TABLE[rawConstructor], - rawDestructor: FUNCTION_TABLE[rawDestructor], + rawConstructor: requireFunction(constructorSignature, rawConstructor), + rawDestructor: requireFunction(destructorSignature, rawDestructor), fields: [], }; } @@ -846,19 +850,21 @@ function __embind_register_value_object_field( structType, fieldName, getterReturnType, + getterSignature, getter, getterContext, setterArgumentType, + setterSignature, setter, setterContext ) { structRegistrations[structType].fields.push({ fieldName: readLatin1String(fieldName), getterReturnType: getterReturnType, - getter: FUNCTION_TABLE[getter], + getter: requireFunction(getterSignature, getter), getterContext: getterContext, setterArgumentType: setterArgumentType, - setter: FUNCTION_TABLE[setter], + setter: requireFunction(setterSignature, setter), setterContext: setterContext, }); } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 8a8b7d69ace8f..e86e75361e37d 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -79,15 +79,19 @@ namespace emscripten { void _embind_register_value_array( TYPEID tupleType, const char* name, + const char* constructorSignature, GenericFunction constructor, + const char* destructorSignature, GenericFunction destructor); void _embind_register_value_array_element( TYPEID tupleType, TYPEID getterReturnType, + const char* getterSignature, GenericFunction getter, void* getterContext, TYPEID setterArgumentType, + const char* setterSignature, GenericFunction setter, void* setterContext); @@ -96,16 +100,20 @@ namespace emscripten { void _embind_register_value_object( TYPEID structType, const char* fieldName, + const char* constructorSignature, GenericFunction constructor, + const char* destructorSignature, GenericFunction destructor); void _embind_register_value_object_field( TYPEID structType, const char* fieldName, TYPEID getterReturnType, + const char* getterSignature, GenericFunction getter, void* getterContext, TYPEID setterArgumentType, + const char* setterSignature, GenericFunction setter, void* setterContext); @@ -604,11 +612,16 @@ namespace emscripten { value_array(const char* name) { using namespace internal; + + auto constructor = &raw_constructor; + auto destructor = &raw_destructor; _embind_register_value_array( TypeID::get(), name, - reinterpret_cast(&raw_constructor), - reinterpret_cast(&raw_destructor)); + getSignature(constructor), + reinterpret_cast(constructor), + getSignature(destructor), + reinterpret_cast(destructor)); } ~value_array() { @@ -619,17 +632,21 @@ namespace emscripten { template value_array& element(ElementType InstanceType::*field) { using namespace internal; + + auto getter = &MemberAccess + ::template getWire; + auto setter = &MemberAccess + ::template setWire; + _embind_register_value_array_element( TypeID::get(), TypeID::get(), - reinterpret_cast( - &MemberAccess - ::template getWire), + getSignature(getter), + reinterpret_cast(getter), getContext(field), TypeID::get(), - reinterpret_cast( - &MemberAccess - ::template setWire), + getSignature(setter), + reinterpret_cast(setter), getContext(field)); return *this; } @@ -639,13 +656,19 @@ namespace emscripten { using namespace internal; typedef GetterPolicy GP; typedef SetterPolicy SP; + + auto g = &GP::template get; + auto s = &SP::template set; + _embind_register_value_array_element( TypeID::get(), TypeID::get(), - reinterpret_cast(&GP::template get), + getSignature(g), + reinterpret_cast(g), GP::getContext(getter), TypeID::get(), - reinterpret_cast(&SP::template set), + getSignature(s), + reinterpret_cast(s), SP::getContext(setter)); return *this; } @@ -655,13 +678,18 @@ namespace emscripten { using namespace internal; ClassType* null = 0; typedef typename std::remove_reference::type ElementType; + auto getter = &internal::get_by_index; + auto setter = &internal::set_by_index; + _embind_register_value_array_element( TypeID::get(), TypeID::get(), - reinterpret_cast(&internal::get_by_index), + getSignature(getter), + reinterpret_cast(getter), reinterpret_cast(Index), TypeID::get(), - reinterpret_cast(&internal::set_by_index), + getSignature(setter), + reinterpret_cast(setter), reinterpret_cast(Index)); return *this; } @@ -678,11 +706,17 @@ namespace emscripten { value_object(const char* name) { using namespace internal; + + auto ctor = &raw_constructor; + auto dtor = &raw_destructor; + _embind_register_value_object( TypeID::get(), name, - reinterpret_cast(&raw_constructor), - reinterpret_cast(&raw_destructor)); + getSignature(ctor), + reinterpret_cast(ctor), + getSignature(dtor), + reinterpret_cast(dtor)); } ~value_object() { @@ -692,18 +726,22 @@ namespace emscripten { template value_object& field(const char* fieldName, FieldType InstanceType::*field) { using namespace internal; + + auto getter = &MemberAccess + ::template getWire; + auto setter = &MemberAccess + ::template setWire; + _embind_register_value_object_field( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast( - &MemberAccess - ::template getWire), + getSignature(getter), + reinterpret_cast(getter), getContext(field), TypeID::get(), - reinterpret_cast( - &MemberAccess - ::template setWire), + getSignature(setter), + reinterpret_cast(setter), getContext(field)); return *this; } @@ -717,14 +755,20 @@ namespace emscripten { using namespace internal; typedef GetterPolicy GP; typedef SetterPolicy SP; + + auto g = &GP::template get; + auto s = &SP::template set; + _embind_register_value_object_field( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&GP::template get), + getSignature(g), + reinterpret_cast(g), GP::getContext(getter), TypeID::get(), - reinterpret_cast(&SP::template set), + getSignature(s), + reinterpret_cast(s), SP::getContext(setter)); return *this; } @@ -734,14 +778,20 @@ namespace emscripten { using namespace internal; ClassType* null = 0; typedef typename std::remove_reference::type ElementType; + + auto getter = &internal::get_by_index; + auto setter = &internal::set_by_index; + _embind_register_value_object_field( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&internal::get_by_index), + getSignature(getter), + reinterpret_cast(getter), reinterpret_cast(Index), TypeID::get(), - reinterpret_cast(&internal::set_by_index), + getSignature(setter), + reinterpret_cast(setter), reinterpret_cast(Index)); return *this; } From 7e19fc2e5bfba9475d1d11a8ed65c2772da02e8d Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sun, 13 Apr 2014 14:45:21 -0700 Subject: [PATCH 05/67] class and enum signatures --- src/embind/embind.js | 43 +++++++--- system/include/emscripten/bind.h | 143 ++++++++++++++++++++++--------- 2 files changed, 132 insertions(+), 54 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 2a95c6b1e4e47..124892e32f9c8 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1343,17 +1343,25 @@ function __embind_register_class( rawPointerType, rawConstPointerType, baseClassRawType, + getActualTypeSignature, getActualType, + upcastSignature, upcast, + downcastSignature, downcast, name, + destructorSignature, rawDestructor ) { name = readLatin1String(name); - rawDestructor = FUNCTION_TABLE[rawDestructor]; - getActualType = FUNCTION_TABLE[getActualType]; - upcast = FUNCTION_TABLE[upcast]; - downcast = FUNCTION_TABLE[downcast]; + getActualType = requireFunction(getActualTypeSignature, getActualType); + if (upcast) { + upcast = requireFunction(upcastSignature, upcast); + } + if (downcast) { + downcast = requireFunction(downcastSignature, downcast); + } + rawDestructor = requireFunction(destructorSignature, rawDestructor); var legalFunctionName = makeLegalFunctionName(name); exposePublicSymbol(legalFunctionName, function() { @@ -1443,11 +1451,12 @@ function __embind_register_class_constructor( rawClassType, argCount, rawArgTypesAddr, + invokerSignature, invoker, rawConstructor ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); - invoker = FUNCTION_TABLE[invoker]; + invoker = requireFunction(invokerSignature, invoker); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; @@ -1532,12 +1541,13 @@ function __embind_register_class_function( methodName, argCount, rawArgTypesAddr, // [ReturnType, ThisType, Args...] + invokerSignature, rawInvoker, context ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = readLatin1String(methodName); - rawInvoker = FUNCTION_TABLE[rawInvoker]; + rawInvoker = requireFunction(invokerSignature, rawInvoker); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; @@ -1583,12 +1593,13 @@ function __embind_register_class_class_function( methodName, argCount, rawArgTypesAddr, + invokerSignature, rawInvoker, fn ) { var rawArgTypes = heap32VectorToArray(argCount, rawArgTypesAddr); methodName = readLatin1String(methodName); - rawInvoker = FUNCTION_TABLE[rawInvoker]; + rawInvoker = requireFunction(invokerSignature, rawInvoker); whenDependentTypesAreResolved([], [rawClassType], function(classType) { classType = classType[0]; var humanName = classType.name + '.' + methodName; @@ -1628,14 +1639,16 @@ function __embind_register_class_property( classType, fieldName, getterReturnType, + getterSignature, getter, getterContext, setterArgumentType, + setterSignature, setter, setterContext ) { fieldName = readLatin1String(fieldName); - getter = FUNCTION_TABLE[getter]; + getter = requireFunction(getterSignature, getter); whenDependentTypesAreResolved([], [classType], function(classType) { classType = classType[0]; @@ -1673,7 +1686,7 @@ function __embind_register_class_property( }; if (setter) { - setter = FUNCTION_TABLE[setter]; + setter = requireFunction(setterSignature, setter); var setterArgumentType = types[1]; desc.set = function(v) { var ptr = validateThis(this, classType, humanName + ' setter'); @@ -1708,16 +1721,20 @@ function __embind_register_smart_ptr( rawPointeeType, name, sharingPolicy, + getPointeeSignature, rawGetPointee, + constructorSignature, rawConstructor, + shareSignature, rawShare, + destructorSignature, rawDestructor ) { name = readLatin1String(name); - rawGetPointee = FUNCTION_TABLE[rawGetPointee]; - rawConstructor = FUNCTION_TABLE[rawConstructor]; - rawShare = FUNCTION_TABLE[rawShare]; - rawDestructor = FUNCTION_TABLE[rawDestructor]; + rawGetPointee = requireFunction(getPointeeSignature, rawGetPointee); + rawConstructor = requireFunction(constructorSignature, rawConstructor); + rawShare = requireFunction(shareSignature, rawShare); + rawDestructor = requireFunction(destructorSignature, rawDestructor); whenDependentTypesAreResolved([rawType], [rawPointeeType], function(pointeeType) { pointeeType = pointeeType[0]; diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index e86e75361e37d..29e6a56eac757 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -119,31 +119,26 @@ namespace emscripten { void _embind_finalize_value_object(TYPEID structType); - void _embind_register_smart_ptr( - TYPEID pointerType, - TYPEID pointeeType, - const char* pointerName, - sharing_policy sharingPolicy, - GenericFunction getPointee, - GenericFunction constructor, - GenericFunction share, - GenericFunction destructor); - void _embind_register_class( TYPEID classType, TYPEID pointerType, TYPEID constPointerType, TYPEID baseClassType, + const char* getActualTypeSignature, GenericFunction getActualType, + const char* upcastSignature, GenericFunction upcast, + const char* downcastSignature, GenericFunction downcast, const char* className, + const char* destructorSignature, GenericFunction destructor); void _embind_register_class_constructor( TYPEID classType, unsigned argCount, TYPEID argTypes[], + const char* invokerSignature, GenericFunction invoker, GenericFunction constructor); @@ -152,6 +147,7 @@ namespace emscripten { const char* methodName, unsigned argCount, TYPEID argTypes[], + const char* invokerSignature, GenericFunction invoker, void* context); @@ -159,9 +155,11 @@ namespace emscripten { TYPEID classType, const char* fieldName, TYPEID getterReturnType, + const char* getterSignature, GenericFunction getter, void* getterContext, TYPEID setterArgumentType, + const char* setterSignature, GenericFunction setter, void* setterContext); @@ -170,6 +168,7 @@ namespace emscripten { const char* methodName, unsigned argCount, TYPEID argTypes[], + const char* invokerSignature, GenericFunction invoker, GenericFunction method); @@ -179,17 +178,25 @@ namespace emscripten { size_t size, bool isSigned); + void _embind_register_smart_ptr( + TYPEID pointerType, + TYPEID pointeeType, + const char* pointerName, + sharing_policy sharingPolicy, + const char* getPointeeSignature, + GenericFunction getPointee, + const char* constructorSignature, + GenericFunction constructor, + const char* shareSignature, + GenericFunction share, + const char* destructorSignature, + GenericFunction destructor); + void _embind_register_enum_value( TYPEID enumType, const char* valueName, GenericEnumValue value); - void _embind_register_interface( - TYPEID interfaceType, - const char* name, - GenericFunction constructor, - GenericFunction destructor); - void _embind_register_constant( const char* name, TYPEID constantType, @@ -944,13 +951,19 @@ namespace emscripten { } template - static internal::GenericFunction getUpcaster() { - return reinterpret_cast(&convertPointer); + using Upcaster = BaseClass* (*)(ClassType*); + + template + using Downcaster = ClassType* (*)(BaseClass*); + + template + static Upcaster getUpcaster() { + return &convertPointer; } template - static internal::GenericFunction getDowncaster() { - return reinterpret_cast(&convertPointer); + static Downcaster getDowncaster() { + return &convertPointer; } template @@ -989,16 +1002,25 @@ namespace emscripten { BaseSpecifier::template verify(); + auto _getActualType = &getActualType; + auto upcast = BaseSpecifier::template getUpcaster(); + auto downcast = BaseSpecifier::template getDowncaster(); + auto destructor = &raw_destructor; + _embind_register_class( TypeID::get(), TypeID>::get(), TypeID>::get(), BaseSpecifier::get(), - reinterpret_cast(&getActualType), - BaseSpecifier::template getUpcaster(), - BaseSpecifier::template getDowncaster(), + getSignature(_getActualType), + reinterpret_cast(_getActualType), + getSignature(upcast), + reinterpret_cast(upcast), + getSignature(downcast), + reinterpret_cast(downcast), name, - reinterpret_cast(&raw_destructor)); + getSignature(destructor), + reinterpret_cast(destructor)); } template @@ -1010,15 +1032,24 @@ namespace emscripten { static_assert(std::is_same::type>::value, "smart pointer must point to this class"); + auto get = &PointerTrait::get; + auto construct_null = &PointerTrait::construct_null; + auto share = &PointerTrait::share; + auto destructor = &raw_destructor; + _embind_register_smart_ptr( TypeID::get(), TypeID::get(), typeid(PointerType).name(), PointerTrait::get_sharing_policy(), - reinterpret_cast(&PointerTrait::get), - reinterpret_cast(&PointerTrait::construct_null), - reinterpret_cast(&PointerTrait::share), - reinterpret_cast(&raw_destructor)); + getSignature(get), + reinterpret_cast(get), + getSignature(construct_null), + reinterpret_cast(construct_null), + getSignature(share), + reinterpret_cast(share), + getSignature(destructor), + reinterpret_cast(destructor)); return *this; }; @@ -1035,11 +1066,13 @@ namespace emscripten { // TODO: allows all raw pointers... policies need a rethink typename WithPolicies::template ArgTypeList args; + auto invoke = &Invoker::invoke; _embind_register_class_constructor( TypeID::get(), args.count, args.types, - reinterpret_cast(&Invoker::invoke), + getSignature(invoke), + reinterpret_cast(invoke), reinterpret_cast(factory)); return *this; } @@ -1051,11 +1084,13 @@ namespace emscripten { smart_ptr(); typename WithPolicies::template ArgTypeList args; + auto invoke = &Invoker::invoke; _embind_register_class_constructor( TypeID::get(), args.count, args.types, - reinterpret_cast(&Invoker::invoke), + getSignature(invoke), + reinterpret_cast(invoke), reinterpret_cast(factory)); return *this; } @@ -1078,13 +1113,16 @@ namespace emscripten { EMSCRIPTEN_ALWAYS_INLINE const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...), Policies...) const { using namespace internal; + auto invoker = &MethodInvoker::invoke; + typename WithPolicies::template ArgTypeList, Args...> args; _embind_register_class_function( TypeID::get(), methodName, args.count, args.types, - reinterpret_cast(&MethodInvoker::invoke), + getSignature(invoker), + reinterpret_cast(invoker), getContext(memberFunction)); return *this; } @@ -1093,13 +1131,16 @@ namespace emscripten { EMSCRIPTEN_ALWAYS_INLINE const class_& function(const char* methodName, ReturnType (ClassType::*memberFunction)(Args...) const, Policies...) const { using namespace internal; + auto invoker = &MethodInvoker::invoke; + typename WithPolicies::template ArgTypeList, Args...> args; _embind_register_class_function( TypeID::get(), methodName, args.count, args.types, - reinterpret_cast(&MethodInvoker::invoke), + getSignature(invoker), + reinterpret_cast(invoker), getContext(memberFunction)); return *this; } @@ -1109,12 +1150,14 @@ namespace emscripten { using namespace internal; typename WithPolicies::template ArgTypeList args; + auto invoke = &FunctionInvoker::invoke; _embind_register_class_function( TypeID::get(), methodName, args.count, args.types, - reinterpret_cast(&FunctionInvoker::invoke), + getSignature(invoke), + reinterpret_cast(invoke), getContext(function)); return *this; } @@ -1122,15 +1165,18 @@ namespace emscripten { template::value>::type> EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, const FieldType ClassType::*field) const { using namespace internal; - + + auto getter = &MemberAccess::template getWire; _embind_register_class_property( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&MemberAccess::template getWire), + getSignature(getter), + reinterpret_cast(getter), getContext(field), 0, 0, + 0, 0); return *this; } @@ -1139,14 +1185,18 @@ namespace emscripten { EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, FieldType ClassType::*field) const { using namespace internal; + auto getter = &MemberAccess::template getWire; + auto setter = &MemberAccess::template setWire; _embind_register_class_property( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&MemberAccess::template getWire), + getSignature(getter), + reinterpret_cast(getter), getContext(field), TypeID::get(), - reinterpret_cast(&MemberAccess::template setWire), + getSignature(setter), + reinterpret_cast(setter), getContext(field)); return *this; } @@ -1155,14 +1205,17 @@ namespace emscripten { EMSCRIPTEN_ALWAYS_INLINE const class_& property(const char* fieldName, Getter getter) const { using namespace internal; typedef GetterPolicy GP; + auto gter = &GP::template get; _embind_register_class_property( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&GP::template get), + getSignature(gter), + reinterpret_cast(gter), GP::getContext(getter), 0, 0, + 0, 0); return *this; } @@ -1172,14 +1225,20 @@ namespace emscripten { using namespace internal; typedef GetterPolicy GP; typedef SetterPolicy SP; + + auto gter = &GP::template get; + auto ster = &SP::template set; + _embind_register_class_property( TypeID::get(), fieldName, TypeID::get(), - reinterpret_cast(&GP::template get), + getSignature(gter), + reinterpret_cast(gter), GP::getContext(getter), TypeID::get(), - reinterpret_cast(&SP::template set), + getSignature(ster), + reinterpret_cast(ster), SP::getContext(setter)); return *this; } @@ -1189,12 +1248,14 @@ namespace emscripten { using namespace internal; typename WithPolicies::template ArgTypeList args; + auto invoke = &internal::Invoker::invoke; _embind_register_class_class_function( TypeID::get(), methodName, args.count, args.types, - reinterpret_cast(&internal::Invoker::invoke), + getSignature(invoke), + reinterpret_cast(invoke), reinterpret_cast(classMethod)); return *this; } From ef5c2dfb219d6fcb0c5604d8cd25732c28a83e29 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sun, 13 Apr 2014 09:28:41 -0700 Subject: [PATCH 06/67] enable asm.js when using embind --- emcc | 6 ------ 1 file changed, 6 deletions(-) diff --git a/emcc b/emcc index c8e1814b2a9fe..47dbc60d8536f 100755 --- a/emcc +++ b/emcc @@ -1224,11 +1224,6 @@ try: value = value.replace('\\\\', '/').replace('\\', '/') # Convert backslash paths to forward slashes on Windows as well, since the JS compiler otherwise needs the backslashes escaped (alternative is to escape all input paths passing to JS, which feels clumsier to read) exec('shared.Settings.' + key + ' = ' + value) - # Apply effects from settings - if bind and shared.Settings.ASM_JS: - logging.warning('disabling asm.js since embind is not ready for it yet') - shared.Settings.ASM_JS = 0 - fastcomp = os.environ.get('EMCC_FAST_COMPILER') != '0' if fastcomp: @@ -1245,7 +1240,6 @@ try: assert shared.Settings.TARGET_ASMJS_UNKNOWN_EMSCRIPTEN == 1, 'fastcomp requires asmjs-unknown-emscripten' assert shared.Settings.USE_TYPED_ARRAYS == 2, 'fastcomp assumes ta2' assert not split_js_file, '--split-js is deprecated and not supported in fastcomp' - assert not bind, 'embind not supported in fastcomp yet' assert shared.Settings.MAX_SETJMPS == 20, 'changing MAX_SETJMPS is not supported in fastcomp yet' assert shared.Settings.INIT_HEAP == 0, 'HEAP_INIT is not supported in fastcomp (and should never be needed except for debugging)' assert not shared.Settings.RUNTIME_TYPE_INFO, 'RUNTIME_TYPE_INFO is not supported in fastcomp' From 2ad10704eb9102b4f7781528b16c508f3e5c3410 Mon Sep 17 00:00:00 2001 From: Usagi Ito Date: Wed, 16 Apr 2014 11:58:39 +0900 Subject: [PATCH 07/67] fix SDL_GetKeyboardState not based on scanCode bug --- src/library_sdl.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/library_sdl.js b/src/library_sdl.js index cadc3aeeebdd3..0704dbab8ae96 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -539,8 +539,11 @@ var LibrarySDL = { } else { code = SDL.keyCodes[event.keyCode] || event.keyCode; } + + var scan = code & ~(1 << 10); + scan = SDL.scanCodes[scan] || scan; - {{{ makeSetValue('SDL.keyboardState', 'code', 'down', 'i8') }}}; + {{{ makeSetValue('SDL.keyboardState', 'scan', 'down', 'i8') }}}; // TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED SDL.modState = ({{{ makeGetValue('SDL.keyboardState', '1248', 'i8') }}} ? 0x0040 | 0x0080 : 0) | // KMOD_LCTRL & KMOD_RCTRL ({{{ makeGetValue('SDL.keyboardState', '1249', 'i8') }}} ? 0x0001 | 0x0002 : 0) | // KMOD_LSHIFT & KMOD_RSHIFT From 11dfeed10d0fe74d9c47fd0396b87b99f7dde0dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 16 Apr 2014 15:15:47 +0300 Subject: [PATCH 08/67] Better standards-compliant fix for browser.test_sdl_touch that works on Chrome as well. --- tests/sdl_touch.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/sdl_touch.c b/tests/sdl_touch.c index f6a8834baf78c..dc315c580131c 100644 --- a/tests/sdl_touch.c +++ b/tests/sdl_touch.c @@ -67,8 +67,8 @@ int main() { Module['canvas'].dispatchEvent(event); } // Pass test coordinates in canvas element coordinate frame. - var x = Module['canvas'].getBoundingClientRect().x; - var y = Module['canvas'].getBoundingClientRect().y; + var x = Module['canvas'].getBoundingClientRect().left; + var y = Module['canvas'].getBoundingClientRect().top; sendEvent('touchstart', { touches: [ { pageX: x+300, pageY: y+225, deviceID: 1, identifier: 1, force: 1 } ] }); sendEvent('touchmove', { touches: [ { pageX: x+400, pageY: y+225, deviceID: 1, identifier: 1, force: 1 } ] }); sendEvent('touchend', { changedTouches: [ { pageX: x+400, pageY: y+225, deviceID: 1, identifier: 1, force: 1 } ] }); From 2c0a4c6ad5c08c03f0c3180346e52326d6f143b9 Mon Sep 17 00:00:00 2001 From: Usagi Ito Date: Wed, 16 Apr 2014 21:26:30 +0900 Subject: [PATCH 09/67] add myself --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 6c6b3f2761b91..791851c2dfa86 100644 --- a/AUTHORS +++ b/AUTHORS @@ -126,3 +126,4 @@ a license to everyone to use it as detailed in LICENSE.) * Jack A. Arrington * Richard Janicek * Joel Croteau +* Usagi Ito From 0f8f1e94e02ead602699c816794d238e642ec1ca Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 16 Apr 2014 14:12:00 -0700 Subject: [PATCH 10/67] optimize multiple shape to contain a map based on ids, not blocks, so we re-merge split nodes early --- src/relooper/Relooper.cpp | 24 ++++++++++++------------ src/relooper/Relooper.h | 7 ++++--- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index 780a6d5930f3e..c396e990d794d 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -243,7 +243,7 @@ void Block::Render(bool InLoop) { Details = ProcessedBranchesOut[DefaultTarget]; } bool SetCurrLabel = (SetLabel && Target->IsCheckedMultipleEntry) || ForceSetLabel; - bool HasFusedContent = Fused && contains(Fused->InnerMap, Target); + bool HasFusedContent = Fused && contains(Fused->InnerMap, Target->Id); bool HasContent = SetCurrLabel || Details->Type != Branch::Direct || HasFusedContent || Details->Code; if (iter != ProcessedBranchesOut.end()) { // If there is nothing to show in this branch, omit the condition @@ -286,7 +286,7 @@ void Block::Render(bool InLoop) { if (!First) Indenter::Indent(); Details->Render(Target, SetCurrLabel); if (HasFusedContent) { - Fused->InnerMap.find(Target)->second->Render(InLoop); + Fused->InnerMap.find(Target->Id)->second->Render(InLoop); } else if (Details->Type == Branch::Nested) { // Nest the parent content here, and remove it from showing up afterwards as Next assert(Parent->Next); @@ -335,14 +335,14 @@ void MultipleShape::Render(bool InLoop) { // We know that blocks with the same Id were split from the same source, so their contents are identical and they are logically the same, so re-merge them here typedef std::map IdShapeMap; IdShapeMap IdMap; - for (BlockShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { - int Id = iter->first->Id; + for (IdShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { + int Id = iter->first; IdShapeMap::iterator Test = IdMap.find(Id); if (Test != IdMap.end()) { assert(Shape::IsSimple(iter->second) && Shape::IsSimple(Test->second)); // we can only merge simple blocks, something horrible has gone wrong if we see anything else continue; } - IdMap[iter->first->Id] = iter->second; + IdMap[iter->first] = iter->second; } bool First = true; @@ -853,7 +853,7 @@ void Relooper::Calculate(Block *Entry) { iter = Next; // increment carefully because Solipsize can remove us } } - Multiple->InnerMap[CurrEntry] = Process(CurrBlocks, CurrEntries, NULL); + Multiple->InnerMap[CurrEntry->Id] = Process(CurrBlocks, CurrEntries, NULL); // If we are not fused, then our entries will actually be checked if (!Fused) { CurrEntry->IsCheckedMultipleEntry = true; @@ -1021,7 +1021,7 @@ void Relooper::Calculate(Block *Entry) { PostOptimizer(Relooper *ParentInit) : Parent(ParentInit), Closure(NULL) {} #define RECURSE_Multiple(shape, func) \ - for (BlockShapeMap::iterator iter = shape->InnerMap.begin(); iter != shape->InnerMap.end(); iter++) { \ + for (IdShapeMap::iterator iter = shape->InnerMap.begin(); iter != shape->InnerMap.end(); iter++) { \ func(iter->second); \ } #define RECURSE_Loop(shape, func) \ @@ -1042,7 +1042,7 @@ void Relooper::Calculate(Block *Entry) { SHAPE_SWITCH(S, { Out.insert(Simple->Inner); }, { - for (BlockShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { + for (IdShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { FollowNaturalFlow(iter->second, Out); } FollowNaturalFlow(Multiple->Next, Out); @@ -1061,7 +1061,7 @@ void Relooper::Calculate(Block *Entry) { SHAPE_SWITCH(Root, { }, { - for (BlockShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { + for (IdShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { FindNaturals(iter->second, Root->Natural); } }, { @@ -1142,7 +1142,7 @@ void Relooper::Calculate(Block *Entry) { } } }, { - for (BlockShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { + for (IdShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { RemoveUnneededFlows(iter->second, Multiple->Next, Multiple->NeedLoop ? NULL : LastLoop); } Next = Multiple->Next; @@ -1290,8 +1290,8 @@ void Debugging::Dump(Shape *S, const char *prefix) { printf("<< Simple with block %d\n", Simple->Inner->Id); }, { printf("<< Multiple\n"); - for (BlockShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { - printf(" with entry %d\n", iter->first->Id); + for (IdShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { + printf(" with entry %d\n", iter->first); } }, { printf("<< Loop\n"); diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h index 152bae0e6e709..7d80e16298dbe 100644 --- a/src/relooper/Relooper.h +++ b/src/relooper/Relooper.h @@ -132,8 +132,6 @@ struct SimpleShape : public Shape { } }; -typedef std::map BlockShapeMap; - // A shape that may be implemented with a labeled loop. struct LabeledShape : public Shape { bool Labeled; // If we have a loop, whether it needs to be labeled @@ -141,8 +139,11 @@ struct LabeledShape : public Shape { LabeledShape(ShapeType TypeInit) : Shape(TypeInit), Labeled(false) {} }; +// Blocks with the same id were split and are identical, so we just care about ids in Multiple entries +typedef std::map IdShapeMap; + struct MultipleShape : public LabeledShape { - BlockShapeMap InnerMap; // entry block -> shape + IdShapeMap InnerMap; // entry block ID -> shape int NeedLoop; // If we have branches, we need a loop. This is a counter of loop requirements, // if we optimize it to 0, the loop is unneeded From 8036eb04feba4bebb5c1e500a8eda5ebafcc947d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 16 Apr 2014 14:15:15 -0700 Subject: [PATCH 11/67] remove unneeded relooper code --- src/relooper/Relooper.cpp | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index c396e990d794d..06ee0aa36a953 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -332,21 +332,8 @@ void MultipleShape::RenderLoopPostfix() { void MultipleShape::Render(bool InLoop) { RenderLoopPrefix(); - // We know that blocks with the same Id were split from the same source, so their contents are identical and they are logically the same, so re-merge them here - typedef std::map IdShapeMap; - IdShapeMap IdMap; - for (IdShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { - int Id = iter->first; - IdShapeMap::iterator Test = IdMap.find(Id); - if (Test != IdMap.end()) { - assert(Shape::IsSimple(iter->second) && Shape::IsSimple(Test->second)); // we can only merge simple blocks, something horrible has gone wrong if we see anything else - continue; - } - IdMap[iter->first] = iter->second; - } - bool First = true; - for (IdShapeMap::iterator iter = IdMap.begin(); iter != IdMap.end(); iter++) { + for (IdShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { if (AsmJS) { PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first); } else { From 65b33689947112aa2f468dc0b00be61401152678 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 16 Apr 2014 15:06:08 -0700 Subject: [PATCH 12/67] emit switches in relooper in many-entried multiple shapes --- src/relooper/Relooper.cpp | 85 +++++++++++++++++++++++++++++---------- src/relooper/Relooper.h | 7 ++-- 2 files changed, 68 insertions(+), 24 deletions(-) diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index 06ee0aa36a953..ce9232d9947f5 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -312,18 +312,28 @@ void Block::Render(bool InLoop) { // MultipleShape void MultipleShape::RenderLoopPrefix() { - if (NeedLoop) { - if (Labeled) { - PrintIndented("L%d: do {\n", Id); + if (Breaks) { + if (UseSwitch) { + if (Labeled) { + PrintIndented("L%d: ", Id); + } } else { - PrintIndented("do {\n"); + if (Labeled) { + if (UseSwitch) { + PrintIndented("L%d: ", Id); + } else { + PrintIndented("L%d: do {\n", Id); + } + } else { + PrintIndented("do {\n"); + } + Indenter::Indent(); } - Indenter::Indent(); } } void MultipleShape::RenderLoopPostfix() { - if (NeedLoop) { + if (Breaks && !UseSwitch) { Indenter::Unindent(); PrintIndented("} while(0);\n"); } @@ -332,19 +342,41 @@ void MultipleShape::RenderLoopPostfix() { void MultipleShape::Render(bool InLoop) { RenderLoopPrefix(); - bool First = true; - for (IdShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { + if (!UseSwitch) { + // emit an if-else chain + bool First = true; + for (IdShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { + if (AsmJS) { + PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first); + } else { + PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first); + } + First = false; + Indenter::Indent(); + iter->second->Render(InLoop); + Indenter::Unindent(); + PrintIndented("}\n"); + } + } else { + // emit a switch if (AsmJS) { - PrintIndented("%sif ((label|0) == %d) {\n", First ? "" : "else ", iter->first); + PrintIndented("switch (label|0) {\n"); } else { - PrintIndented("%sif (label == %d) {\n", First ? "" : "else ", iter->first); + PrintIndented("switch (label) {\n"); } - First = false; Indenter::Indent(); - iter->second->Render(InLoop); + for (IdShapeMap::iterator iter = InnerMap.begin(); iter != InnerMap.end(); iter++) { + PrintIndented("case %d: {\n", iter->first); + Indenter::Indent(); + iter->second->Render(InLoop); + PrintIndented("break;\n"); + Indenter::Unindent(); + PrintIndented("}\n"); + } Indenter::Unindent(); PrintIndented("}\n"); } + RenderLoopPostfix(); if (Next) Next->Render(InLoop); } @@ -534,7 +566,7 @@ void Relooper::Calculate(Block *Entry) { PriorOut->Ancestor = Ancestor; PriorOut->Type = Type; if (MultipleShape *Multiple = Shape::IsMultiple(Ancestor)) { - Multiple->NeedLoop++; // We are breaking out of this Multiple, so need a loop + Multiple->Breaks++; // We are breaking out of this Multiple, so need a loop } iter++; // carefully increment iter before erasing Target->BranchesIn.erase(Prior); @@ -854,6 +886,11 @@ void Relooper::Calculate(Block *Entry) { NextEntries.insert(Entry); } } + // The multiple has been created, we can decide how to implement it + if (Multiple->InnerMap.size() >= 10) { + Multiple->UseSwitch = true; + Multiple->Breaks++; // switch captures breaks + } return Multiple; } @@ -1098,7 +1135,7 @@ void Relooper::Calculate(Block *Entry) { if (Details->Type == Branch::Break) { Details->Type = Branch::Direct; if (MultipleShape *Multiple = Shape::IsMultiple(Details->Ancestor)) { - Multiple->NeedLoop--; + Multiple->Breaks--; } } else { assert(Details->Type == Branch::Direct); @@ -1117,20 +1154,20 @@ void Relooper::Calculate(Block *Entry) { if (Details->Type != Branch::Direct && contains(NaturalBlocks, Target)) { // note: cannot handle split blocks Details->Type = Branch::Direct; if (MultipleShape *Multiple = Shape::IsMultiple(Details->Ancestor)) { - Multiple->NeedLoop--; + Multiple->Breaks--; } } else if (Details->Type == Branch::Break && LastLoop && LastLoop->Natural == Details->Ancestor->Natural) { // it is important to simplify breaks, as simpler breaks enable other optimizations Details->Labeled = false; if (MultipleShape *Multiple = Shape::IsMultiple(Details->Ancestor)) { - Multiple->NeedLoop--; + Multiple->Breaks--; } } } } }, { for (IdShapeMap::iterator iter = Multiple->InnerMap.begin(); iter != Multiple->InnerMap.end(); iter++) { - RemoveUnneededFlows(iter->second, Multiple->Next, Multiple->NeedLoop ? NULL : LastLoop); + RemoveUnneededFlows(iter->second, Multiple->Next, Multiple->Breaks ? NULL : LastLoop); } Next = Multiple->Next; }, { @@ -1156,13 +1193,16 @@ void Relooper::Calculate(Block *Entry) { SHAPE_SWITCH(Root, { MultipleShape *Fused = Shape::IsMultiple(Root->Next); // If we are fusing a Multiple with a loop into this Simple, then visit it now - if (Fused && Fused->NeedLoop) { + if (Fused && Fused->Breaks) { LoopStack.push(Fused); } if (Simple->Inner->BranchVar) { LoopStack.push(NULL); // a switch means breaks are now useless, push a dummy } if (Fused) { + if (Fused->UseSwitch) { + LoopStack.push(NULL); // a switch means breaks are now useless, push a dummy + } RECURSE_Multiple(Fused, FindLabeledLoops); } for (BlockBranchMap::iterator iter = Simple->Inner->ProcessedBranchesOut.begin(); iter != Simple->Inner->ProcessedBranchesOut.end(); iter++) { @@ -1178,10 +1218,13 @@ void Relooper::Calculate(Block *Entry) { } } } + if (Fused && Fused->UseSwitch) { + LoopStack.pop(); + } if (Simple->Inner->BranchVar) { LoopStack.pop(); } - if (Fused && Fused->NeedLoop) { + if (Fused && Fused->Breaks) { LoopStack.pop(); } if (Fused) { @@ -1190,11 +1233,11 @@ void Relooper::Calculate(Block *Entry) { Next = Root->Next; } }, { - if (Multiple->NeedLoop) { + if (Multiple->Breaks) { LoopStack.push(Multiple); } RECURSE(Multiple, FindLabeledLoops); - if (Multiple->NeedLoop) { + if (Multiple->Breaks) { LoopStack.pop(); } Next = Root->Next; diff --git a/src/relooper/Relooper.h b/src/relooper/Relooper.h index 7d80e16298dbe..c86e63ac1f1f1 100644 --- a/src/relooper/Relooper.h +++ b/src/relooper/Relooper.h @@ -144,10 +144,11 @@ typedef std::map IdShapeMap; struct MultipleShape : public LabeledShape { IdShapeMap InnerMap; // entry block ID -> shape - int NeedLoop; // If we have branches, we need a loop. This is a counter of loop requirements, - // if we optimize it to 0, the loop is unneeded + int Breaks; // If we have branches on us, we need a loop (or a switch). This is a counter of requirements, + // if we optimize it to 0, the loop is unneeded + bool UseSwitch; // Whether to switch on label as opposed to an if-else chain - MultipleShape() : LabeledShape(Multiple), NeedLoop(0) {} + MultipleShape() : LabeledShape(Multiple), Breaks(0), UseSwitch(false) {} void RenderLoopPrefix(); void RenderLoopPostfix(); From eedeeda0ae6558b02f1fa81562af6f6159765f3d Mon Sep 17 00:00:00 2001 From: Soeren Balko Date: Thu, 17 Apr 2014 14:12:26 +1000 Subject: [PATCH 13/67] asm.js-ify some LLVM intrinsics --- src/library.js | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index 1d5a91407455e..a29a972773d40 100644 --- a/src/library.js +++ b/src/library.js @@ -3908,12 +3908,22 @@ LibraryManager.library = { {{{ makeCopyValues('(ppdest+'+Runtime.QUANTUM_SIZE+')', '(ppsrc+'+Runtime.QUANTUM_SIZE+')', Runtime.QUANTUM_SIZE, 'null', null, 1) }}}; }, + llvm_bswap_i16__asm: true, + llvm_bswap_i16__sig: 'ii', llvm_bswap_i16: function(x) { - return ((x&0xff)<<8) | ((x>>8)&0xff); + x = x|0; + return (((((x&0xff)|0)<<8)|0) | + (((x>>8)|0)&0xff)|0)|0; }, + llvm_bswap_i32__asm: true, + llvm_bswap_i32__sig: 'ii', llvm_bswap_i32: function(x) { - return ((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24); + x = x|0; + return (((((x&0xff)|0)<<24)|0) | + ((((((x>>8)|0)&0xff)|0)<<16)|0) | + ((((((x>>16)|0)&0xff)|0)<<8)|0) | + ((x>>>24)|0))|0; }, llvm_bswap_i64__deps: ['llvm_bswap_i32'], From 8e812b712fb6d281b48fba60af36103e062f495e Mon Sep 17 00:00:00 2001 From: Soeren Balko Date: Thu, 17 Apr 2014 15:23:02 +1000 Subject: [PATCH 14/67] Removed superfluous casts --- src/library.js | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/library.js b/src/library.js index a29a972773d40..c283039728440 100644 --- a/src/library.js +++ b/src/library.js @@ -3912,18 +3912,14 @@ LibraryManager.library = { llvm_bswap_i16__sig: 'ii', llvm_bswap_i16: function(x) { x = x|0; - return (((((x&0xff)|0)<<8)|0) | - (((x>>8)|0)&0xff)|0)|0; + return (((x&0xff)<<8) | ((x>>8)&0xff))|0; }, llvm_bswap_i32__asm: true, llvm_bswap_i32__sig: 'ii', llvm_bswap_i32: function(x) { x = x|0; - return (((((x&0xff)|0)<<24)|0) | - ((((((x>>8)|0)&0xff)|0)<<16)|0) | - ((((((x>>16)|0)&0xff)|0)<<8)|0) | - ((x>>>24)|0))|0; + return (((x&0xff)<<24) | (((x>>8)&0xff)<<16) | (((x>>16)&0xff)<<8) | (x>>>24))|0; }, llvm_bswap_i64__deps: ['llvm_bswap_i32'], From 5a2501b3b9bd39b49750b7d0486b6c2de215713a Mon Sep 17 00:00:00 2001 From: Ori Avtalion Date: Wed, 16 Apr 2014 23:18:03 +0300 Subject: [PATCH 15/67] Fix typo in settings.js --- AUTHORS | 1 + src/settings.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 99703f937a44b..6d5798cdda0cb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -134,4 +134,5 @@ a license to everyone to use it as detailed in LICENSE.) * Daniele Di Proietto * Dan Dascalescu * Thomas Borsos +* Ori Avtalion diff --git a/src/settings.js b/src/settings.js index 8b046e9551b63..bf16290bbe466 100644 --- a/src/settings.js +++ b/src/settings.js @@ -39,7 +39,7 @@ var CHECK_SIGNS = 0; // Runtime errors for signing issues that need correcting. var ASSERTIONS = 1; // Whether we should add runtime assertions, for example to // check that each allocation to the stack does not - // exceed it's size, whether all allocations (stack and static) are + // exceed its size, whether all allocations (stack and static) are // of positive size, etc., whether we should throw if we encounter a bad __label__, i.e., // if code flow runs into a fault // ASSERTIONS == 2 gives even more runtime checks From 87d62e4e7505c77c53ebc00d5bc56540863699db Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 17 Apr 2014 11:26:13 -0700 Subject: [PATCH 16/67] eliminate loop vars even if used after increment, by adding another helper (which has less overhead than the previous helper) --- tests/fuzz/19.c | 1408 +++++++++++++++++ tests/fuzz/19.c.txt | 1 + .../eliminator/asm-eliminator-test-output.js | 52 +- tools/eliminator/asm-eliminator-test.js | 23 +- tools/js-optimizer.js | 17 +- 5 files changed, 1476 insertions(+), 25 deletions(-) create mode 100644 tests/fuzz/19.c create mode 100644 tests/fuzz/19.c.txt diff --git a/tests/fuzz/19.c b/tests/fuzz/19.c new file mode 100644 index 0000000000000..d94318c5e5fdb --- /dev/null +++ b/tests/fuzz/19.c @@ -0,0 +1,1408 @@ +/* + * This is a RANDOMLY GENERATED PROGRAM. + * + * Generator: csmith 2.2.0 + * Git version: bf42ffd + * Options: --no-volatiles --no-packed-struct --no-math64 + * Seed: 2524651702 + */ + +#include "csmith.h" + + +static long __undefined; + +/* --- Struct/Union Declarations --- */ +/* --- GLOBAL VARIABLES --- */ +static uint32_t g_2[5][1] = {{0xF1124F01L},{0x1F2C29A3L},{0xF1124F01L},{0x1F2C29A3L},{0xF1124F01L}}; +static int32_t g_3 = 0x3FA75C19L; +static uint32_t g_14[6] = {0xD1A4E665L,0xD1A4E665L,0xD1A4E665L,0xD1A4E665L,0xD1A4E665L,0xD1A4E665L}; +static uint32_t g_15 = 18446744073709551615UL; +static int32_t g_34 = 1L; +static int8_t g_36 = 0x6DL; +static uint8_t g_40[7] = {0xEAL,0xEAL,0xEAL,0xEAL,0xEAL,0xEAL,0xEAL}; +static uint8_t g_44 = 0UL; +static uint8_t *g_43 = &g_44; +static int32_t g_46 = 0x461302D9L; +static int32_t g_51[2][8][3] = {{{0x0D357E8FL,0x604C38DBL,0x0D357E8FL},{0x0D357E8FL,0x349DDA4AL,0x1ADF561FL},{0x0D357E8FL,0x2D584125L,(-4L)},{0x0D357E8FL,0x604C38DBL,0x0D357E8FL},{0x0D357E8FL,0x349DDA4AL,0x1ADF561FL},{0x0D357E8FL,0x2D584125L,(-4L)},{0x0D357E8FL,0x604C38DBL,0x0D357E8FL},{0x0D357E8FL,0x349DDA4AL,0x1ADF561FL}},{{0x0D357E8FL,0x2D584125L,(-4L)},{0x0D357E8FL,0x1ADF561FL,(-10L)},{(-10L),0x0D357E8FL,0xCF8610F1L},{(-10L),(-4L),(-9L)},{(-10L),0x1ADF561FL,(-10L)},{(-10L),0x0D357E8FL,0xCF8610F1L},{(-10L),(-4L),(-9L)},{(-10L),0x1ADF561FL,(-10L)}}}; +static uint32_t g_52 = 0x171C63CCL; +static uint32_t g_56 = 0xFBFBE831L; +static uint32_t *g_55 = &g_56; +static const int8_t * const g_132 = &g_36; +static const int8_t * const *g_131 = &g_132; +static int32_t g_140 = 0L; +static int32_t *g_143 = &g_140; +static uint8_t **g_175 = &g_43; +static uint8_t **g_176 = &g_43; +static uint8_t **g_177 = (void*)0; +static int8_t *g_243[6][2][9] = {{{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36}},{{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36}},{{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36}},{{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36}},{{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36}},{{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36,&g_36}}}; +static int8_t **g_242 = &g_243[5][1][5]; +static int8_t **g_245 = &g_243[5][1][5]; +static uint16_t g_251 = 0x6187L; +static int8_t g_255 = 0xFEL; +static int16_t g_290 = 0xF4DEL; +static int16_t *g_289 = &g_290; +static uint32_t g_294[5] = {0xFDB146E2L,0xFDB146E2L,0xFDB146E2L,0xFDB146E2L,0xFDB146E2L}; +static int32_t g_297[2] = {1L,1L}; +static int32_t *g_312[2][1][6] = {{{(void*)0,(void*)0,&g_51[0][3][1],(void*)0,(void*)0,&g_51[0][3][1]}},{{(void*)0,(void*)0,&g_51[0][3][1],(void*)0,(void*)0,&g_51[0][3][1]}}}; +static uint8_t g_320 = 0xD4L; +static int16_t g_347 = 0x586CL; +static int16_t g_419 = 0xDAAFL; +static uint32_t g_477 = 0x661A1A9FL; +static uint32_t g_705[6] = {1UL,1UL,1UL,1UL,1UL,1UL}; +static uint32_t ** const g_736 = &g_55; +static uint32_t ** const *g_735 = &g_736; +static uint8_t ****g_897 = (void*)0; +static uint8_t ***g_905 = &g_175; +static uint8_t ****g_904[3][6] = {{&g_905,&g_905,&g_905,&g_905,&g_905,&g_905},{&g_905,&g_905,&g_905,&g_905,&g_905,&g_905},{&g_905,&g_905,&g_905,&g_905,&g_905,&g_905}}; +static int32_t **g_961 = &g_312[1][0][4]; +static int32_t ***g_960 = &g_961; +static uint16_t g_969 = 5UL; +static int8_t ***g_1019[7][1][1] = {{{&g_242}},{{&g_242}},{{&g_242}},{{&g_242}},{{&g_242}},{{&g_242}},{{&g_242}}}; +static int8_t ****g_1018 = &g_1019[3][0][0]; +static int32_t g_1055 = (-8L); +static uint32_t g_1099 = 0xAD3B6902L; +static int32_t g_1132 = (-9L); +static int16_t * const *g_1185 = &g_289; +static int16_t * const * const *g_1184 = &g_1185; +static int16_t g_1189 = 0L; +static uint32_t **g_1238 = &g_55; +static uint32_t ***g_1237[8][4][4] = {{{&g_1238,(void*)0,&g_1238,(void*)0},{&g_1238,(void*)0,&g_1238,&g_1238},{(void*)0,&g_1238,&g_1238,(void*)0},{(void*)0,&g_1238,(void*)0,&g_1238}},{{&g_1238,(void*)0,(void*)0,&g_1238},{&g_1238,&g_1238,&g_1238,(void*)0},{&g_1238,&g_1238,&g_1238,(void*)0},{&g_1238,(void*)0,&g_1238,&g_1238}},{{&g_1238,&g_1238,&g_1238,(void*)0},{&g_1238,&g_1238,&g_1238,&g_1238},{&g_1238,(void*)0,(void*)0,&g_1238},{(void*)0,&g_1238,(void*)0,(void*)0}},{{&g_1238,(void*)0,&g_1238,(void*)0},{&g_1238,&g_1238,(void*)0,(void*)0},{(void*)0,(void*)0,&g_1238,&g_1238},{&g_1238,&g_1238,&g_1238,&g_1238}},{{&g_1238,&g_1238,&g_1238,&g_1238},{&g_1238,&g_1238,&g_1238,&g_1238},{&g_1238,&g_1238,&g_1238,&g_1238},{&g_1238,(void*)0,(void*)0,(void*)0}},{{&g_1238,&g_1238,&g_1238,(void*)0},{&g_1238,(void*)0,&g_1238,(void*)0},{(void*)0,&g_1238,(void*)0,&g_1238},{&g_1238,(void*)0,(void*)0,&g_1238}},{{&g_1238,&g_1238,&g_1238,(void*)0},{&g_1238,&g_1238,&g_1238,&g_1238},{&g_1238,(void*)0,&g_1238,(void*)0},{&g_1238,&g_1238,&g_1238,(void*)0}},{{&g_1238,&g_1238,&g_1238,&g_1238},{(void*)0,(void*)0,&g_1238,&g_1238},{(void*)0,&g_1238,&g_1238,(void*)0},{&g_1238,&g_1238,&g_1238,&g_1238}}}; +static uint32_t ***g_1241 = (void*)0; +static uint32_t g_1254[8][1][8] = {{{0x441F7909L,0x441F7909L,0UL,0x5B976413L,18446744073709551610UL,0UL,18446744073709551610UL,0x5B976413L}},{{0x0ECD52E7L,0x5B976413L,0x0ECD52E7L,0xD72EFABCL,0x5B976413L,0x6701CBD7L,0x6701CBD7L,0x5B976413L}},{{0x5B976413L,0x6701CBD7L,0x6701CBD7L,0x5B976413L,0xD72EFABCL,0x0ECD52E7L,0x5B976413L,0x0ECD52E7L}},{{0x5B976413L,18446744073709551610UL,0UL,18446744073709551610UL,0x5B976413L,0UL,0x441F7909L,0x441F7909L}},{{0x0ECD52E7L,18446744073709551610UL,0xD72EFABCL,0xD72EFABCL,18446744073709551610UL,0x0ECD52E7L,0x6701CBD7L,18446744073709551610UL}},{{0x441F7909L,0x6701CBD7L,0xD72EFABCL,0x441F7909L,0xD72EFABCL,0x6701CBD7L,0x441F7909L,0x0ECD52E7L}},{{18446744073709551610UL,0x5B976413L,0UL,0x441F7909L,0x441F7909L,0UL,0x5B976413L,18446744073709551610UL}},{{0x0ECD52E7L,0x441F7909L,0x6701CBD7L,0xD72EFABCL,0x441F7909L,0xD72EFABCL,0x6701CBD7L,0x441F7909L}}}; +static int16_t g_1285 = 0L; +static uint8_t * const **g_1295 = (void*)0; +static uint8_t g_1298 = 0xB8L; +static int16_t g_1333 = 0x34D4L; +static uint32_t g_1334 = 0x1191E655L; +static int32_t g_1509 = 1L; +static uint8_t ***g_1548 = &g_176; +static uint8_t ***g_1549 = (void*)0; +static uint8_t ***g_1550 = (void*)0; +static uint8_t ***g_1551[3][5] = {{&g_176,&g_176,&g_176,&g_176,&g_176},{&g_176,&g_176,&g_176,&g_176,&g_176},{&g_176,&g_176,&g_176,&g_176,&g_176}}; +static uint8_t ***g_1552[10][9] = {{&g_175,&g_177,&g_175,(void*)0,&g_175,&g_175,(void*)0,&g_175,&g_177},{(void*)0,&g_175,&g_175,(void*)0,&g_175,&g_177,&g_176,&g_175,&g_175},{&g_175,&g_175,&g_177,(void*)0,&g_177,&g_175,&g_175,&g_177,&g_175},{&g_176,&g_175,&g_176,(void*)0,&g_177,&g_176,&g_176,&g_176,&g_177},{&g_176,&g_177,&g_177,&g_176,&g_175,&g_176,(void*)0,&g_177,&g_176},{&g_175,&g_177,&g_175,(void*)0,&g_175,&g_175,(void*)0,&g_175,&g_177},{(void*)0,&g_175,&g_175,(void*)0,&g_175,&g_177,&g_176,&g_175,&g_175},{&g_175,&g_175,&g_177,(void*)0,&g_177,&g_175,&g_175,&g_177,&g_175},{&g_176,&g_175,&g_176,(void*)0,&g_177,&g_176,&g_176,&g_176,&g_177},{&g_176,&g_177,&g_177,&g_176,&g_175,&g_176,(void*)0,&g_177,&g_176}}; +static uint8_t **** const g_1547[1][6][2] = {{{&g_1551[1][3],&g_1552[7][4]},{&g_1551[1][3],&g_1551[1][3]},{&g_1552[7][4],&g_1551[1][3]},{&g_1551[1][3],&g_1552[7][4]},{&g_1551[1][3],&g_1551[1][3]},{&g_1552[7][4],&g_1551[1][3]}}}; +static uint8_t **** const *g_1546[5] = {&g_1547[0][2][0],&g_1547[0][2][0],&g_1547[0][2][0],&g_1547[0][2][0],&g_1547[0][2][0]}; +static int8_t ***g_1656 = &g_245; +static uint16_t g_1766 = 0x2A71L; +static const uint32_t g_1776 = 4294967288UL; +static const uint32_t g_1782[6][8][5] = {{{9UL,1UL,0xC7DDDB76L,0x6C0C4151L,0x8031E06CL},{4294967288UL,0x67522ABBL,4294967289UL,9UL,0x6B1862C6L},{4294967289UL,0x035D4646L,0x4BD87A52L,0xF04D3E88L,0x02BA768FL},{0x67522ABBL,1UL,0xFBE5C2AFL,0x09838561L,0x6E51EAD8L},{0x67522ABBL,0x8031E06CL,0xFC56E314L,0x5133D18EL,0xF04D3E88L},{4294967289UL,0xFBE5C2AFL,4294967286UL,4294967295UL,4294967295UL},{4294967288UL,4294967289UL,4294967288UL,0xFC56E314L,0x4BD87A52L},{9UL,0x09838561L,4294967295UL,1UL,3UL}},{{0xD3C5907BL,0x6C0C4151L,4294967289UL,0x8031E06CL,0x035D4646L},{0x6B1862C6L,0x6E51EAD8L,4294967295UL,3UL,0x02BA768FL},{4294967294UL,0xD3C5907BL,4294967288UL,0x67522ABBL,4294967289UL},{0x6C0C4151L,0x8031E06CL,4294967286UL,4294967295UL,0xB9EFEB98L},{8UL,4294967291UL,0xFC56E314L,4294967295UL,0x2B8C1A21L},{4294967291UL,0x6B1862C6L,0xFBE5C2AFL,1UL,0x2B8C1A21L},{9UL,0x1C34F8ADL,0x4BD87A52L,4294967288UL,0xB9EFEB98L},{1UL,4294967288UL,4294967289UL,0xB9EFEB98L,4294967289UL}},{{0xE9241C7AL,0xE9241C7AL,0x6E51EAD8L,1UL,0x09838561L},{4294967288UL,3UL,0x8031E06CL,4294967291UL,0x37358859L},{1UL,4294967295UL,0xD83C2DFAL,1UL,4294967286UL},{0x4478B581L,3UL,0x2B8C1A21L,8UL,0x5A8F52F4L},{0xB9EFEB98L,0xE9241C7AL,0xF04D3E88L,0xC7DDDB76L,8UL},{1UL,1UL,0UL,7UL,0x5133D18EL},{0xF04D3E88L,4294967291UL,0x084A6D3FL,4294967286UL,0x02BA768FL},{0x02BA768FL,0xB3D218BBL,4294967289UL,4294967286UL,0x09838561L}},{{0x2BAF5CEFL,9UL,0xFDF9E1B7L,7UL,0xB3D218BBL},{4294967291UL,4294967295UL,0xC7DDDB76L,0xC7DDDB76L,4294967295UL},{0x37358859L,0x9D243B0BL,4294967295UL,8UL,4294967289UL},{0xFDF9E1B7L,0x02BA768FL,0x9D243B0BL,1UL,0x6B1862C6L},{1UL,0xFBE5C2AFL,0x6B1862C6L,4294967291UL,4294967286UL},{0xFDF9E1B7L,0x2BAF5CEFL,0x084A6D3FL,1UL,0x731D77D9L},{0x37358859L,0x084A6D3FL,0x035D4646L,0xFC56E314L,0x09838561L},{4294967291UL,0xB9EFEB98L,9UL,1UL,0x4478B581L}},{{0x2BAF5CEFL,4294967295UL,4294967291UL,4294967295UL,1UL},{0x02BA768FL,0x8031E06CL,4294967291UL,8UL,0UL},{0xF04D3E88L,0x37358859L,9UL,0x2B8C1A21L,0x6E51EAD8L},{1UL,0xD3C5907BL,0x035D4646L,0xD3C5907BL,1UL},{0xB9EFEB98L,4294967288UL,0x084A6D3FL,4294967286UL,0xE9241C7AL},{0x4478B581L,0x731D77D9L,0x6B1862C6L,4294967295UL,0x09838561L},{1UL,0xFDF9E1B7L,0x9D243B0BL,4294967288UL,0xE9241C7AL},{4294967288UL,4294967295UL,4294967295UL,0x4BD87A52L,1UL}},{{0xE9241C7AL,0xF04D3E88L,0xC7DDDB76L,8UL,0x6E51EAD8L},{0x8031E06CL,0x4478B581L,0xFDF9E1B7L,4294967291UL,0UL},{1UL,7UL,4294967289UL,0x2BAF5CEFL,1UL},{9UL,7UL,0x084A6D3FL,0x5133D18EL,0x4478B581L},{0x731D77D9L,0x4478B581L,0UL,1UL,0x09838561L},{0xFBE5C2AFL,0xF04D3E88L,0xF04D3E88L,0xFBE5C2AFL,0x731D77D9L},{7UL,4294967295UL,0x2B8C1A21L,0xD83C2DFAL,4294967286UL},{0xB3D218BBL,0xFDF9E1B7L,0xD83C2DFAL,8UL,0x6B1862C6L}}}; +static const uint32_t *g_1781 = &g_1782[2][3][4]; +static int8_t g_1857 = 0L; +static const uint8_t *g_1941 = (void*)0; +static const uint8_t ** const g_1940[7] = {&g_1941,&g_1941,&g_1941,&g_1941,&g_1941,&g_1941,&g_1941}; +static const uint8_t ** const *g_1939 = &g_1940[2]; +static const uint8_t ** const **g_1938 = &g_1939; +static const uint8_t ** const ***g_1937 = &g_1938; +static int16_t g_1961 = (-2L); +static const int8_t g_2067 = (-1L); +static const uint32_t ***g_2068[3] = {(void*)0,(void*)0,(void*)0}; +static int8_t g_2147[10] = {0x23L,0x23L,0x23L,0x23L,0x23L,0x23L,0x23L,0x23L,0x23L,0x23L}; +static uint16_t g_2148 = 0x794EL; +static int16_t g_2207 = 0L; + + +/* --- FORWARD DECLARATIONS --- */ +static uint16_t func_1(void); +static int8_t func_10(uint32_t p_11); +static int32_t func_16(int8_t p_17, uint32_t * p_18, uint32_t * p_19, uint16_t p_20, uint32_t p_21); +static uint32_t * func_22(int16_t p_23, uint32_t p_24, uint32_t * p_25); +static int32_t func_62(int32_t * p_63, uint8_t p_64); +static int32_t * func_65(int8_t p_66, uint16_t p_67, uint8_t p_68, int32_t * p_69, uint32_t * p_70); +static uint8_t * func_71(uint32_t p_72, int8_t p_73); +static int32_t * func_94(uint32_t * p_95, int32_t p_96, const int32_t p_97, int32_t p_98, int8_t p_99); +static int8_t func_100(int32_t * p_101, uint8_t p_102, uint8_t p_103, uint32_t p_104); +static int32_t * func_105(uint32_t p_106); + + +/* --- FUNCTIONS --- */ +/* ------------------------------------------ */ +/* + * reads : g_2 g_14 g_15 g_36 g_40 g_43 g_3 g_52 g_46 g_51 g_55 g_56 g_44 g_251 g_143 g_140 g_176 g_705 g_289 g_290 g_297 g_255 g_34 g_131 g_132 g_243 g_347 g_320 g_736 g_294 g_175 g_897 g_905 g_735 g_960 g_969 g_961 g_312 g_1334 g_1132 g_1184 g_1185 g_1099 g_1656 g_1238 g_1548 g_1018 g_1019 g_1254 g_1766 g_1776 g_1857 g_477 g_1298 g_1937 g_1961 g_242 g_1781 g_1782 g_419 g_2068 g_245 g_1938 g_2147 g_2148 g_1333 g_2207 + * writes: g_3 g_14 g_15 g_34 g_36 g_40 g_52 g_51 g_46 g_255 g_297 g_140 g_312 g_294 g_56 g_44 g_347 g_290 g_897 g_904 g_419 g_251 g_969 g_1334 g_1132 g_1298 g_175 g_1099 g_1055 g_477 g_55 g_1766 g_1781 g_960 g_242 g_961 g_705 g_2068 g_2148 g_2207 + */ +static uint16_t func_1(void) +{ /* block id: 0 */ + int32_t l_38 = 0xCA862934L; + int32_t l_1612 = 0xB952CD69L; + int32_t l_1634 = 0x1D6D5307L; + int16_t l_1658[5][6] = {{0x1999L,0L,0x1999L,0x1999L,0L,0x1999L},{0x1999L,0L,0x1999L,0x1999L,0L,0x0361L},{0x0361L,0x1999L,0x0361L,0x0361L,0x1999L,0x0361L},{0x0361L,0x1999L,0x0361L,0x0361L,0x1999L,0x0361L},{0x0361L,0x1999L,0x0361L,0x0361L,0x1999L,0x0361L}}; + uint8_t * const ***l_1712 = &g_1295; + uint8_t * const ****l_1711[9] = {&l_1712,&l_1712,&l_1712,&l_1712,&l_1712,&l_1712,&l_1712,&l_1712,&l_1712}; + uint8_t **l_1725 = &g_43; + int16_t l_1756[10][2] = {{0xB2C0L,(-1L)},{(-1L),0xB2C0L},{(-1L),(-1L)},{0xB2C0L,(-1L)},{(-1L),0xB2C0L},{(-1L),(-1L)},{0xB2C0L,(-1L)},{(-1L),0xB2C0L},{(-1L),(-1L)},{0xB2C0L,(-1L)}}; + int32_t l_1763 = (-8L); + uint32_t *l_1783 = &g_14[1]; + int32_t ***l_1785 = &g_961; + uint32_t *****l_1788 = (void*)0; + uint8_t l_1831 = 0x9CL; + uint8_t *l_1877 = &g_40[0]; + uint32_t l_2046 = 18446744073709551609UL; + int8_t l_2047 = 1L; + uint32_t l_2048 = 2UL; + int32_t l_2056 = 1L; + int32_t l_2058 = 0L; + int32_t l_2072 = 9L; + uint32_t l_2099 = 4UL; + uint32_t l_2116 = 4UL; + uint32_t l_2184 = 0xE4A882E7L; + int16_t **l_2189[6][6][7] = {{{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{(void*)0,&g_289,&g_289,(void*)0,(void*)0,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{(void*)0,&g_289,&g_289,&g_289,(void*)0,&g_289,(void*)0},{&g_289,(void*)0,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,(void*)0,&g_289,(void*)0,&g_289,&g_289,&g_289}},{{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0,(void*)0}},{{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{(void*)0,(void*)0,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,(void*)0,&g_289,&g_289,&g_289},{(void*)0,&g_289,&g_289,&g_289,&g_289,(void*)0,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,(void*)0,&g_289,&g_289,(void*)0}},{{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0,&g_289},{&g_289,(void*)0,(void*)0,(void*)0,(void*)0,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0,&g_289},{&g_289,&g_289,(void*)0,&g_289,(void*)0,&g_289,&g_289}},{{&g_289,&g_289,&g_289,(void*)0,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,(void*)0,(void*)0,&g_289,&g_289,&g_289,&g_289}},{{&g_289,(void*)0,&g_289,&g_289,&g_289,&g_289,&g_289},{&g_289,&g_289,(void*)0,&g_289,&g_289,(void*)0,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{(void*)0,&g_289,&g_289,(void*)0,(void*)0,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289},{(void*)0,&g_289,&g_289,&g_289,(void*)0,&g_289,(void*)0}}}; + int16_t ***l_2188 = &l_2189[0][5][4]; + int16_t ****l_2187[1]; + int i, j, k; + for (i = 0; i < 1; i++) + l_2187[i] = &l_2188; +lbl_2208: + for (g_3 = 0; (g_3 <= 0); g_3 += 1) + { /* block id: 3 */ + uint32_t *l_12 = (void*)0; + uint32_t *l_13[2][9][7] = {{{&g_14[4],&g_14[2],&g_14[1],&g_14[1],&g_14[1],(void*)0,&g_14[4]},{(void*)0,&g_14[1],&g_14[3],&g_14[1],&g_14[1],&g_14[3],&g_14[1]},{&g_14[4],&g_14[2],&g_14[1],&g_14[1],&g_14[1],(void*)0,&g_14[4]},{(void*)0,&g_14[1],&g_14[3],&g_14[1],&g_14[1],&g_14[3],&g_14[1]},{&g_14[4],&g_14[2],&g_14[1],&g_14[1],&g_14[1],(void*)0,&g_14[4]},{(void*)0,&g_14[1],&g_14[3],&g_14[1],&g_14[1],&g_14[3],&g_14[1]},{&g_14[4],&g_14[2],&g_14[1],&g_14[1],&g_14[1],(void*)0,&g_14[4]},{(void*)0,&g_14[1],&g_14[3],&g_14[1],&g_14[1],&g_14[3],&g_14[1]},{&g_14[4],&g_14[2],&g_14[1],&g_14[1],&g_14[1],(void*)0,&g_14[4]}},{{(void*)0,&g_14[1],&g_14[3],&g_14[1],&g_14[1],&g_14[3],&g_14[1]},{&g_14[4],&g_14[2],&g_14[1],&g_14[1],&g_14[1],(void*)0,&g_14[4]},{(void*)0,&g_14[1],&g_14[3],&g_14[1],(void*)0,&g_14[1],&g_14[0]},{&g_14[1],&g_14[3],&g_14[1],(void*)0,&g_14[4],&g_14[1],&g_14[1]},{&g_14[1],&g_14[0],&g_14[1],(void*)0,(void*)0,&g_14[1],&g_14[0]},{&g_14[1],&g_14[3],&g_14[1],(void*)0,&g_14[4],&g_14[1],&g_14[1]},{&g_14[1],&g_14[0],&g_14[1],(void*)0,(void*)0,&g_14[1],&g_14[0]},{&g_14[1],&g_14[3],&g_14[1],(void*)0,&g_14[4],&g_14[1],&g_14[1]},{&g_14[1],&g_14[0],&g_14[1],(void*)0,(void*)0,&g_14[1],&g_14[0]}}}; + int8_t *l_35 = &g_36; + int32_t l_37 = 0x129EC6EAL; + uint8_t *l_39 = &g_40[1]; + uint32_t l_1611 = 1UL; + const int16_t l_1613 = (-7L); + int32_t l_1616 = 0xF7091F80L; + int32_t l_1618 = 0x81A177EAL; + int32_t l_1623 = (-3L); + int8_t ***l_1657 = &g_245; + int i, j, k; + if ((((((safe_mul_func_int8_t_s_s(((safe_div_func_uint8_t_u_u(((safe_mod_func_int8_t_s_s(func_10((((g_15 &= (g_14[4] ^= g_2[1][0])) == func_16(g_2[2][0], func_22((safe_div_func_int8_t_s_s((safe_mul_func_int16_t_s_s(((safe_div_func_int32_t_s_s((safe_rshift_func_uint8_t_u_s((g_34 = 1UL), ((*l_35) ^= 0x4DL))), l_37)) == (((((*l_39) = l_38) , (--(*l_39))) >= l_37) ^ 0UL)), ((void*)0 == g_43))), g_3)), l_38, l_13[1][1][2]), g_55, l_37, g_56)) >= l_37)), l_38)) == 0x3C9EL), l_38)) , 0xBCL), l_1611)) | l_1612) == 1UL) < l_1613) == 0x39F7L)) + { /* block id: 771 */ + int32_t *l_1614 = &g_1055; + if (l_1613) + break; + (**g_960) = l_1614; + if (l_1611) + continue; + } + else + { /* block id: 775 */ + int32_t *l_1615 = &g_51[1][6][2]; + int32_t *l_1617 = &g_297[1]; + int32_t *l_1619 = &l_1616; + int32_t *l_1620 = (void*)0; + int32_t *l_1621 = &l_1618; + int32_t *l_1622 = &g_297[1]; + int32_t *l_1624 = &g_51[0][3][1]; + int32_t *l_1625 = &l_37; + int32_t *l_1626 = (void*)0; + int32_t *l_1627 = &g_1132; + int32_t *l_1628 = &g_297[1]; + int32_t *l_1629 = &l_1618; + int32_t *l_1630[9] = {&g_297[0],&g_297[0],&g_297[0],&g_297[0],&g_297[0],&g_297[0],&g_297[0],&g_297[0],&g_297[0]}; + uint8_t l_1631 = 6UL; + int i; + --l_1631; + return (*l_1617); + } + l_1634 |= 0xB346B708L; + for (g_1298 = 0; (g_1298 <= 0); g_1298 += 1) + { /* block id: 782 */ + uint32_t l_1635 = 0xEF083A2AL; + int32_t l_1644 = 0x4F483357L; + (*g_143) ^= l_1635; + (*g_143) = (safe_mul_func_uint16_t_u_u(((safe_sub_func_int8_t_s_s(((!(l_38 , l_1611)) != (l_1644 &= (safe_lshift_func_int8_t_s_s((safe_add_func_int8_t_s_s(0x2CL, l_1612)), 4)))), (safe_unary_minus_func_uint32_t_u((safe_div_func_int8_t_s_s(((g_320 <= (((l_38 <= (((safe_add_func_int16_t_s_s((safe_sub_func_uint16_t_u_u((l_1618 & (((safe_div_func_uint16_t_u_u((((((safe_rshift_func_int16_t_s_s(0x3853L, l_1635)) >= l_1612) , g_1656) != l_1657) & l_38), 65531UL)) ^ l_1623) && l_1635)), l_1658[1][1])), 0x80FFL)) == 7UL) == (**g_1238))) > 0x43L) || g_14[5])) , 5L), l_1612)))))) > l_1658[1][1]), 0UL)); + } + for (g_1099 = 0; (g_1099 <= 0); g_1099 += 1) + { /* block id: 789 */ + int16_t l_1661 = 0x12BEL; + uint16_t *l_1666[10][9] = {{(void*)0,&g_969,&g_251,&g_969,&g_251,&g_969,&g_969,&g_251,&g_969},{(void*)0,&g_969,(void*)0,(void*)0,(void*)0,&g_969,(void*)0,(void*)0,(void*)0},{&g_969,(void*)0,&g_251,&g_969,&g_251,&g_251,&g_969,&g_251,(void*)0},{&g_969,&g_969,&g_969,(void*)0,&g_969,(void*)0,&g_969,&g_969,&g_969},{&g_251,&g_251,&g_251,&g_969,&g_969,&g_251,&g_251,&g_251,&g_251},{(void*)0,&g_969,(void*)0,&g_969,(void*)0,&g_969,(void*)0,&g_969,(void*)0},{&g_251,(void*)0,&g_251,&g_251,(void*)0,&g_251,&g_251,&g_969,&g_251},{&g_969,&g_969,&g_969,&g_969,&g_969,&g_969,&g_969,&g_969,&g_969},{&g_969,&g_969,&g_969,&g_969,&g_251,&g_969,&g_251,&g_251,(void*)0},{(void*)0,&g_969,(void*)0,&g_969,(void*)0,&g_969,(void*)0,&g_969,(void*)0}}; + int16_t l_1667 = 0xD2A4L; + int32_t l_1680 = 0x06D2A1F8L; + int32_t l_1681 = 0xB17E7D5CL; + int8_t l_1682 = (-5L); + int32_t *l_1683 = &g_1055; + int i, j; + l_37 ^= ((*l_1683) = ((*g_143) = ((safe_add_func_uint32_t_u_u((--(***g_735)), (safe_mul_func_uint8_t_u_u(((l_1681 = (!((g_969 = (l_1667 &= 1UL)) != ((*g_132) != (((((safe_mul_func_int16_t_s_s(((***g_1548) && (safe_div_func_uint8_t_u_u((((safe_sub_func_int16_t_s_s(((safe_add_func_int32_t_s_s((safe_lshift_func_uint16_t_u_u(g_34, ((*g_1018) != (*g_1018)))), (*g_143))) , (((safe_add_func_uint16_t_u_u((l_1680 = ((((l_1618 = ((***g_1184) | ((((**g_1185) ^ l_1661) && l_1661) , l_1661))) < 1L) || 65533UL) | l_1616)), (-2L))) == l_1658[3][5]) != l_1661)), l_1623)) , 0L) | l_1661), l_1661))), l_1634)) <= (*g_143)) , l_38) || (*g_143)) != (***g_1184)))))) , (*g_43)), (***g_1548))))) <= l_1682))); + } + } + for (l_38 = 2; (l_38 <= (-27)); l_38 = safe_sub_func_int8_t_s_s(l_38, 6)) + { /* block id: 803 */ + int32_t l_1692 = 0L; + int32_t l_1702 = 0xA1267D64L; + uint32_t l_1722 = 8UL; + uint8_t * const * const l_1726 = &g_43; + uint32_t *l_1737 = &g_1099; + int8_t *l_1793 = (void*)0; + int32_t *l_1797 = (void*)0; + uint32_t l_1859 = 0x82CF6B6FL; + int8_t l_1899 = 1L; + uint16_t l_1902 = 65534UL; + int8_t ***l_1936[8] = {(void*)0,&g_242,&g_242,(void*)0,&g_242,&g_242,(void*)0,&g_242}; + uint32_t l_1957 = 5UL; + int32_t **l_2005 = &g_143; + uint32_t l_2007 = 18446744073709551615UL; + int32_t l_2050 = (-1L); + int32_t l_2051 = 5L; + int32_t l_2052[8][1]; + const int8_t *l_2066 = &g_2067; + const int8_t **l_2065[10] = {(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0}; + uint32_t l_2071[3][7][7] = {{{0x30CE76AEL,0UL,18446744073709551615UL,1UL,1UL,1UL,0UL},{0xAD0A2372L,0xEA6E9C20L,0UL,0x324BC3A3L,0xF442972AL,0x911E4A42L,0x911E4A42L},{18446744073709551608UL,18446744073709551610UL,0x1262E29EL,18446744073709551610UL,18446744073709551608UL,0x9477AE01L,0xF442972AL},{1UL,5UL,0x30CE76AEL,18446744073709551611UL,0x99881E2AL,0xDA83510BL,18446744073709551615UL},{0xF442972AL,0x911E4A42L,0xFCFF20AAL,0x23F69BAEL,18446744073709551608UL,0x30CE76AEL,0xAD0A2372L},{0x1262E29EL,0UL,18446744073709551615UL,1UL,0x6F0D46CCL,0x1262E29EL,0x7CF12E04L},{18446744073709551615UL,0xF442972AL,0x5F49E352L,5UL,18446744073709551615UL,0UL,0UL}},{{18446744073709551611UL,18446744073709551615UL,0x23F69BAEL,0x30CE76AEL,0UL,18446744073709551615UL,1UL},{0x250C5BC2L,18446744073709551615UL,6UL,0x30CE76AEL,1UL,1UL,0UL},{18446744073709551615UL,0x6F0D46CCL,1UL,5UL,0x911E4A42L,1UL,0x911E4A42L},{1UL,18446744073709551615UL,18446744073709551615UL,1UL,0x9477AE01L,0x23E5CD91L,0x30CE76AEL},{0x2665B0F5L,0UL,1UL,0x23F69BAEL,0xDA83510BL,0x9D1F30D5L,0UL},{18446744073709551611UL,0x5F49E352L,0x84F3CCEFL,0UL,0x9A4CA65DL,18446744073709551610UL,0x30CE76AEL},{6UL,0UL,0x324BC3A3L,0x5F49E352L,1UL,5UL,0x911E4A42L}},{{1UL,18446744073709551608UL,18446744073709551613UL,0xDC003897L,1UL,0UL,0UL},{1UL,18446744073709551615UL,18446744073709551615UL,0x324BC3A3L,18446744073709551608UL,0xCC0F1D77L,1UL},{0x9D1F30D5L,0x7DDAB611L,18446744073709551615UL,0xFCFF20AAL,0UL,0x9D1F30D5L,0UL},{18446744073709551615UL,18446744073709551615UL,18446744073709551613UL,0x7CF12E04L,0UL,0UL,0x7CF12E04L},{0x324BC3A3L,0UL,0x324BC3A3L,0x30CE76AEL,0x7CF12E04L,6UL,0xAD0A2372L},{0x5F49E352L,18446744073709551615UL,0x84F3CCEFL,18446744073709551615UL,18446744073709551614UL,18446744073709551615UL,0UL},{1UL,0UL,1UL,0x27C4E890L,0x911E4A42L,6UL,18446744073709551615UL}}}; + uint16_t l_2191 = 0UL; + uint32_t l_2194 = 0x1CA07694L; + uint8_t *****l_2202 = &g_904[0][3]; + uint8_t ******l_2201 = &l_2202; + uint8_t *l_2205 = &l_1831; + int32_t *l_2206[1][2]; + int i, j, k; + for (i = 0; i < 8; i++) + { + for (j = 0; j < 1; j++) + l_2052[i][j] = 1L; + } + for (i = 0; i < 1; i++) + { + for (j = 0; j < 2; j++) + l_2206[i][j] = &l_2052[2][0]; + } + if (((((0xEC18D826L > 0xC2623D2EL) == (safe_add_func_int32_t_s_s(((void*)0 == (*g_1018)), (*g_143)))) < ((*g_43) |= (((safe_add_func_int8_t_s_s(l_1658[4][2], (**g_131))) == (l_1634 = ((((safe_lshift_func_uint16_t_u_s(g_294[0], 5)) , l_1692) , 0x47L) && 0x07L))) != 0x6DDD7AF3L))) <= l_1692)) + { /* block id: 806 */ + int8_t l_1727 = 0x36L; + uint16_t l_1730 = 0x5E85L; + int32_t l_1758 = 1L; + int32_t l_1760 = 0x8ED80A0BL; + int32_t l_1762 = 0xC5EE06D0L; + int32_t l_1764 = 0x9C30C92FL; + uint8_t l_1773 = 0x04L; + uint32_t l_1795 = 0x25B5191FL; + int32_t *l_1832 = (void*)0; + int32_t l_1850 = 3L; + uint16_t l_1876 = 0xC3DDL; + uint32_t *****l_1891 = (void*)0; + uint16_t l_1901 = 65528UL; + for (g_419 = 0; (g_419 < 27); ++g_419) + { /* block id: 809 */ + int32_t l_1697[6] = {(-8L),(-8L),(-8L),(-8L),(-8L),(-8L)}; + uint16_t *l_1698[10][3] = {{&g_251,&g_251,&g_251},{&g_251,&g_251,&g_251},{&g_251,&g_251,&g_251},{&g_251,&g_969,&g_251},{&g_251,&g_251,&g_251},{&g_251,&g_251,&g_251},{&g_969,&g_251,&g_251},{&g_251,&g_251,&g_251},{&g_251,&g_251,&g_251},{&g_251,&g_969,&g_969}}; + int i, j; + (*g_143) ^= ((**g_736) , l_1612); + l_1634 = (safe_lshift_func_uint16_t_u_s((g_969 = l_1697[1]), 5)); + } + for (g_255 = 0; (g_255 > 7); g_255 = safe_add_func_int16_t_s_s(g_255, 8)) + { /* block id: 816 */ + uint8_t l_1701 = 0xB3L; + uint8_t * const ***l_1709 = (void*)0; + uint8_t * const ****l_1708 = &l_1709; + uint8_t * const *****l_1710[10][10][2] = {{{&l_1708,(void*)0},{&l_1708,&l_1708},{(void*)0,&l_1708},{&l_1708,(void*)0},{&l_1708,&l_1708},{(void*)0,&l_1708},{&l_1708,(void*)0},{&l_1708,&l_1708},{(void*)0,&l_1708},{&l_1708,(void*)0}},{{&l_1708,&l_1708},{(void*)0,&l_1708},{&l_1708,(void*)0},{&l_1708,&l_1708},{(void*)0,&l_1708},{&l_1708,(void*)0},{&l_1708,&l_1708},{(void*)0,&l_1708},{&l_1708,&l_1708},{(void*)0,(void*)0}},{{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0}},{{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708}},{{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0}},{{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0}},{{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708}},{{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0}},{{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0}},{{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708},{(void*)0,(void*)0},{&l_1708,(void*)0},{(void*)0,&l_1708}}}; + int32_t l_1721 = 1L; + uint32_t *l_1728 = &g_477; + int32_t *l_1729[5][7] = {{(void*)0,&l_38,&l_38,&l_38,(void*)0,&l_1692,&l_1692},{&g_34,(void*)0,&l_1612,(void*)0,&g_34,&g_1509,&g_1509},{(void*)0,&l_38,&l_38,&l_38,(void*)0,&l_1692,&l_1692},{&g_34,(void*)0,&l_1612,(void*)0,&g_34,&g_1509,&l_1612},{&l_1692,&l_1692,&g_34,&l_1692,&l_1692,&l_38,&l_38}}; + int8_t *l_1731 = &l_1727; + int32_t l_1739 = 0xD1196770L; + int32_t l_1759 = 0L; + uint16_t *l_1806[2][8] = {{&l_1730,&l_1730,&l_1730,&l_1730,&l_1730,&l_1730,&l_1730,&l_1730},{&l_1730,&l_1730,&l_1730,&l_1730,&l_1730,&l_1730,&l_1730,&l_1730}}; + int32_t *l_1833 = &g_3; + int i, j, k; + l_1702 = l_1701; + if ((safe_lshift_func_uint8_t_u_u((l_38 , 0xE4L), (((safe_mul_func_int8_t_s_s(((*l_1731) = (((safe_unary_minus_func_int8_t_s((&g_1547[0][2][1] != (l_1711[7] = l_1708)))) == (safe_add_func_int8_t_s_s((((**g_736) = (**g_736)) < (((safe_mod_func_uint16_t_u_u(((l_1634 = (((*l_1728) = (safe_mul_func_uint8_t_u_u((((**l_1726) = (((safe_add_func_uint8_t_u_u((l_1721 = l_1701), (l_1722 != (safe_div_func_int32_t_s_s((((l_1725 == l_1726) , 0x32L) > l_1727), (*g_143)))))) , 0UL) <= 0xB756L)) && 0UL), l_1612))) < 0UL)) , g_1132), (**g_1185))) && 0x6EL) | g_1254[7][0][7])), 0xB8L))) >= l_1730)), l_1730)) > 0xF123L) || (*g_43))))) + { /* block id: 825 */ + uint32_t *l_1738 = &g_56; + for (g_477 = (-18); (g_477 >= 4); g_477 = safe_add_func_int32_t_s_s(g_477, 1)) + { /* block id: 828 */ + int8_t l_1736 = 0xE8L; + (*g_143) |= l_1727; + l_1721 = (l_1721 < (l_1739 = ((l_1736 , 0x13L) <= ((l_1738 = l_1737) == ((*g_736) = (*g_736)))))); + if ((*g_143)) + break; + } + } + else + { /* block id: 836 */ + int32_t l_1761 = 0x3F63D84DL; + int32_t l_1784[6] = {0xC54599E7L,0xC54599E7L,0x4344EDEAL,0xC54599E7L,0xC54599E7L,0x4344EDEAL}; + int32_t ***l_1794[9] = {(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0}; + int16_t **l_1796[5][2][9] = {{{&g_289,&g_289,(void*)0,&g_289,&g_289,&g_289,(void*)0,(void*)0,&g_289},{(void*)0,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289}},{{(void*)0,&g_289,&g_289,&g_289,(void*)0,&g_289,(void*)0,&g_289,&g_289},{&g_289,&g_289,(void*)0,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289}},{{&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0,&g_289,(void*)0},{&g_289,(void*)0,(void*)0,(void*)0,&g_289,&g_289,&g_289,(void*)0,&g_289}},{{(void*)0,(void*)0,&g_289,&g_289,&g_289,(void*)0,(void*)0,&g_289,&g_289},{&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0,&g_289,&g_289,&g_289}},{{(void*)0,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289,(void*)0,&g_289},{&g_289,(void*)0,(void*)0,&g_289,&g_289,&g_289,&g_289,&g_289,&g_289}}}; + int i, j, k; + for (g_1132 = 0; (g_1132 >= 0); g_1132 -= 1) + { /* block id: 839 */ + int32_t l_1757 = 0x90288987L; + int32_t l_1765 = 0x82B8DD8AL; + const uint32_t *l_1775 = &g_1776; + const uint32_t **l_1774 = &l_1775; + const uint32_t *l_1778 = (void*)0; + const uint32_t **l_1777 = &l_1778; + const uint32_t *l_1780 = &g_1776; + const uint32_t **l_1779 = &l_1780; + int i, j, k; + l_1784[5] = ((safe_sub_func_int32_t_s_s((safe_mul_func_int8_t_s_s((safe_add_func_uint8_t_u_u((++(**l_1725)), ((((l_1761 = ((safe_mod_func_uint32_t_u_u((safe_lshift_func_uint16_t_u_s(0x6591L, g_1254[(g_1132 + 4)][g_1132][(g_1132 + 2)])), (l_1721 & (((safe_add_func_int16_t_s_s(l_1721, (**g_1185))) , &g_1019[3][0][0]) != &g_1019[6][0][0])))) || ((safe_add_func_uint16_t_u_u(((g_1781 = ((*l_1779) = ((*l_1777) = ((*l_1774) = func_22(((((*g_143) = ((++g_1766) < (((((((safe_add_func_int16_t_s_s(((**g_1238) , (safe_rshift_func_uint8_t_u_s(l_1765, 6))), (**g_1185))) , 0xDFL) == l_1721) | (*g_289)) & l_1739) | l_1764) < 0UL))) , l_1761) , l_1773), l_1762, (**g_735)))))) != l_1783), 0x2B14L)) & 0x69A24093L))) > l_1701) >= 1L) == l_1739))), l_1730)), 0xBDA5626EL)) | l_1701); + (*g_143) = l_1761; + l_1797 = func_105((((g_960 = l_1785) != (((safe_mul_func_uint8_t_u_u((l_1788 != (void*)0), (g_14[2] , ((((+(safe_sub_func_uint8_t_u_u((((***g_905) = (safe_mul_func_int8_t_s_s((**g_131), ((*l_1731) = ((*g_131) != l_1793))))) <= (l_1794[4] != (void*)0)), l_1795))) , (void*)0) == l_1796[1][0][3]) && g_1254[(g_1132 + 4)][g_1132][(g_1132 + 2)])))) >= l_1722) , (void*)0)) < 0xA30C448CL)); + return l_1727; + } + (*g_143) ^= ((safe_mul_func_int8_t_s_s(0xA2L, ((safe_div_func_uint8_t_u_u(((**g_1185) < (7L < l_1701)), (*g_43))) && 0x80504E05L))) > 0UL); + } + (**g_960) = (l_1833 = (l_1832 = ((l_1773 | ((safe_mul_func_uint8_t_u_u(((++g_251) , (((--(**l_1726)) ^ ((safe_mod_func_uint32_t_u_u(0xE9892A02L, 0x6E452460L)) | (0xDA1EL && (!(((safe_div_func_int16_t_s_s((safe_rshift_func_uint16_t_u_u((g_251 = ((((safe_add_func_uint16_t_u_u((safe_mul_func_uint16_t_u_u((g_969++), 0UL)), (g_1334 & (!(((l_1758 ^= (safe_div_func_int32_t_s_s(((+((safe_lshift_func_int8_t_s_s((safe_div_func_int32_t_s_s(0x469EB03BL, ((((safe_mod_func_int32_t_s_s(l_1730, l_1773)) | l_1701) , (**g_1238)) , 4294967295UL))), 7)) != (**g_1185))) ^ 65530UL), 0x7B945D20L))) , l_1721) && l_1758))))) < 0x75L) , l_1773) != 0xD86B841BL)), g_1099)), (**g_1185))) == g_1776) != l_1759))))) , (**g_176))), 0x8EL)) || l_1831)) , (void*)0))); + } + if ((safe_div_func_uint8_t_u_u((~(safe_mod_func_uint8_t_u_u((safe_div_func_int32_t_s_s(((***g_1548) < (l_1634 |= (safe_add_func_int16_t_s_s((-3L), ((safe_mul_func_int8_t_s_s((((~(safe_mod_func_int8_t_s_s((**g_131), (safe_mul_func_uint8_t_u_u((safe_div_func_int32_t_s_s((l_1702 , ((l_1850 == (safe_rshift_func_uint16_t_u_s(1UL, (0x3DCC7414L | ((0x04DDBC4DL && (((((safe_mul_func_uint8_t_u_u(255UL, l_1760)) > (***g_1184)) >= (**g_736)) >= g_1857) == 0xD4CEL)) >= l_1763))))) > g_477)), (-1L))), (*g_132)))))) , (void*)0) != &g_961), (*g_43))) >= (**g_1185)))))), 0x7424D03BL)), l_1850))), (***g_905)))) + { /* block id: 868 */ + uint16_t l_1858 = 0x3EA7L; + (*g_143) ^= (l_1858 = 0x9CFAB74FL); + } + else + { /* block id: 871 */ + int16_t **l_1864 = &g_289; + int16_t ***l_1863[5] = {(void*)0,(void*)0,(void*)0,(void*)0,(void*)0}; + const int8_t *l_1873 = &g_36; + const int8_t **l_1872 = &l_1873; + const int8_t ***l_1871 = &l_1872; + int32_t l_1888 = 0x7ACDB461L; + uint32_t ****l_1893 = &g_1241; + uint32_t **** const *l_1892[1][10] = {{&l_1893,&l_1893,&l_1893,&l_1893,&l_1893,&l_1893,&l_1893,&l_1893,&l_1893,&l_1893}}; + uint8_t **l_1898[8] = {&l_1877,&l_1877,&l_1877,&l_1877,&l_1877,&l_1877,&l_1877,&l_1877}; + int32_t l_1900 = 0x122D3568L; + int8_t l_1931 = 0x34L; + int i, j; + (*g_143) |= l_1859; + for (l_1762 = 1; (l_1762 >= 0); l_1762 -= 1) + { /* block id: 875 */ + uint32_t l_1860[3]; + int16_t **l_1862 = &g_289; + int16_t ***l_1861 = &l_1862; + const int8_t ***l_1875 = &l_1872; + const int8_t ****l_1874 = &l_1875; + int i; + for (i = 0; i < 3; i++) + l_1860[i] = 18446744073709551614UL; + (*g_143) |= ((l_1860[0] != (l_1861 == l_1863[2])) & (safe_mul_func_uint8_t_u_u(((safe_mod_func_int32_t_s_s((+((***g_1184) < (safe_div_func_uint8_t_u_u((l_1871 == ((*l_1874) = (void*)0)), l_1876)))), ((*g_55) = ((g_297[l_1762] = (((**g_736) , l_1877) != (*l_1726))) , (**g_736))))) || 0xE5L), l_1860[2]))); + } + (*g_143) = (((safe_lshift_func_uint16_t_u_u(((safe_sub_func_int8_t_s_s((*g_132), (safe_add_func_int16_t_s_s(0x0DE1L, (safe_sub_func_int16_t_s_s((safe_mod_func_uint16_t_u_u(((l_1888 , (*g_55)) && (g_969 < (g_1766 = (((**l_1725) = (((((l_1891 != l_1892[0][2]) , (safe_mul_func_uint8_t_u_u((safe_mul_func_int16_t_s_s(((l_1888 |= ((l_1898[7] != (void*)0) != 0x581BL)) || l_1634), 8UL)), 0x19L))) , (*g_289)) , l_1899) < 0x06L)) <= 0UL)))), l_1900)), (**g_1185))))))) >= 0x94L), l_1901)) != 4294967295UL) , (*g_143)); + if (l_1902) + { /* block id: 885 */ + int32_t l_1905 = 1L; + for (l_1760 = (-2); (l_1760 < (-23)); l_1760 = safe_sub_func_int32_t_s_s(l_1760, 3)) + { /* block id: 888 */ + (*g_143) ^= l_1905; + if (l_1905) + continue; + } + } + else + { /* block id: 892 */ + uint16_t *l_1908[5][4] = {{&g_1766,&g_1766,&g_969,&l_1901},{(void*)0,&g_1766,&g_1766,(void*)0},{&g_1766,(void*)0,&g_1766,&g_969},{&g_1766,&g_1766,&g_1766,&g_969},{(void*)0,&g_969,&g_969,&g_969}}; + int32_t l_1919 = 0x8D5F8744L; + int i, j; + (*g_143) = (l_1702 ^= ((((safe_sub_func_uint16_t_u_u((g_1766 = (++g_251)), ((((safe_div_func_int32_t_s_s(((++g_969) | (safe_mul_func_uint8_t_u_u(l_1919, (l_1919 != l_1658[2][1])))), l_1756[4][1])) <= ((safe_sub_func_int16_t_s_s((safe_lshift_func_uint8_t_u_s(l_1888, l_1730)), (((safe_lshift_func_int16_t_s_s((safe_rshift_func_uint16_t_u_s((((!(l_1919 , 0x59L)) ^ (l_1900 < l_1900)) >= l_1900), 4)), 14)) , (void*)0) != (void*)0))) <= 0xD049L)) > 0x779C7159L) , g_255))) ^ l_1900) | 1L) <= (***g_905))); + for (g_1298 = (-14); (g_1298 >= 3); g_1298++) + { /* block id: 900 */ + int32_t l_1930 = (-1L); + if (l_1930) + break; + if (l_1931) + continue; + l_1919 &= 0xDF650B0EL; + } + for (g_34 = 0; (g_34 <= 3); g_34 += 1) + { /* block id: 907 */ + return g_36; + } + } + } + } + else + { /* block id: 912 */ + int16_t l_1932 = (-4L); + const uint8_t ** const ***l_1943 = &g_1938; + int8_t **l_1974 = &l_1793; + int32_t l_1990 = (-4L); + int32_t *l_2009[3]; + int16_t **l_2027 = &g_289; + int16_t ***l_2026 = &l_2027; + const int16_t *l_2030 = &g_1285; + const int16_t **l_2029 = &l_2030; + const int16_t ***l_2028[3][5][2] = {{{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029}},{{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029}},{{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029},{&l_2029,&l_2029}}}; + int32_t l_2031[7][5] = {{0x7B32F464L,0x31A52CFCL,(-1L),0x1CB357FAL,(-1L)},{(-1L),(-1L),0xFE12D187L,0x1CB357FAL,(-10L)},{0x31A52CFCL,0x7B32F464L,0x7B32F464L,0x31A52CFCL,(-1L)},{0x31A52CFCL,0x1CB357FAL,0L,0L,0x1CB357FAL},{(-1L),0x7B32F464L,0L,0xFE12D187L,0xFE12D187L},{0x7B32F464L,(-1L),0x7B32F464L,0L,0xFE12D187L},{0x1CB357FAL,0x31A52CFCL,0xFE12D187L,0x31A52CFCL,0x1CB357FAL}}; + int32_t l_2032 = 4L; + int i, j, k; + for (i = 0; i < 3; i++) + l_2009[i] = &g_3; + if (l_1932) + { /* block id: 913 */ + uint16_t l_1966 = 0xAA16L; + uint8_t l_1967 = 9UL; + int32_t l_1989 = 0x49AFD519L; + int32_t **l_2003 = &g_312[1][0][5]; + for (g_347 = 0; (g_347 <= 18); g_347++) + { /* block id: 916 */ + uint8_t l_1935[1][10][2] = {{{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL},{4UL,0x9AL}}}; + int32_t l_1975 = (-9L); + uint8_t l_2006 = 0x8EL; + int i, j, k; + if (l_1935[0][3][1]) + { /* block id: 917 */ + const uint8_t ** const ****l_1942[3][1]; + int i, j; + for (i = 0; i < 3; i++) + { + for (j = 0; j < 1; j++) + l_1942[i][j] = &g_1937; + } + (*g_143) = ((((((void*)0 != l_1936[2]) & (-1L)) , &g_897) != (l_1943 = g_1937)) & (safe_lshift_func_uint16_t_u_s((safe_add_func_int8_t_s_s((*g_132), (0UL <= l_1932))), 4))); + } + else + { /* block id: 920 */ + int32_t *l_1952 = &l_1612; + int32_t l_1960 = 0x13E80650L; + uint16_t *l_1968[9] = {&g_1766,&g_251,&g_1766,&g_1766,&g_251,&g_1766,&g_1766,&g_251,&g_1766}; + int32_t *l_1969 = &g_3; + int32_t ***l_2004[4] = {&l_2003,&l_2003,&l_2003,&l_2003}; + uint32_t *l_2008 = &g_705[2]; + int i; + (*l_1969) ^= ((safe_mul_func_int16_t_s_s((*g_289), (safe_sub_func_uint8_t_u_u(((((*l_1952) = 0x79EFCB11L) , (((0x39L >= ((safe_div_func_int32_t_s_s(((*g_143) = (safe_add_func_int8_t_s_s(l_1957, (g_1857 && (g_251 = (safe_mul_func_uint8_t_u_u((l_1960 | g_1961), ((((safe_mod_func_int32_t_s_s(((safe_lshift_func_uint16_t_u_u(g_1298, l_1960)) == l_1966), l_1967)) && (*g_289)) , (*g_55)) != (*g_55))))))))), l_1960)) && l_1966)) , (***g_1184)) , l_1966)) || (**g_131)), (***g_1548))))) || l_1935[0][6][1]); + l_1990 &= (safe_rshift_func_int16_t_s_u((safe_rshift_func_int8_t_s_s((l_1975 = ((g_320 , ((**g_1018) = (**g_1018))) != l_1974)), 7)), ((l_1935[0][3][1] & (safe_add_func_int16_t_s_s((safe_div_func_int16_t_s_s((((((*l_1969) = ((***g_1184) > ((*l_1969) ^ (l_1989 = (safe_add_func_uint8_t_u_u(((safe_unary_minus_func_uint16_t_u(((((((((safe_lshift_func_int8_t_s_u(((safe_rshift_func_uint8_t_u_u(l_1935[0][6][0], l_1902)) > (((g_1766 = ((l_1967 , (*g_143)) & (*g_143))) , &g_1184) != (void*)0)), l_1935[0][3][1])) , l_1966) , 0x5DL) || 0x87L) <= l_1935[0][3][1]) || (*g_1781)) , &l_1692) == &g_1509))) ^ l_1932), 0xE0L)))))) || 251UL) | 0x46L) > l_1967), 0x3894L)), 0UL))) , g_1782[2][3][4]))); + l_2009[0] = func_105(((*l_2008) |= (safe_mod_func_int8_t_s_s((safe_rshift_func_uint16_t_u_s((g_1766++), ((((**g_1185) || (safe_rshift_func_uint16_t_u_u((((**g_736) = ((((+l_1935[0][3][1]) ^ 0x452888BFL) || ((((+((safe_rshift_func_int16_t_s_u((((l_1763 &= (safe_add_func_uint32_t_u_u((*g_55), ((((((*g_289) = ((*g_143) != ((*l_1969) = (*g_55)))) || 0x3A0FL) , ((((*l_1785) = (*g_960)) != (l_2005 = l_2003)) && l_1989)) , (*l_1969)) < l_1990)))) < 0xC6L) || 0xF854188CL), l_1975)) != l_2006)) <= 6L) , (void*)0) == (void*)0)) , l_2007)) | l_2006), g_251))) || 1L) | 0x7544L))), 4L)))); + } + if (l_1935[0][3][1]) + continue; + } + (*g_143) &= 0xCBD7ED2CL; + } + else + { /* block id: 944 */ + int32_t l_2014 = 0x16460141L; + uint8_t l_2033 = 0x2EL; + uint16_t *l_2039 = &g_251; + int32_t l_2049 = 0L; + int16_t l_2053[3]; + int32_t l_2054 = 0x72FC0805L; + int32_t l_2055 = (-4L); + int32_t l_2057 = 0x441D13AEL; + int32_t l_2059 = 0xB129E460L; + uint32_t l_2060[3][6] = {{1UL,1UL,18446744073709551615UL,1UL,1UL,18446744073709551615UL},{1UL,1UL,18446744073709551615UL,1UL,1UL,18446744073709551615UL},{1UL,1UL,18446744073709551615UL,1UL,1UL,18446744073709551615UL}}; + int i, j; + for (i = 0; i < 3; i++) + l_2053[i] = (-9L); + if (((**l_2005) > ((safe_div_func_uint16_t_u_u(((((**g_736) = (safe_mul_func_int8_t_s_s(0xC9L, l_2014))) & (safe_sub_func_int32_t_s_s((safe_sub_func_uint8_t_u_u((**l_2005), ((safe_mul_func_uint16_t_u_u((((safe_unary_minus_func_int16_t_s(((l_2032 = (l_2014 , (safe_mod_func_int32_t_s_s(0L, (safe_rshift_func_int8_t_s_s(((((((**g_1185) = (l_1658[1][1] == l_2014)) > ((l_2026 = l_2026) == l_2028[1][2][1])) || 1L) < g_1254[4][0][0]) <= g_297[1]), l_2031[3][2])))))) >= 0xFCL))) < (*g_143)) != 65529UL), l_2033)) , l_2014))), 0L))) >= (**l_2005)), (-4L))) || 4L))) + { /* block id: 949 */ + int32_t *l_2036 = (void*)0; + for (g_1298 = 3; (g_1298 < 13); g_1298++) + { /* block id: 952 */ + (*g_961) = l_2036; + (*g_143) = l_2033; + } + } + else + { /* block id: 956 */ + if ((*g_143)) + break; + } + l_2049 ^= ((safe_mod_func_uint16_t_u_u((g_1766 = ((1L ^ (((*l_2039) = ((void*)0 != &g_52)) <= (**g_1185))) , ((((safe_add_func_int16_t_s_s((((((+(safe_mod_func_int32_t_s_s((safe_sub_func_int16_t_s_s(((l_2046 ^ l_2047) >= ((!((l_2048 && (*g_1781)) , (254UL >= 0x4AL))) || 0xC4L)), g_51[0][3][1])), 0xD7857D83L))) , g_419) > g_40[1]) ^ l_2014) | 0x90L), g_1334)) & 0x40A7L) >= 0x889DL) | (**l_2005)))), 0x2C7FL)) != (**g_131)); + l_2060[2][2]--; + l_2059 |= (safe_sub_func_int32_t_s_s(l_2057, (0x662AL ^ (((l_2065[3] = (void*)0) != ((**g_1018) = (**g_1018))) >= ((0x53A4L & ((*l_2039) &= ((&g_736 != (g_2068[0] = g_2068[1])) >= (safe_mul_func_uint8_t_u_u(l_2049, (**g_131)))))) ^ l_2071[1][4][6]))))); + } + } + if (((*g_143) = l_2072)) + { /* block id: 971 */ + uint8_t l_2089 = 0x87L; + int32_t l_2095 = 1L; + const uint16_t l_2097 = 0xBF4DL; + int32_t l_2102[7][4]; + int32_t l_2108 = 0x7BAB6EA1L; + int8_t l_2128 = 0x3DL; + uint32_t *l_2168 = &l_1957; + int32_t l_2182 = 0x479FFEDCL; + int32_t *l_2190[4]; + int i, j; + for (i = 0; i < 7; i++) + { + for (j = 0; j < 4; j++) + l_2102[i][j] = 0x0A83AFD4L; + } + for (i = 0; i < 4; i++) + l_2190[i] = &g_3; + for (l_1692 = 2; (l_1692 >= 0); l_1692 -= 1) + { /* block id: 974 */ + uint32_t l_2085 = 0xB0246361L; + int8_t l_2086 = 0xB9L; + int32_t l_2094 = (-10L); + const uint32_t l_2096[1] = {0xC2A82A10L}; + uint32_t *l_2098 = &l_2071[1][5][2]; + int32_t *l_2100 = &l_1634; + int32_t *l_2101[4]; + uint16_t *l_2179 = &g_2148; + int i, j; + for (i = 0; i < 4; i++) + l_2101[i] = &l_2050; + if ((l_2102[6][0] |= ((*l_2100) &= (safe_mul_func_int8_t_s_s(((safe_div_func_uint8_t_u_u((g_705[2] , (safe_mod_func_int8_t_s_s((((*l_2098) = (safe_lshift_func_uint8_t_u_u((safe_sub_func_int8_t_s_s((((safe_mul_func_int8_t_s_s((l_2085 < l_2086), (g_1782[3][1][1] >= ((((safe_lshift_func_uint8_t_u_s(l_2089, 2)) == (g_705[2] ^ (((safe_mod_func_int16_t_s_s(((***g_1184) = (((((safe_mod_func_int32_t_s_s(((+(l_2095 = (l_2094 = l_2089))) , ((*g_143) = ((*g_143) > l_2085))), (**g_1238))) < (***g_1184)) == l_2089) || l_2096[0]) , 0x2B74L)), l_2089)) == l_2085) , 0x2251L))) != l_2089) || 65535UL)))) <= l_2089) , (-10L)), l_2089)), l_2097))) , l_2099), 0x69L))), l_2089)) <= (*g_55)), (**g_131)))))) + { /* block id: 982 */ + int8_t l_2115 = 1L; + int8_t * const *l_2118 = &g_243[5][0][8]; + int16_t *l_2136 = &l_1658[1][1]; + int16_t **l_2137 = &l_2136; + int32_t l_2146 = 1L; + int32_t ***l_2157 = &g_961; + int32_t ****l_2167 = &g_960; + for (l_1722 = 0; (l_1722 <= 4); l_1722 += 1) + { /* block id: 985 */ + uint16_t *l_2117 = &l_1902; + int16_t *l_2127 = &g_347; + uint32_t l_2135 = 8UL; + int i, j; + l_2095 = (l_2102[6][0] = (((safe_unary_minus_func_uint8_t_u(l_1658[l_1722][(l_1692 + 3)])) != (((((*l_2117) &= (l_1658[l_1692][(l_1722 + 1)] >= (safe_mod_func_uint8_t_u_u((((0L < (((void*)0 != (*g_1656)) , (l_2108 > (safe_add_func_int32_t_s_s(((*l_2100) = ((safe_mod_func_uint32_t_u_u(l_2108, ((safe_mul_func_int8_t_s_s(0xACL, (l_2115 , (**g_175)))) & l_2116))) >= 0x6E903ADFL)), l_2115))))) || (**g_131)) ^ 0UL), l_1658[l_1722][(l_1692 + 3)])))) , (void*)0) != l_2118) & (***g_1184))) || 0xFCE3BADFL)); + (*g_143) = (safe_mod_func_int8_t_s_s(((0xCFL > (safe_rshift_func_uint16_t_u_s((((((*g_1937) == (void*)0) != (*g_143)) && (safe_lshift_func_uint16_t_u_u((((~((*g_289) = (((((safe_lshift_func_uint8_t_u_s(l_2115, 4)) > (-6L)) && ((*l_2127) ^= (*g_289))) , (l_2128 >= (((safe_mod_func_uint16_t_u_u((safe_sub_func_uint8_t_u_u((((*l_2100) = ((safe_add_func_uint8_t_u_u(l_1658[l_1722][(l_1692 + 3)], l_2102[2][1])) ^ l_2135)) < l_2102[0][3]), (**g_175))), l_1658[l_1692][(l_1722 + 1)])) & 3L) , 1L))) >= 1UL))) & l_2108) > 1L), 6))) ^ 0xA1E6L), 14))) <= (*g_132)), (-6L))); + } + (*l_2100) &= (((*l_2137) = l_2136) == (void*)0); + l_2050 &= ((safe_mod_func_int8_t_s_s((l_1634 = (*g_132)), (safe_mod_func_int16_t_s_s((((*g_143) = (*g_143)) > (g_1857 < (l_2058 && (g_2148 |= (((((((void*)0 != &l_2086) == ((***g_735) = (((+(((l_2146 ^= (~(((safe_div_func_int32_t_s_s(0xBFC11C93L, (safe_mod_func_uint32_t_u_u(l_2095, (((*g_289) < 4L) , (*g_1781)))))) ^ 0x95679D65L) >= 0xA1895B12L))) >= (**g_131)) && 4294967293UL)) >= (**g_131)) , g_2147[7]))) , l_2146) <= l_2102[6][0]) , 0xB3BFL) == (-1L)))))), g_705[2])))) == 0x3157L); + if ((*g_143)) + { /* block id: 1003 */ + int32_t ****l_2158 = (void*)0; + int32_t ****l_2159 = &l_2157; + uint16_t *l_2160 = &l_1902; + l_2102[6][0] = (((safe_rshift_func_int16_t_s_u((0L ^ (safe_rshift_func_int8_t_s_s((((*l_2160) = (safe_div_func_int32_t_s_s((safe_mod_func_uint16_t_u_u((((*l_2159) = l_2157) == (void*)0), g_1333)), (*l_2100)))) > ((safe_add_func_int32_t_s_s(0x43A31542L, (safe_rshift_func_uint8_t_u_s((((*l_2136) = ((*g_289) = 0x48A9L)) <= l_2146), (((((((**g_736)--) , &g_960) == l_2167) & l_2089) <= (*g_1781)) < (**g_131)))))) < (*g_143))), 5))), 5)) ^ 0xDFCAL) & 65532UL); + (**g_960) = (***l_2167); + } + else + { /* block id: 1011 */ + int32_t l_2169 = 0xB5AD6469L; + (**g_960) = func_22((*g_289), (*g_1781), l_2168); + (*g_143) = l_2169; + } + } + else + { /* block id: 1015 */ + int32_t **l_2170[5]; + int i; + for (i = 0; i < 5; i++) + l_2170[i] = &l_1797; + l_2100 = ((**l_1785) = (**g_960)); + } + (**g_960) = func_22((safe_div_func_uint16_t_u_u(((((safe_add_func_uint16_t_u_u((l_1692 , g_34), (safe_add_func_uint8_t_u_u(l_2095, 250UL)))) ^ (*g_132)) & ((safe_mod_func_uint32_t_u_u((5UL < (((*l_2179) = ((void*)0 == (**g_1656))) && (safe_mul_func_int16_t_s_s((((l_2182 > 1UL) <= (*g_143)) != (*g_289)), 1UL)))), 0x328F77E6L)) , 1L)) | 1L), g_140)), (***g_735), &l_2048); + for (l_2099 = 0; (l_2099 <= 2); l_2099 += 1) + { /* block id: 1023 */ + int32_t l_2183 = 0x7A6C031CL; + ++l_2184; + l_2102[2][3] = ((*g_143) = (l_2187[0] == &g_1184)); + } + return g_1099; + } + l_2191++; + } + else + { /* block id: 1031 */ + return l_2194; + } + g_2207 |= ((*g_143) = (safe_sub_func_int32_t_s_s(l_2056, (safe_div_func_uint8_t_u_u(((((!(*g_289)) , ((safe_sub_func_int8_t_s_s(((((*l_2201) = &g_904[2][1]) != &g_1547[0][5][0]) & 0x784FL), (safe_sub_func_uint16_t_u_u((l_2205 == (void*)0), g_1132)))) || (0L > (-1L)))) , &g_1019[4][0][0]) != &g_1019[5][0][0]), l_1612))))); + if (l_2050) + goto lbl_2208; + } + return l_1658[1][1]; +} + + +/* ------------------------------------------ */ +/* + * reads : g_290 g_143 g_905 g_1298 + * writes: g_290 g_140 g_175 g_1298 + */ +static int8_t func_10(uint32_t p_11) +{ /* block id: 756 */ + uint32_t l_1605 = 3UL; + uint8_t **l_1608[3][5] = {{&g_43,&g_43,&g_43,&g_43,&g_43},{&g_43,&g_43,&g_43,&g_43,&g_43},{&g_43,&g_43,&g_43,&g_43,&g_43}}; + int i, j; + for (g_290 = 0; (g_290 >= 1); g_290++) + { /* block id: 759 */ + int32_t l_1603 = (-1L); + int32_t *l_1604[10]; + int i; + for (i = 0; i < 10; i++) + l_1604[i] = &g_297[1]; + (*g_143) = (safe_mod_func_int32_t_s_s(l_1603, p_11)); + l_1605++; + if (p_11) + break; + } + (*g_905) = l_1608[2][0]; + for (g_1298 = (-1); (g_1298 == 37); g_1298 = safe_add_func_uint16_t_u_u(g_1298, 9)) + { /* block id: 767 */ + return l_1605; + } + return l_1605; +} + + +/* ------------------------------------------ */ +/* + * reads : g_52 g_43 g_44 g_51 g_251 g_143 g_140 g_176 g_705 g_289 g_290 g_297 g_255 g_55 g_56 g_36 g_34 g_131 g_132 g_243 g_347 g_320 g_736 g_294 g_175 g_897 g_905 g_735 g_960 g_969 g_961 g_312 g_1334 g_1132 g_1184 g_1185 g_1099 g_1298 g_40 + * writes: g_46 g_36 g_255 g_297 g_140 g_312 g_294 g_51 g_34 g_56 g_44 g_347 g_290 g_897 g_904 g_419 g_251 g_969 g_1334 g_1132 g_1298 g_175 + */ +static int32_t func_16(int8_t p_17, uint32_t * p_18, uint32_t * p_19, uint16_t p_20, uint32_t p_21) +{ /* block id: 16 */ + uint32_t l_57 = 0xB31DF952L; + uint32_t *l_58 = &g_56; + int32_t * const l_59[10] = {&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2],&g_51[1][4][2]}; + uint32_t l_74[2][9] = {{0x548DC091L,0x548DC091L,0x548DC091L,0x548DC091L,0x548DC091L,0x548DC091L,0x548DC091L,0x548DC091L,0x548DC091L},{0UL,0x253094EEL,0UL,0x253094EEL,0UL,0x253094EEL,0UL,0x253094EEL,0UL}}; + uint8_t *l_1340[8][7] = {{&g_40[1],&g_40[5],&g_1298,&g_1298,&g_40[5],&g_40[1],&g_40[1]},{&g_40[5],&g_40[1],(void*)0,&g_1298,&g_1298,(void*)0,&g_40[1]},{&g_40[5],&g_40[1],&g_40[1],&g_40[5],&g_1298,&g_1298,&g_40[5]},{&g_40[1],&g_40[1],&g_40[1],&g_1298,&g_40[1],&g_40[1],&g_40[1]},{&g_40[1],&g_40[5],(void*)0,&g_40[5],&g_40[1],(void*)0,&g_1298},{&g_1298,&g_40[1],&g_1298,&g_1298,&g_1298,&g_40[1],&g_1298},{&g_40[1],&g_1298,&g_40[1],&g_1298,&g_1298,&g_1298,&g_40[1]},{&g_1298,&g_40[1],&g_1298,&g_40[1],&g_1298,&g_1298,&g_1298}}; + uint8_t *l_1341 = (void*)0; + uint8_t l_1385 = 0UL; + const int8_t *l_1399 = &g_255; + const int8_t ** const l_1398 = &l_1399; + const int8_t ** const *l_1397 = &l_1398; + int16_t **l_1400 = &g_289; + int8_t l_1404 = 0xDEL; + int16_t l_1460 = 0x14BCL; + uint8_t ** const *l_1553 = &g_175; + int32_t *l_1557[2]; + const uint32_t *l_1564[2]; + const uint32_t **l_1563[9][8][3] = {{{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[0],(void*)0,(void*)0},{&l_1564[1],&l_1564[0],&l_1564[1]},{(void*)0,&l_1564[1],&l_1564[1]},{&l_1564[0],&l_1564[1],(void*)0},{(void*)0,&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]}},{{(void*)0,&l_1564[0],&l_1564[1]},{&l_1564[1],(void*)0,&l_1564[1]},{&l_1564[0],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[0],&l_1564[1]},{&l_1564[1],&l_1564[1],(void*)0},{&l_1564[0],&l_1564[1],&l_1564[1]},{&l_1564[0],&l_1564[1],&l_1564[0]},{&l_1564[0],&l_1564[1],&l_1564[1]}},{{&l_1564[0],&l_1564[1],&l_1564[0]},{&l_1564[0],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[0],&l_1564[0],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{(void*)0,&l_1564[1],&l_1564[0]},{&l_1564[1],&l_1564[1],&l_1564[0]}},{{&l_1564[1],&l_1564[0],&l_1564[0]},{(void*)0,&l_1564[1],&l_1564[0]},{&l_1564[0],&l_1564[1],&l_1564[0]},{(void*)0,&l_1564[1],&l_1564[1]},{&l_1564[1],(void*)0,&l_1564[1]},{&l_1564[0],(void*)0,&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]}},{{&l_1564[1],&l_1564[1],&l_1564[0]},{&l_1564[1],(void*)0,&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[0]},{&l_1564[1],(void*)0,&l_1564[1]},{&l_1564[1],&l_1564[1],(void*)0},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],(void*)0,&l_1564[1]}},{{&l_1564[1],(void*)0,&l_1564[1]},{&l_1564[0],&l_1564[1],&l_1564[1]},{(void*)0,&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[0],(void*)0},{&l_1564[1],&l_1564[1],&l_1564[1]},{(void*)0,&l_1564[1],&l_1564[1]},{&l_1564[0],&l_1564[1],(void*)0}},{{&l_1564[1],&l_1564[0],&l_1564[1]},{&l_1564[1],&l_1564[1],(void*)0},{&l_1564[1],&l_1564[1],&l_1564[0]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]}},{{&l_1564[1],&l_1564[1],&l_1564[0]},{&l_1564[1],&l_1564[0],(void*)0},{&l_1564[1],&l_1564[1],&l_1564[1]},{&l_1564[0],(void*)0,(void*)0},{&l_1564[1],&l_1564[0],&l_1564[1]},{(void*)0,&l_1564[1],&l_1564[0]},{&l_1564[1],&l_1564[1],&l_1564[1]},{(void*)0,&l_1564[1],&l_1564[0]}},{{&l_1564[1],&l_1564[1],&l_1564[0]},{&l_1564[1],&l_1564[1],&l_1564[1]},{(void*)0,&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[0]},{(void*)0,&l_1564[1],&l_1564[1]},{&l_1564[1],&l_1564[1],&l_1564[1]},{(void*)0,&l_1564[0],(void*)0},{(void*)0,(void*)0,&l_1564[1]}}}; + const uint32_t ***l_1562 = &l_1563[2][1][2]; + const uint32_t ****l_1561 = &l_1562; + int32_t l_1574 = (-3L); + int32_t l_1577 = (-2L); + const uint8_t *l_1594 = &g_320; + const uint8_t **l_1593 = &l_1594; + int i, j, k; + for (i = 0; i < 2; i++) + l_1557[i] = &g_1132; + for (i = 0; i < 2; i++) + l_1564[i] = (void*)0; + if (((*g_143) = ((((((*p_18) = l_57) > ((l_58 = &l_57) != ((((l_59[2] != ((safe_rshift_func_int8_t_s_s(g_52, (((void*)0 == p_19) , ((*g_43) , (func_62(func_65((((l_1340[5][0] = func_71(l_74[0][4], p_20)) != l_1341) >= (-1L)), p_17, p_17, p_18, p_19), p_20) & l_1385))))) , (void*)0)) , 5L) == p_21) , (void*)0))) , 1L) | p_21) < p_17))) + { /* block id: 667 */ + int16_t l_1396[4]; + int32_t l_1421 = 7L; + int32_t l_1462 = 0x12662E75L; + int32_t l_1465 = 0x863BF099L; + int32_t l_1467 = 0L; + int32_t l_1470 = 2L; + int32_t l_1477 = 0x4CD2A26BL; + int32_t l_1490[10][2][5] = {{{0L,1L,8L,0x286E9DC0L,0x5DE9A0F1L},{0L,0x8BAB543FL,0x040A2369L,0x8BAB543FL,0L}},{{0x5DE9A0F1L,0x286E9DC0L,8L,1L,0L},{0L,0xF9205F80L,0x3F2E14FAL,0x8BAB543FL,(-1L)}},{{0L,0x286E9DC0L,(-4L),0x286E9DC0L,0L},{(-1L),0x8BAB543FL,0x3F2E14FAL,0xF9205F80L,0L}},{{0L,1L,8L,0x286E9DC0L,0x5DE9A0F1L},{0L,0x8BAB543FL,0x040A2369L,0x8BAB543FL,0L}},{{0x5DE9A0F1L,0x286E9DC0L,8L,1L,0L},{0L,0xF9205F80L,0x3F2E14FAL,0x8BAB543FL,(-1L)}},{{0L,0x286E9DC0L,(-4L),0x286E9DC0L,0L},{(-1L),0x8BAB543FL,0x3F2E14FAL,0xF9205F80L,0L}},{{0L,1L,8L,0x286E9DC0L,0x5DE9A0F1L},{0L,0x8BAB543FL,0x040A2369L,0x8BAB543FL,0L}},{{0x5DE9A0F1L,0x286E9DC0L,8L,1L,0L},{0L,0xF9205F80L,0x3F2E14FAL,0x8BAB543FL,(-1L)}},{{0L,0x286E9DC0L,(-4L),0x286E9DC0L,0L},{(-1L),0x8BAB543FL,0x3F2E14FAL,0xF9205F80L,0L}},{{0L,1L,8L,0x286E9DC0L,0x5DE9A0F1L},{0L,0x8BAB543FL,0x040A2369L,0x8BAB543FL,0L}}}; + uint8_t l_1499 = 0xACL; + const int32_t l_1539[1][3] = {{0L,0L,0L}}; + uint32_t ****l_1575 = &g_1237[6][2][0]; + int32_t **l_1579 = (void*)0; + int i, j, k; + for (i = 0; i < 4; i++) + l_1396[i] = (-1L); + for (g_1298 = 1; (g_1298 <= 5); g_1298 += 1) + { /* block id: 670 */ + int16_t **l_1401 = (void*)0; + uint16_t *l_1402 = &g_969; + int32_t l_1403 = (-1L); + uint32_t ***l_1405 = &g_1238; + uint32_t **l_1406 = &g_55; + uint32_t *l_1422[9]; + uint16_t l_1431 = 3UL; + int32_t l_1432 = 0xD4EEA904L; + int16_t ***l_1449 = &l_1401; + int32_t l_1464 = (-8L); + int32_t l_1468 = (-7L); + int32_t l_1469[8][4] = {{0x419228AFL,0xBFCFCC48L,0x419228AFL,2L},{0x3A8515F3L,0xBFCFCC48L,0x213DF6CAL,0xBFCFCC48L},{0x3A8515F3L,2L,0x419228AFL,0xBFCFCC48L},{0x419228AFL,0xBFCFCC48L,0x419228AFL,2L},{0x3A8515F3L,0xBFCFCC48L,0x213DF6CAL,0xBFCFCC48L},{0x3A8515F3L,2L,0x419228AFL,0xBFCFCC48L},{0x419228AFL,0xBFCFCC48L,0x419228AFL,2L},{0x3A8515F3L,0xBFCFCC48L,0x213DF6CAL,0xBFCFCC48L}}; + int8_t l_1493 = 0L; + int32_t **l_1532 = &g_312[0][0][4]; + int i, j; + for (i = 0; i < 9; i++) + l_1422[i] = &g_1099; + } + } + else + { /* block id: 747 */ + int16_t l_1580 = (-1L); + const uint8_t ***l_1595 = &l_1593; + uint8_t *l_1598[2]; + int i; + for (i = 0; i < 2; i++) + l_1598[i] = &g_1298; + (*g_143) = l_1580; + l_1557[1] = ((safe_lshift_func_int8_t_s_s((!(safe_rshift_func_uint8_t_u_s((l_1580 & (((safe_lshift_func_int16_t_s_u((safe_mod_func_uint8_t_u_u((safe_sub_func_uint16_t_u_u((((g_40[1] != g_34) , ((*l_1595) = l_1593)) == ((*g_905) = &l_1340[5][4])), (safe_sub_func_int32_t_s_s((((void*)0 != l_1598[0]) , ((*g_143) |= p_20)), (((l_1580 ^ l_1580) && p_21) , p_20))))), p_17)), p_20)) && p_17) < p_21)), l_1580))), l_1580)) , (*g_961)); + return l_1580; + } + return p_21; +} + + +/* ------------------------------------------ */ +/* + * reads : g_52 g_46 g_51 + * writes: g_52 g_51 g_36 g_40 + */ +static uint32_t * func_22(int16_t p_23, uint32_t p_24, uint32_t * p_25) +{ /* block id: 10 */ + int32_t *l_45 = &g_46; + int32_t *l_47 = (void*)0; + int32_t *l_48 = &g_46; + int32_t *l_49 = &g_46; + int32_t *l_50[1]; + int i; + for (i = 0; i < 1; i++) + l_50[i] = &g_46; + --g_52; + g_51[0][3][1] &= (*l_48); + for (g_52 = 0; g_52 < 2; g_52 += 1) + { + for (g_36 = 0; g_36 < 8; g_36 += 1) + { + for (p_24 = 0; p_24 < 3; p_24 += 1) + { + g_51[g_52][g_36][p_24] = 0x6F67A21EL; + } + } + } + for (p_24 = 0; p_24 < 7; p_24 += 1) + { + g_40[p_24] = 248UL; + } + return l_50[0]; +} + + +/* ------------------------------------------ */ +/* + * reads : g_143 g_140 + * writes: g_140 + */ +static int32_t func_62(int32_t * p_63, uint8_t p_64) +{ /* block id: 663 */ + uint32_t l_1384 = 4294967295UL; + (*g_143) &= l_1384; + return (*g_143); +} + + +/* ------------------------------------------ */ +/* + * reads : g_143 g_140 g_1132 g_735 g_736 g_55 g_289 g_290 g_56 g_176 g_43 g_1184 g_1185 g_1099 g_44 g_297 g_36 g_51 g_705 g_34 g_131 g_132 g_243 g_347 g_320 g_294 g_175 g_255 g_897 g_905 g_251 g_960 g_969 g_961 g_312 g_1334 + * writes: g_1132 g_44 g_36 g_140 g_312 g_51 g_34 g_56 g_297 g_347 g_290 g_255 g_897 g_904 g_294 g_419 g_251 g_969 g_1334 + */ +static int32_t * func_65(int8_t p_66, uint16_t p_67, uint8_t p_68, int32_t * p_69, uint32_t * p_70) +{ /* block id: 647 */ + int32_t *l_1342 = &g_1132; + int8_t *l_1361 = &g_36; + uint16_t *l_1362[3][5][2] = {{{&g_969,&g_969},{&g_969,&g_969},{&g_969,&g_969},{&g_969,&g_969},{&g_969,&g_969}},{{&g_969,&g_969},{&g_969,&g_969},{&g_969,&g_969},{&g_969,&g_969},{&g_969,&g_969}},{{&g_969,&g_969},{&g_969,&g_969},{&g_969,(void*)0},{&g_969,&g_969},{&g_251,&g_251}}}; + int32_t l_1363[2]; + uint32_t *l_1375[6][5] = {{(void*)0,&g_477,&g_1099,&g_1099,&g_477},{(void*)0,&g_294[0],&g_1099,&g_477,&g_1334},{&g_294[0],&g_1099,&g_1099,(void*)0,&g_1099},{&g_1334,&g_1334,&g_1099,(void*)0,(void*)0},{&g_294[0],(void*)0,(void*)0,(void*)0,(void*)0},{(void*)0,&g_294[2],(void*)0,(void*)0,&g_1334}}; + int32_t l_1376 = 1L; + uint32_t l_1379 = 0xCFCA353CL; + const uint32_t **l_1382 = (void*)0; + const uint32_t ***l_1381 = &l_1382; + const uint32_t ****l_1380[2][1][7] = {{{(void*)0,&l_1381,&l_1381,&l_1381,(void*)0,&l_1381,&l_1381}},{{(void*)0,&l_1381,&l_1381,&l_1381,(void*)0,&l_1381,&l_1381}}}; + const uint32_t ***l_1383 = &l_1382; + int i, j, k; + for (i = 0; i < 2; i++) + l_1363[i] = 0xABF6ADA9L; + (*l_1342) ^= (*g_143); + if (g_140) + goto lbl_1364; + p_69 = func_94((**g_735), (*l_1342), (((((((safe_div_func_int32_t_s_s((safe_mul_func_uint16_t_u_u((safe_rshift_func_int16_t_s_u(p_66, (0xC741L && (((safe_div_func_int8_t_s_s((((safe_mul_func_uint8_t_u_u(0xD3L, (safe_rshift_func_int16_t_s_s((safe_add_func_uint16_t_u_u(((0L > (*g_289)) & (((l_1363[0] = ((p_68 = (safe_mul_func_uint8_t_u_u((((*l_1361) = ((((**g_176) = (safe_mod_func_int16_t_s_s(((((***g_735) , 0x0EL) >= (*l_1342)) || (*g_289)), p_68))) <= 0x01L) < (*l_1342))) , (*l_1342)), p_68))) != 0xDAL)) != p_66) == (*l_1342))), (***g_1184))), 10)))) & 0xF1L) != 249UL), (*l_1342))) != (***g_1184)) > 0x40L)))), (*l_1342))), (*p_70))) , (void*)0) == l_1361) <= g_1099) < (*l_1342)) < (*l_1342)) , (*g_143)), (*l_1342), (*l_1342)); +lbl_1364: + (*g_143) = (+(*l_1342)); + (*g_143) = (1UL == (((safe_rshift_func_int8_t_s_u((safe_lshift_func_int8_t_s_s(((void*)0 != (*g_905)), (3UL != ((safe_rshift_func_int8_t_s_s(((l_1383 = ((((safe_div_func_uint32_t_u_u((p_66 <= (*l_1342)), (l_1376 = (++(*p_70))))) == g_251) && (g_34 <= (p_67 = (((*l_1342) = (safe_sub_func_int16_t_s_s((((((*l_1342) || (-1L)) != (*l_1342)) == l_1379) <= p_67), 0xD1CDL))) & l_1376)))) , (void*)0)) != (void*)0), 0)) != p_68)))), p_66)) ^ 65535UL) || 1UL)); + return p_69; +} + + +/* ------------------------------------------ */ +/* + * reads : g_51 g_44 g_251 g_143 g_140 g_176 g_43 g_705 g_289 g_290 g_297 g_255 g_55 g_56 g_36 g_34 g_131 g_132 g_243 g_347 g_320 g_736 g_294 g_175 g_897 g_905 g_735 g_960 g_969 g_961 g_312 g_1334 + * writes: g_36 g_255 g_297 g_140 g_312 g_294 g_51 g_34 g_56 g_44 g_347 g_290 g_897 g_904 g_419 g_251 g_969 g_1334 + */ +static uint8_t * func_71(uint32_t p_72, int8_t p_73) +{ /* block id: 19 */ + int32_t *l_75 = &g_51[0][3][1]; + int32_t *l_76 = &g_51[0][2][2]; + int32_t *l_77 = &g_51[0][7][1]; + int32_t *l_78 = &g_51[0][3][1]; + int32_t *l_79 = &g_51[0][5][2]; + int32_t *l_80 = &g_51[0][0][0]; + int32_t *l_81 = &g_51[1][3][1]; + int32_t *l_82 = &g_51[1][0][1]; + int32_t *l_83 = &g_51[0][3][1]; + int32_t *l_84 = (void*)0; + int32_t l_85[9][2][7] = {{{(-4L),(-7L),0x7DDA0CFDL,(-8L),0x77CB2DEBL,0x5D6CB7F0L,0L},{0x9A3785E6L,0x69DBBC94L,(-10L),0x74D9FAD1L,(-10L),0x69DBBC94L,0x9A3785E6L}},{{0x5D6CB7F0L,0x6F9888A1L,1L,0x139E91ECL,0xC7048B0AL,0xFEAE78DFL,0x4ABCDCAFL},{(-10L),(-8L),(-1L),3L,0x74D9FAD1L,4L,0x204C5B33L}},{{0x7DDA0CFDL,4L,1L,7L,0x6F9888A1L,7L,1L},{0xB031E64CL,0xB031E64CL,(-10L),1L,0x2DE0ECACL,0x40782372L,0x501D8DD5L}},{{0x6F9888A1L,0x24FAE1B8L,0x7DDA0CFDL,1L,0x4ABCDCAFL,4L,(-7L)},{(-1L),0xEF1A95A0L,0x40782372L,0x53E6AFD1L,0x2DE0ECACL,1L,0x2DE0ECACL}},{{0L,0x4ABCDCAFL,0x4ABCDCAFL,0L,0x6F9888A1L,(-1L),0xE2E886BEL},{0x53E6AFD1L,0x40782372L,0xEF1A95A0L,(-1L),0x74D9FAD1L,0x204C5B33L,1L}},{{1L,0x7DDA0CFDL,0x24FAE1B8L,0x6F9888A1L,0xC7048B0AL,(-4L),0xE2E886BEL},{1L,(-10L),0xB031E64CL,0xB031E64CL,(-10L),1L,0x2DE0ECACL}},{{7L,1L,4L,0x7DDA0CFDL,0x77CB2DEBL,(-1L),(-7L)},{3L,(-1L),(-8L),(-10L),0x53E6AFD1L,0x9A3785E6L,0x501D8DD5L}},{{0x139E91ECL,1L,0x6F9888A1L,0x5D6CB7F0L,0x5D6CB7F0L,0x6F9888A1L,1L},{0x74D9FAD1L,(-10L),0x69DBBC94L,0x9A3785E6L,0x75422B1FL,(-1L),0x204C5B33L}},{{(-8L),0x7DDA0CFDL,(-7L),(-4L),(-1L),0xA96CD894L,0x4ABCDCAFL},{0x69DBBC94L,0x40782372L,0x204C5B33L,0x9A3785E6L,(-8L),(-8L),0x9A3785E6L}}}; + int32_t *l_86 = &l_85[0][1][0]; + int32_t *l_87 = (void*)0; + int32_t *l_88 = &l_85[1][1][4]; + int32_t *l_89 = &g_51[0][3][1]; + int32_t *l_90[3][9] = {{(void*)0,(void*)0,&g_51[0][5][2],(void*)0,(void*)0,&g_51[0][5][2],(void*)0,(void*)0,&g_51[0][5][2]},{&g_3,&g_3,(void*)0,&g_3,&g_3,(void*)0,&g_51[0][3][1],&g_51[0][3][1],&g_3},{(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0,(void*)0}}; + uint8_t l_91[9][7][4] = {{{0x14L,253UL,255UL,0x88L},{0x51L,0x35L,0x0BL,254UL},{0xC0L,255UL,1UL,0x5BL},{253UL,0x8DL,0x88L,0x2BL},{0xD1L,0x2CL,0UL,0x01L},{0x9AL,0xD1L,0x35L,0x80L},{0x16L,0x3AL,0x9AL,0x39L}},{{6UL,1UL,0xF3L,0UL},{0x51L,1UL,0x4FL,1UL},{1UL,0x01L,0x50L,0xE4L},{0x30L,0x9AL,1UL,0UL},{0x93L,0x2CL,0x2CL,0x93L},{255UL,1UL,0xA9L,255UL},{4UL,2UL,0x4CL,0x88L}},{{0x5BL,254UL,0xF3L,0x88L},{0UL,2UL,1UL,255UL},{0xDFL,1UL,0x24L,0x93L},{0x23L,0x2CL,0x41L,0UL},{0xD1L,0x9AL,4UL,0xE4L},{0x16L,0x01L,0x23L,1UL},{0x2CL,1UL,248UL,0UL}},{{0x5BL,1UL,255UL,0x39L},{1UL,0x3AL,0x50L,0x80L},{0x80L,0xD1L,0x16L,0x01L},{0x5EL,0x2CL,1UL,0x2BL},{0xE4L,0x8DL,0xF0L,0x5BL},{4UL,255UL,0x51L,254UL},{0x4CL,0x35L,248UL,0x88L}},{{6UL,253UL,0UL,255UL},{253UL,0xF9L,0x24L,0x4DL},{248UL,6UL,0UL,0x01L},{0x23L,0x9AL,0x88L,5UL},{4UL,0UL,0x9AL,1UL},{0x2CL,0x14L,0xEBL,248UL},{0x4CL,1UL,0x4CL,0x39L}},{{0x14L,0xFDL,254UL,251UL},{0x30L,0x23L,0x16L,0xFDL},{0x4DL,6UL,0x16L,0x93L},{0x30L,0x8DL,254UL,0x4FL},{0x14L,0x30L,0x4CL,0xB0L},{0x4CL,0xB0L,0xEBL,254UL},{0x2CL,2UL,0x9AL,255UL}},{{4UL,1UL,0x88L,0x16L},{0x23L,0UL,0UL,0xFDL},{248UL,0xD1L,0x24L,0x8DL},{0xA2L,0xC0L,0x24L,2UL},{0x6AL,0x80L,0xDFL,4UL},{0xFDL,255UL,0x2CL,253UL},{0x80L,0xD2L,255UL,0UL}},{{0x8DL,0x88L,0x2BL,0x16L},{0xA5L,0xF0L,0x5EL,0UL},{0x39L,0x30L,0xEBL,0UL},{0x04L,1UL,0UL,1UL},{0UL,1UL,0xDFL,4UL},{0x4DL,0xF0L,1UL,0x41L},{255UL,1UL,1UL,1UL}},{{4UL,0x16L,0x16L,0x16L},{1UL,1UL,1UL,0x39L},{255UL,0x2CL,0x35L,0x30L},{0xF0L,0x80L,250UL,0x35L},{0UL,0x80L,0xFDL,0x30L},{0x80L,0x2CL,1UL,0x39L},{1UL,1UL,0x4DL,0x16L}}}; + uint32_t *l_115[8] = {&g_56,&g_56,&g_56,&g_56,&g_56,&g_56,&g_56,&g_56}; + int8_t *l_118 = &g_36; + int8_t **l_119 = &l_118; + int8_t *l_121 = &g_36; + int8_t **l_120 = &l_121; + int8_t **l_122 = (void*)0; + int8_t *l_124 = &g_36; + int8_t **l_123 = &l_124; + int8_t *l_126 = &g_36; + int8_t **l_125 = &l_126; + int8_t *l_127[7][8][4] = {{{&g_36,&g_36,&g_36,&g_36},{(void*)0,&g_36,&g_36,&g_36},{(void*)0,(void*)0,&g_36,&g_36},{(void*)0,(void*)0,(void*)0,(void*)0},{&g_36,&g_36,&g_36,(void*)0},{(void*)0,&g_36,&g_36,(void*)0},{&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,(void*)0}},{{(void*)0,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36},{(void*)0,&g_36,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36}},{{&g_36,&g_36,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36},{&g_36,&g_36,&g_36,(void*)0},{&g_36,&g_36,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36},{(void*)0,&g_36,&g_36,(void*)0},{&g_36,&g_36,&g_36,(void*)0},{&g_36,&g_36,&g_36,&g_36}},{{&g_36,(void*)0,&g_36,(void*)0},{&g_36,&g_36,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36},{(void*)0,(void*)0,&g_36,&g_36},{&g_36,&g_36,(void*)0,&g_36},{&g_36,(void*)0,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36},{&g_36,&g_36,(void*)0,&g_36}},{{(void*)0,&g_36,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36},{(void*)0,&g_36,(void*)0,&g_36},{&g_36,&g_36,&g_36,&g_36},{&g_36,(void*)0,(void*)0,&g_36},{&g_36,(void*)0,(void*)0,(void*)0},{&g_36,&g_36,&g_36,&g_36}},{{&g_36,&g_36,&g_36,&g_36},{(void*)0,&g_36,(void*)0,(void*)0},{&g_36,(void*)0,&g_36,&g_36},{(void*)0,(void*)0,(void*)0,&g_36},{&g_36,&g_36,&g_36,&g_36},{(void*)0,&g_36,(void*)0,&g_36},{(void*)0,&g_36,&g_36,&g_36},{&g_36,(void*)0,(void*)0,&g_36}},{{&g_36,&g_36,(void*)0,&g_36},{&g_36,&g_36,&g_36,&g_36},{(void*)0,(void*)0,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36},{&g_36,&g_36,&g_36,&g_36},{&g_36,(void*)0,&g_36,&g_36},{&g_36,&g_36,&g_36,(void*)0},{&g_36,&g_36,&g_36,&g_36}}}; + int8_t *l_129 = &g_36; + int8_t **l_128 = &l_129; + int8_t *l_130[4][2] = {{(void*)0,(void*)0},{(void*)0,(void*)0},{(void*)0,(void*)0},{(void*)0,(void*)0}}; + int32_t l_690 = (-1L); + int i, j, k; + ++l_91[2][2][0]; + (*g_961) = func_94(&g_56, ((g_51[1][1][2] >= func_100(func_105(((g_44 ^ ((g_44 , (safe_sub_func_int8_t_s_s((g_36 = (safe_add_func_uint8_t_u_u((safe_sub_func_int8_t_s_s(((*l_86) |= (((~(&g_56 != l_115[6])) , (((((safe_rshift_func_uint16_t_u_u(1UL, 14)) < ((((l_127[6][3][0] = ((*l_125) = ((*l_123) = ((*l_120) = ((*l_119) = l_118))))) == ((*l_128) = &p_73)) ^ 255UL) == p_73)) == 0xCAL) && 8L) ^ 0x2359L)) , p_72)), p_72)), g_51[1][2][0]))), 0xA4L))) == 6UL)) < 0xD5L)), l_690, (*l_79), g_251)) <= 255UL), p_72, (*l_77), p_73); + return (**g_905); +} + + +/* ------------------------------------------ */ +/* + * reads : g_36 g_176 g_43 g_44 g_297 g_143 g_140 g_51 g_705 g_34 g_131 g_132 g_55 g_56 g_243 g_289 g_347 g_320 g_736 g_294 g_175 g_255 g_897 g_905 g_290 g_735 g_251 g_960 g_969 g_961 g_312 g_1334 + * writes: g_36 g_140 g_312 g_51 g_34 g_56 g_297 g_44 g_347 g_290 g_255 g_897 g_904 g_294 g_419 g_251 g_969 g_1334 + */ +static int32_t * func_94(uint32_t * p_95, int32_t p_96, const int32_t p_97, int32_t p_98, int8_t p_99) +{ /* block id: 395 */ + int8_t l_778 = (-5L); + int32_t l_868[8] = {0xC949261DL,0xC949261DL,0xC949261DL,0xC949261DL,0xC949261DL,0xC949261DL,0xC949261DL,0xC949261DL}; + int32_t l_885 = 0L; + int32_t l_891 = 0x3573B375L; + int16_t * const l_916 = &g_419; + uint8_t *** const l_948 = &g_175; + int32_t l_982 = (-1L); + uint32_t *l_983 = &g_294[4]; + int32_t l_984 = 1L; + int8_t l_998 = 0L; + uint8_t ****l_1044[3]; + uint8_t l_1256 = 3UL; + int16_t l_1325[10][7] = {{0x9403L,(-1L),0x5345L,0x2B69L,0x41E0L,0x8199L,0x8199L},{0x640AL,(-1L),0x93F5L,(-1L),0x640AL,0xF19AL,0x93F5L},{(-1L),0x9403L,(-1L),0x5345L,0x2B69L,0x41E0L,0x8199L},{0xD399L,1L,0x6F08L,0xF19AL,0x6F08L,1L,0xD399L},{(-1L),0x5345L,0x8199L,0x2B69L,0x9403L,0x23E0L,(-1L)},{0x640AL,1L,1L,8L,0x640AL,8L,1L},{0x9403L,0x9403L,0x8199L,(-1L),(-1L),0x41E0L,0x5345L},{0x6F08L,(-1L),0x6F08L,8L,0xD399L,(-1L),0xD399L},{0x2B69L,(-1L),(-1L),0x2B69L,(-1L),0x8199L,0x23E0L},{0x640AL,0xF19AL,0x93F5L,0xF19AL,0x640AL,(-1L),0x93F5L}}; + int32_t *l_1339 = &g_51[1][1][1]; + int i, j; + for (i = 0; i < 3; i++) + l_1044[i] = &g_905; + for (g_36 = 0; (g_36 <= (-2)); --g_36) + { /* block id: 398 */ + if (l_778) + break; + } + (*g_143) = ((safe_mod_func_int32_t_s_s((safe_sub_func_uint8_t_u_u(l_778, (**g_176))), (safe_div_func_int16_t_s_s((-1L), (safe_add_func_int16_t_s_s(((void*)0 == &p_95), p_99)))))) , (safe_mul_func_int8_t_s_s(((safe_div_func_uint16_t_u_u((((safe_add_func_int32_t_s_s(p_96, 4294967286UL)) >= 0xB233L) && p_99), g_297[1])) & p_96), 0xFEL))); + for (g_36 = 1; (g_36 >= 0); g_36 -= 1) + { /* block id: 404 */ + int16_t l_806[2]; + int32_t l_814 = (-9L); + uint8_t *l_846[6][2][10] = {{{&g_40[1],&g_44,&g_320,&g_44,(void*)0,(void*)0,(void*)0,(void*)0,&g_320,(void*)0},{&g_40[0],&g_44,(void*)0,&g_40[1],&g_320,&g_40[5],&g_40[5],&g_320,&g_40[1],(void*)0}},{{(void*)0,(void*)0,&g_320,&g_320,&g_40[0],&g_40[3],(void*)0,&g_40[1],&g_44,&g_320},{&g_320,&g_40[1],&g_44,(void*)0,&g_40[1],&g_44,(void*)0,(void*)0,&g_40[6],&g_40[5]}},{{&g_40[5],(void*)0,&g_40[1],&g_40[1],&g_320,&g_320,&g_40[5],&g_40[5],&g_40[5],&g_40[1]},{(void*)0,&g_44,(void*)0,&g_44,&g_40[2],&g_40[5],(void*)0,&g_44,(void*)0,&g_40[1]}},{{(void*)0,&g_44,&g_40[0],(void*)0,&g_40[1],(void*)0,&g_40[0],&g_44,(void*)0,(void*)0},{&g_40[1],&g_40[1],&g_320,&g_44,&g_40[0],(void*)0,&g_44,(void*)0,&g_44,(void*)0}},{{&g_40[0],&g_320,(void*)0,&g_44,&g_40[6],&g_320,(void*)0,&g_40[3],(void*)0,&g_320},{(void*)0,(void*)0,&g_40[5],(void*)0,&g_40[1],&g_40[6],&g_40[1],&g_320,(void*)0,&g_44}},{{&g_40[2],&g_320,&g_320,&g_44,&g_40[3],&g_320,&g_44,&g_40[5],&g_40[5],&g_44},{(void*)0,(void*)0,&g_40[1],&g_40[1],(void*)0,(void*)0,(void*)0,&g_40[0],&g_40[6],(void*)0}}}; + int32_t l_870 = 0x0B9A60E1L; + int32_t l_872 = (-5L); + int32_t l_879 = 0x68AC52C0L; + int32_t l_880 = 1L; + int32_t l_882 = (-3L); + int32_t l_883 = 0x329F4C9FL; + int32_t l_884 = (-2L); + int32_t l_887 = 0x1D6C2448L; + int32_t l_888[9]; + uint8_t ***l_903 = &g_175; + uint8_t ****l_902[5][1] = {{&l_903},{&l_903},{&l_903},{&l_903},{&l_903}}; + int8_t **l_919 = &g_243[1][0][1]; + int i, j, k; + for (i = 0; i < 2; i++) + l_806[i] = 0xDFCAL; + for (i = 0; i < 9; i++) + l_888[i] = 0xAEB8A862L; + for (g_140 = 0; (g_140 <= 1); g_140 += 1) + { /* block id: 407 */ + const uint16_t l_807 = 0UL; + int32_t *l_809 = (void*)0; + int32_t *l_864 = &g_297[1]; + int32_t l_867 = 0xB4D5446DL; + int32_t l_869 = 1L; + int32_t l_871 = 0L; + int32_t l_873 = (-1L); + int8_t l_874 = 1L; + int32_t l_875 = 0x566BCB73L; + int32_t l_876 = 0x640B2514L; + int32_t l_877 = (-10L); + int32_t l_878 = 0L; + int32_t l_881[1][2][1]; + int32_t l_890 = (-10L); + int i, j, k; + for (i = 0; i < 1; i++) + { + for (j = 0; j < 2; j++) + { + for (k = 0; k < 1; k++) + l_881[i][j][k] = (-1L); + } + } + for (p_98 = 0; (p_98 <= 1); p_98 += 1) + { /* block id: 410 */ + uint16_t *l_837[7][2][10] = {{{&g_251,(void*)0,&g_251,(void*)0,&g_251,&g_251,&g_251,(void*)0,&g_251,(void*)0},{(void*)0,&g_251,&g_251,&g_251,(void*)0,&g_251,&g_251,&g_251,&g_251,&g_251}},{{&g_251,&g_251,&g_251,(void*)0,&g_251,&g_251,&g_251,(void*)0,&g_251,&g_251},{(void*)0,&g_251,&g_251,(void*)0,&g_251,&g_251,(void*)0,&g_251,&g_251,&g_251}},{{&g_251,&g_251,(void*)0,&g_251,(void*)0,&g_251,&g_251,&g_251,&g_251,(void*)0},{(void*)0,&g_251,&g_251,(void*)0,&g_251,&g_251,&g_251,(void*)0,&g_251,(void*)0}},{{&g_251,&g_251,&g_251,&g_251,(void*)0,(void*)0,&g_251,&g_251,&g_251,(void*)0},{(void*)0,&g_251,(void*)0,&g_251,&g_251,(void*)0,&g_251,(void*)0,(void*)0,&g_251}},{{&g_251,&g_251,&g_251,(void*)0,&g_251,&g_251,&g_251,&g_251,&g_251,&g_251},{(void*)0,&g_251,&g_251,&g_251,&g_251,&g_251,(void*)0,&g_251,(void*)0,&g_251}},{{&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,(void*)0,&g_251},{&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,(void*)0,&g_251,&g_251,(void*)0}},{{&g_251,&g_251,&g_251,&g_251,&g_251,(void*)0,&g_251,(void*)0,&g_251,&g_251},{&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,&g_251,&g_251}}}; + int32_t l_848 = (-7L); + uint8_t *l_856 = &g_40[0]; + int32_t *l_860 = &l_848; + int i, j, k; + g_312[0][0][5] = (void*)0; + g_51[g_36][(p_98 + 1)][g_140] ^= 0x87124F79L; + for (g_34 = 0; (g_34 <= 1); g_34 += 1) + { /* block id: 415 */ + uint32_t l_805[5]; + int32_t *l_808 = &g_297[1]; + int i, j, k; + for (i = 0; i < 5; i++) + l_805[i] = 0UL; + (*l_808) ^= (((safe_mod_func_int32_t_s_s((!(~((g_51[g_36][g_140][g_36] != (g_705[p_98] && ((*g_55) |= ((g_705[(g_34 + 3)] <= ((safe_add_func_int16_t_s_s(g_705[(g_34 + 3)], (safe_sub_func_int32_t_s_s((2UL != ((safe_sub_func_int8_t_s_s(p_98, p_97)) , (safe_mul_func_int16_t_s_s((safe_add_func_int8_t_s_s((((g_51[0][3][1] < l_778) || l_805[0]) > (*g_143)), (**g_131))), l_806[0])))), l_778)))) > 0x76L)) & g_34)))) | l_807))), p_96)) > l_778) ^ p_99); + l_809 = &p_98; + } + for (p_96 = 0; (p_96 <= 1); p_96 += 1) + { /* block id: 422 */ + uint8_t l_847 = 1UL; + int i, j, k; + if (g_51[p_98][(g_36 + 5)][g_140]) + break; + l_814 = ((safe_mul_func_uint16_t_u_u(0x9540L, 65535UL)) <= (++(*g_43))); + for (g_347 = 4; (g_347 >= 0); g_347 -= 1) + { /* block id: 428 */ + int8_t *l_851 = &g_255; + int32_t *l_859 = &g_297[1]; + int i, j, k; + l_848 = (safe_rshift_func_int16_t_s_s((-1L), ((safe_mod_func_uint32_t_u_u(((g_51[g_140][(g_140 + 5)][g_140] = (safe_sub_func_int8_t_s_s((((safe_div_func_uint32_t_u_u(g_51[g_140][(g_36 + 2)][(g_140 + 1)], 2L)) <= (safe_unary_minus_func_uint32_t_u((safe_sub_func_int8_t_s_s((((safe_rshift_func_int8_t_s_s(((safe_add_func_int8_t_s_s((p_98 ^ (safe_add_func_int16_t_s_s((safe_sub_func_int16_t_s_s((safe_mul_func_uint8_t_u_u((((~(safe_unary_minus_func_int8_t_s((((((&g_251 == l_837[2][0][1]) ^ ((-1L) == ((*g_289) = (safe_lshift_func_uint16_t_u_s((l_814 = ((safe_lshift_func_int16_t_s_u(g_51[g_140][(g_36 + 2)][(g_140 + 1)], 13)) >= (safe_sub_func_uint8_t_u_u(((safe_div_func_int8_t_s_s((((g_243[(g_36 + 1)][g_36][(p_96 + 3)] == l_846[0][1][8]) == 0xC75DL) <= g_51[g_140][(g_36 + 2)][(g_140 + 1)]), g_51[p_98][(g_36 + 5)][g_140])) | p_99), 255UL)))), p_98))))) > l_847) , l_778) < 0x4EDBL)))) | g_347) != l_778), (*g_132))), g_51[p_98][(g_36 + 5)][g_140])), 0x4155L))), (*g_43))) <= (-4L)), 4)) < g_320) <= p_97), 0x7DL))))) | 0xE6F3L), p_96))) && (**g_736)), 1UL)) | 0x59L))); + if (p_97) + break; + (*l_859) ^= ((*p_95) && (((safe_div_func_int8_t_s_s(((*l_851) = (g_294[0] >= 0x74B3L)), ((**g_175) = (**g_176)))) , (safe_sub_func_uint8_t_u_u(((!(l_814 = (safe_mod_func_int8_t_s_s(((*l_851) ^= (l_856 == (void*)0)), (p_99 = (safe_lshift_func_int16_t_s_u(g_51[g_140][(g_140 + 5)][g_140], 2))))))) > g_51[g_36][(p_98 + 1)][g_140]), l_778))) , 0UL)); + l_860 = &l_814; + } + for (g_56 = 0; (g_56 <= 1); g_56 += 1) + { /* block id: 444 */ + int32_t **l_861 = &l_809; + (*l_861) = &g_51[0][3][1]; + if (p_99) + break; + } + } + } + (*l_864) = (((l_806[0] , (safe_lshift_func_uint8_t_u_u((p_97 ^ 0UL), 2))) & (~1UL)) == (**g_736)); + for (p_98 = 1; (p_98 >= 0); p_98 -= 1) + { /* block id: 453 */ + int32_t *l_865 = &l_814; + int32_t *l_866[5]; + int16_t l_886[3]; + int32_t l_889 = 0xF193AD92L; + uint32_t l_892 = 4294967295UL; + uint16_t *l_920 = &g_251; + uint32_t l_931 = 4UL; + const uint8_t *l_951[4]; + const uint8_t **l_950 = &l_951[3]; + const uint8_t *** const l_949 = &l_950; + int32_t ***l_962[9] = {&g_961,&g_961,&g_961,&g_961,&g_961,&g_961,&g_961,&g_961,&g_961}; + int i; + for (i = 0; i < 5; i++) + l_866[i] = (void*)0; + for (i = 0; i < 3; i++) + l_886[i] = 0x4E3AL; + for (i = 0; i < 4; i++) + l_951[i] = (void*)0; + l_892--; + for (l_877 = 4; (l_877 >= 0); l_877 -= 1) + { /* block id: 457 */ + uint8_t *****l_898 = (void*)0; + uint8_t *****l_899 = (void*)0; + uint8_t *****l_900 = (void*)0; + uint8_t *****l_901 = (void*)0; + int32_t l_929 = 0x9F81C2E6L; + int32_t l_930[6]; + uint32_t l_954 = 0UL; + int i, j, k; + for (i = 0; i < 6; i++) + l_930[i] = 0xF1E80E14L; + if ((safe_rshift_func_uint16_t_u_s((&g_736 == &g_736), (((g_294[g_140] != g_294[p_98]) && (((1UL != (((g_897 = g_897) != (g_904[0][3] = l_902[0][0])) != ((*g_289) = (((g_294[(g_140 + 1)] = ((safe_mod_func_int16_t_s_s(((**g_131) , (((p_97 || l_882) != 0x37DD31F2L) | 0L)), p_97)) || (*g_143))) ^ (*l_865)) , 1L)))) == (***g_905)) , (*g_289))) ^ (-7L))))) + { /* block id: 462 */ + uint16_t l_921 = 1UL; + int32_t l_922 = 0xB991C690L; + l_922 &= (safe_rshift_func_int8_t_s_u((((safe_div_func_uint8_t_u_u((((l_921 = (((((safe_lshift_func_uint8_t_u_u((1UL != (((safe_rshift_func_uint8_t_u_s((((void*)0 == l_916) == 0xDFCCF46BL), (((((*l_864) | ((p_99 = ((l_920 = (((l_868[1] , l_919) != &g_243[(p_98 + 3)][g_36][(p_98 + 6)]) , (void*)0)) == (void*)0)) <= g_294[(g_140 + 1)])) & 3UL) <= (***g_735)) || (**g_736)))) <= (***g_905)) > g_294[(g_140 + 1)])), p_98)) == (*g_289)) < g_51[0][3][1]) | p_98) , (**g_175))) < 0x64L) < l_814), l_888[1])) , (-4L)) , l_868[6]), 1)); + } + else + { /* block id: 467 */ + uint8_t l_923 = 0xE8L; + int32_t l_926 = (-9L); + int32_t l_927 = 8L; + int32_t l_928 = (-1L); + --l_923; + if (p_96) + continue; + l_931++; + } + (*l_864) = (safe_sub_func_uint8_t_u_u((((*l_865) = (((safe_div_func_uint8_t_u_u(((safe_mod_func_uint16_t_u_u(0xDC88L, (safe_rshift_func_int16_t_s_s(((0UL ^ (-6L)) > p_97), ((safe_add_func_uint16_t_u_u(l_868[6], (safe_add_func_int16_t_s_s((safe_rshift_func_uint8_t_u_s((l_948 == l_949), ((safe_sub_func_int16_t_s_s((l_954 > ((&g_289 != (void*)0) & g_140)), 0x0045L)) > 0UL))), 0xB58DL)))) < (*g_289)))))) < (***g_735)), l_868[6])) != p_98) | p_99)) & (*g_55)), 0x4AL)); + (*l_864) &= 0xD1CAA0FBL; + } + for (l_778 = 1; (l_778 >= 0); l_778 -= 1) + { /* block id: 478 */ + int16_t *l_959 = &l_806[1]; + int32_t l_965 = (-8L); + int8_t *l_966 = &g_255; + uint16_t *l_967 = &g_251; + uint16_t *l_968 = &g_969; + int i, j, k; + (*l_864) = (p_96 |= l_888[6]); + p_96 = (((6UL <= ((safe_mod_func_int8_t_s_s((g_251 , (((*g_289) <= (safe_mod_func_int16_t_s_s(((*l_959) &= ((*l_916) = 0x3137L)), (((g_960 != l_962[4]) , ((*l_968) &= ((*l_967) = ((((safe_add_func_uint16_t_u_u(0xEADCL, ((((((*l_966) &= (l_965 == l_879)) == 0xA5L) , p_96) >= p_96) ^ (*p_95)))) , 5UL) & (*g_143)) , p_99)))) , (*g_289))))) ^ (**g_176))), 3L)) == (*g_55))) && (**g_131)) <= p_97); + } + } + } + if (l_868[6]) + break; + } + if ((p_98 = (safe_mod_func_int16_t_s_s((*g_289), (safe_add_func_uint32_t_u_u(((l_984 = (0x4C7D768FL <= ((*l_983) ^= (safe_mul_func_int8_t_s_s(((**g_736) || (l_982 &= ((p_98 == (safe_sub_func_uint32_t_u_u((((l_948 == l_948) | (safe_lshift_func_int8_t_s_s((0x454BL <= l_868[3]), 0))) ^ ((safe_lshift_func_uint8_t_u_s((!255UL), 0)) <= l_885)), (*p_95)))) || (*g_55)))), 0x15L))))) & l_778), (*p_95))))))) + { /* block id: 496 */ + uint8_t ***l_993 = &g_175; + int16_t l_999 = 0x1B88L; + int8_t *** const *l_1034 = &g_1019[1][0][0]; + int32_t *l_1046 = &l_982; + int32_t l_1048[1][2][7] = {{{0xEA46108CL,0xEA46108CL,0xEA46108CL,0xEA46108CL,0xEA46108CL,0xEA46108CL,0xEA46108CL},{(-1L),(-1L),(-1L),(-1L),(-1L),(-1L),(-1L)}}}; + uint32_t l_1093[3]; + uint16_t l_1131 = 0xE112L; + int16_t **l_1135[6][2][5] = {{{&g_289,&g_289,&g_289,&g_289,(void*)0},{&g_289,&g_289,&g_289,&g_289,&g_289}},{{&g_289,(void*)0,&g_289,(void*)0,&g_289},{&g_289,&g_289,&g_289,(void*)0,(void*)0}},{{&g_289,(void*)0,(void*)0,&g_289,&g_289},{&g_289,(void*)0,(void*)0,&g_289,(void*)0}},{{(void*)0,&g_289,&g_289,&g_289,&g_289},{(void*)0,&g_289,(void*)0,&g_289,&g_289}},{{&g_289,&g_289,&g_289,&g_289,(void*)0},{&g_289,&g_289,&g_289,&g_289,&g_289}},{{&g_289,&g_289,&g_289,(void*)0,(void*)0},{&g_289,(void*)0,(void*)0,(void*)0,(void*)0}}}; + int32_t l_1180 = 0L; + uint8_t l_1276[9]; + int32_t *l_1294 = &g_1132; + int32_t *l_1320 = &g_51[0][3][1]; + int32_t *l_1321 = &g_140; + int32_t *l_1322 = &g_297[1]; + int32_t *l_1323 = &l_1048[0][1][0]; + int32_t *l_1324[1]; + int16_t l_1326 = 0x2195L; + int32_t l_1327 = 0x947976B8L; + uint16_t l_1328 = 0x24D6L; + int i, j, k; + for (i = 0; i < 3; i++) + l_1093[i] = 1UL; + for (i = 0; i < 9; i++) + l_1276[i] = 255UL; + for (i = 0; i < 1; i++) + l_1324[i] = &l_1048[0][0][6]; + for (g_44 = 0; (g_44 <= 6); g_44 += 1) + { /* block id: 499 */ + uint8_t ***l_994 = &g_175; + int8_t l_997 = 0xA6L; + int8_t ***l_1017 = &g_245; + int8_t ****l_1016 = &l_1017; + int32_t l_1050 = 0xF31EAA3DL; + int32_t l_1051 = 0x0917F34DL; + int32_t l_1056 = 0x36E77B1BL; + int32_t l_1057 = 0x4D998F65L; + int8_t l_1113 = 0x9DL; + uint32_t l_1114[6]; + int32_t l_1168 = 0xF8E5B00AL; + int32_t l_1170 = 0x729BDDB8L; + int32_t l_1171 = 1L; + int32_t l_1172 = (-1L); + int32_t l_1173 = 0L; + int32_t l_1176[5][7][6] = {{{0xBDCB05A3L,0L,0xCD8737B6L,0L,0xBDCB05A3L,0xC7DD3347L},{0L,0xBDCB05A3L,0xC7DD3347L,0xC7DD3347L,0xBDCB05A3L,0L},{(-6L),0L,0xF426EDDCL,0xBDCB05A3L,0xF426EDDCL,0L},{0xF426EDDCL,(-6L),0xC7DD3347L,0xCD8737B6L,0xCD8737B6L,0xCD8737B6L},{0xA0CC386BL,0xA0CC386BL,0xF426EDDCL,0xC7DD3347L,0L,0xC7DD3347L},{0xBDCB05A3L,0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL},{(-6L),0xBDCB05A3L,0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L}},{{0xC7DD3347L,(-6L),0xF426EDDCL,(-6L),0xC7DD3347L,0xCD8737B6L},{(-6L),0xC7DD3347L,0xCD8737B6L,0xCD8737B6L,0xC7DD3347L,(-6L)},{0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L,0xA0CC386BL,(-6L)},{0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL,0xCD8737B6L},{0xA0CC386BL,0xA0CC386BL,0xF426EDDCL,0xC7DD3347L,0L,0xC7DD3347L},{0xBDCB05A3L,0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL},{(-6L),0xBDCB05A3L,0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L}},{{0xC7DD3347L,(-6L),0xF426EDDCL,(-6L),0xC7DD3347L,0xCD8737B6L},{(-6L),0xC7DD3347L,0xCD8737B6L,0xCD8737B6L,0xC7DD3347L,(-6L)},{0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L,0xA0CC386BL,(-6L)},{0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL,0xCD8737B6L},{0xA0CC386BL,0xA0CC386BL,0xF426EDDCL,0xC7DD3347L,0L,0xC7DD3347L},{0xBDCB05A3L,0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL},{(-6L),0xBDCB05A3L,0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L}},{{0xC7DD3347L,(-6L),0xF426EDDCL,(-6L),0xC7DD3347L,0xCD8737B6L},{(-6L),0xC7DD3347L,0xCD8737B6L,0xCD8737B6L,0xC7DD3347L,(-6L)},{0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L,0xA0CC386BL,(-6L)},{0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL,0xCD8737B6L},{0xA0CC386BL,0xA0CC386BL,0xF426EDDCL,0xC7DD3347L,0L,0xC7DD3347L},{0xBDCB05A3L,0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL},{(-6L),0xBDCB05A3L,0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L}},{{0xC7DD3347L,(-6L),0xF426EDDCL,(-6L),0xC7DD3347L,0xCD8737B6L},{(-6L),0xC7DD3347L,0xCD8737B6L,0xCD8737B6L,0xC7DD3347L,(-6L)},{0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L,0xA0CC386BL,(-6L)},{0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL,0xCD8737B6L},{0xA0CC386BL,0xA0CC386BL,0xF426EDDCL,0xC7DD3347L,0L,0xC7DD3347L},{0xBDCB05A3L,0xA0CC386BL,0xBDCB05A3L,0xCD8737B6L,0xF426EDDCL,0xF426EDDCL},{(-6L),0xBDCB05A3L,0xBDCB05A3L,(-6L),0xA0CC386BL,0xC7DD3347L}}}; + uint32_t l_1319 = 0x3CC17454L; + int i, j, k; + for (i = 0; i < 6; i++) + l_1114[i] = 1UL; + } + --l_1328; + (*g_143) ^= ((*g_960) == (void*)0); + return (**g_960); + } + else + { /* block id: 635 */ + int32_t *l_1331 = &g_51[0][1][1]; + int32_t *l_1332[6] = {&g_1055,&g_1055,&g_1055,&g_1055,&g_1055,&g_1055}; + int i; + ++g_1334; + for (g_347 = 0; (g_347 == 26); g_347 = safe_add_func_uint16_t_u_u(g_347, 7)) + { /* block id: 639 */ + return (*g_961); + } + } + return l_1339; +} + + +/* ------------------------------------------ */ +/* + * reads : g_143 g_140 g_176 g_43 g_44 g_705 g_289 g_290 g_297 g_255 g_55 g_56 + * writes: g_255 g_297 g_140 g_312 g_294 + */ +static int8_t func_100(int32_t * p_101, uint8_t p_102, uint8_t p_103, uint32_t p_104) +{ /* block id: 323 */ + int8_t ***l_692 = (void*)0; + int8_t ****l_691 = &l_692; + int32_t l_697 = 0xB23966F9L; + int32_t l_704 = 0x17C47AB5L; + int32_t l_712 = 0x92F85846L; + uint32_t l_724 = 1UL; + uint32_t l_754 = 0x40901257L; + uint32_t l_755[9][7] = {{0x3F92B650L,0x3F92B650L,0x59DA734BL,0x3F92B650L,0x3F92B650L,0x59DA734BL,0x3F92B650L},{0x1D3867C8L,4294967286UL,4294967295UL,5UL,4294967295UL,4294967286UL,0x1D3867C8L},{0xB66E3024L,0x3F92B650L,0xB66E3024L,0xB66E3024L,0x3F92B650L,0xB66E3024L,0xB66E3024L},{0x1D3867C8L,5UL,0x67201704L,5UL,0x1D3867C8L,4294967295UL,0x1D3867C8L},{0x3F92B650L,0xB66E3024L,0xB66E3024L,0x3F92B650L,0xB66E3024L,0xB66E3024L,0x3F92B650L},{4294967295UL,5UL,4294967295UL,4294967286UL,0x1D3867C8L,4294967286UL,4294967295UL},{0x3F92B650L,0x3F92B650L,0x59DA734BL,0x3F92B650L,0x3F92B650L,0x59DA734BL,0x3F92B650L},{0x1D3867C8L,4294967286UL,4294967295UL,5UL,4294967295UL,4294967286UL,0x1D3867C8L},{0xB66E3024L,0x3F92B650L,0xB66E3024L,0xB66E3024L,0x3F92B650L,0xB66E3024L,0xB66E3024L}}; + int i, j; + if (((l_691 == &l_692) < (safe_mod_func_int16_t_s_s(((safe_mul_func_int16_t_s_s(((l_697 & (0UL != ((l_697 & ((0L ^ 0UL) <= (safe_mod_func_int32_t_s_s((*g_143), (safe_mod_func_uint8_t_u_u((safe_mul_func_uint8_t_u_u(((l_704 = (p_102 > l_697)) & (**g_176)), 0xD2L)), l_697)))))) && (-1L)))) , g_705[2]), (*g_289))) && l_697), (*g_289))))) + { /* block id: 325 */ + int16_t l_715 = (-7L); + int8_t *l_716 = &g_255; + int8_t **l_717 = (void*)0; + (*g_143) ^= (safe_div_func_int8_t_s_s(((((safe_lshift_func_int8_t_s_u(((((0x7466BED0L && ((safe_rshift_func_int8_t_s_s(l_712, ((0x6627434EL > (safe_mod_func_int16_t_s_s(l_715, 0xA37DL))) == ((((~g_297[1]) & p_102) , ((*p_101) = (p_104 < ((*l_716) ^= l_715)))) > (*g_55))))) && p_102)) , l_704) >= 0x8C828013L) , 0x19L), 6)) > l_715) , l_717) == &l_716), 1UL)); + return p_102; + } + else + { /* block id: 330 */ + int32_t **l_718 = &g_312[1][0][5]; + uint32_t *l_766 = &l_755[0][2]; + (*l_718) = p_101; + for (p_103 = 25; (p_103 != 48); ++p_103) + { /* block id: 334 */ + int8_t l_723[9][8][3] = {{{0x6BL,0L,0xCAL},{0xF4L,0xB1L,0x8BL},{0L,0L,0x53L},{0xBFL,0L,0x76L},{0xBFL,0x39L,0x1BL},{0L,1L,0xDFL},{0xF4L,0xBFL,0x1BL},{0x6BL,0x2AL,0x76L}},{{1L,0x2AL,0x53L},{1L,0xBFL,0x8BL},{0xA4L,1L,0xCAL},{1L,0x39L,0x10L},{1L,0L,0x10L},{0x6BL,0L,0xCAL},{0xF4L,0xB1L,0x8BL},{0L,0L,0x53L}},{{0xBFL,0L,0x76L},{0xBFL,0x39L,0x1BL},{0L,1L,0xDFL},{0xF4L,0xBFL,0x1BL},{0x6BL,0x2AL,0x76L},{1L,0x2AL,0x53L},{1L,0xBFL,0x8BL},{0xA4L,1L,0xCAL}},{{1L,0x39L,0x10L},{1L,0L,0x10L},{0x6BL,0L,0xCAL},{0xF4L,0xB1L,0x8BL},{0L,0L,0x53L},{0xBFL,0L,0x76L},{0xBFL,0x39L,0x1BL},{0L,1L,0xDFL}},{{0xF4L,0xBFL,0x1BL},{0x6BL,0x2AL,0x76L},{1L,0x2AL,0x53L},{1L,0xBFL,0x8BL},{0xA4L,1L,0xCAL},{1L,0x39L,0x10L},{1L,0L,0x10L},{0x6BL,0L,0xCAL}},{{0xF4L,0xB1L,0x8BL},{0L,0L,0x53L},{0x6FL,9L,0x6CL},{0x6FL,0xE5L,0L},{(-1L),0L,1L},{(-9L),0x6FL,0L},{0xE9L,1L,0x6CL},{0xC4L,1L,0xBFL}},{{0L,0x6FL,1L},{1L,0L,0xA4L},{0L,0xE5L,0xB1L},{0xC4L,9L,0xB1L},{0xE9L,(-1L),0xA4L},{(-9L),0x19L,1L},{(-1L),(-1L),0xBFL},{0x6FL,9L,0x6CL}},{{0x6FL,0xE5L,0L},{(-1L),0L,1L},{(-9L),0x6FL,0L},{0xE9L,1L,0x6CL},{0xC4L,1L,0xBFL},{0L,0x6FL,1L},{1L,0L,0xA4L},{0L,0xE5L,0xB1L}},{{0xC4L,9L,0xB1L},{0xE9L,(-1L),0xA4L},{(-9L),0x19L,1L},{(-1L),(-1L),0xBFL},{0x6FL,9L,0x6CL},{0x6FL,0xE5L,0L},{(-1L),0L,1L},{(-9L),0x6FL,0L}}}; + int8_t ***l_761[10] = {&g_245,&g_245,&g_245,&g_245,&g_245,&g_245,&g_245,&g_245,&g_245,&g_245}; + int i, j, k; + } + for (l_704 = 0; l_704 < 5; l_704 += 1) + { + g_294[l_704] = 1UL; + } + } + (*g_143) = (safe_div_func_int32_t_s_s((*g_143), l_704)); + return l_697; +} + + +/* ------------------------------------------ */ +/* + * reads : + * writes: + */ +static int32_t * func_105(uint32_t p_106) +{ /* block id: 29 */ + int8_t *l_134 = &g_36; + int8_t ** const l_133 = &l_134; + int32_t l_156 = 0xE85A3F02L; + uint32_t l_166 = 0x5E662131L; + uint8_t **l_172 = &g_43; + uint8_t **l_174[2][7] = {{&g_43,&g_43,&g_43,&g_43,&g_43,&g_43,&g_43},{&g_43,&g_43,&g_43,&g_43,&g_43,&g_43,&g_43}}; + uint8_t ***l_173[2][9] = {{(void*)0,&l_172,(void*)0,&l_172,(void*)0,&l_172,(void*)0,&l_172,(void*)0},{(void*)0,(void*)0,&l_174[1][0],&l_174[1][0],(void*)0,(void*)0,&l_174[1][0],&l_174[1][0],(void*)0}}; + int32_t *l_211[6] = {&g_3,&g_3,&g_3,&g_3,&g_3,&g_3}; + int32_t l_418 = 0xBEDB2E7EL; + int32_t l_582 = 8L; + int16_t l_587[5][7][2] = {{{0x5323L,1L},{0xDA62L,0xA377L},{0xD174L,0xDA62L},{0x959BL,0x0DAEL},{0x959BL,0xDA62L},{0xD174L,0xA377L},{0xDA62L,1L}},{{0x5323L,(-1L)},{0xA377L,0x9B9BL},{0x9B9BL,0x9B9BL},{0xA377L,(-1L)},{0x5323L,1L},{0xDA62L,0xA377L},{0xD174L,0xDA62L}},{{0x959BL,0x0DAEL},{0x959BL,0xDA62L},{0xD174L,0xA377L},{0xDA62L,1L},{0x5323L,(-1L)},{0xA377L,0x9B9BL},{0x9B9BL,0x9B9BL}},{{0xA377L,(-1L)},{0x5323L,1L},{0xDA62L,0xA377L},{0xD174L,0xDA62L},{0x959BL,0x0DAEL},{(-1L),0x0DAEL},{0x5323L,0x9B9BL}},{{0x0DAEL,0xD174L},{0x959BL,0xA377L},{0x9B9BL,(-7L)},{(-7L),(-7L)},{0x9B9BL,0xA377L},{0x959BL,0xD174L},{0x0DAEL,0x9B9BL}}}; + uint32_t l_614 = 4294967286UL; + int i, j, k; + return &g_297[1]; +} + + + + +/* ---------------------------------------- */ +int main (int argc, char* argv[]) +{ + int i, j, k; + int print_hash_value = 0; + if (argc == 2 && strcmp(argv[1], "1") == 0) print_hash_value = 1; + platform_main_begin(); + crc32_gentab(); + func_1(); + for (i = 0; i < 5; i++) + { + for (j = 0; j < 1; j++) + { + transparent_crc(g_2[i][j], "g_2[i][j]", print_hash_value); + if (print_hash_value) printf("index = [%d][%d]\n", i, j); + + } + } + transparent_crc(g_3, "g_3", print_hash_value); + for (i = 0; i < 6; i++) + { + transparent_crc(g_14[i], "g_14[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_15, "g_15", print_hash_value); + transparent_crc(g_34, "g_34", print_hash_value); + transparent_crc(g_36, "g_36", print_hash_value); + for (i = 0; i < 7; i++) + { + transparent_crc(g_40[i], "g_40[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_44, "g_44", print_hash_value); + transparent_crc(g_46, "g_46", print_hash_value); + for (i = 0; i < 2; i++) + { + for (j = 0; j < 8; j++) + { + for (k = 0; k < 3; k++) + { + transparent_crc(g_51[i][j][k], "g_51[i][j][k]", print_hash_value); + if (print_hash_value) printf("index = [%d][%d][%d]\n", i, j, k); + + } + } + } + transparent_crc(g_52, "g_52", print_hash_value); + transparent_crc(g_56, "g_56", print_hash_value); + transparent_crc(g_140, "g_140", print_hash_value); + transparent_crc(g_251, "g_251", print_hash_value); + transparent_crc(g_255, "g_255", print_hash_value); + transparent_crc(g_290, "g_290", print_hash_value); + for (i = 0; i < 5; i++) + { + transparent_crc(g_294[i], "g_294[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + for (i = 0; i < 2; i++) + { + transparent_crc(g_297[i], "g_297[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_320, "g_320", print_hash_value); + transparent_crc(g_347, "g_347", print_hash_value); + transparent_crc(g_419, "g_419", print_hash_value); + transparent_crc(g_477, "g_477", print_hash_value); + for (i = 0; i < 6; i++) + { + transparent_crc(g_705[i], "g_705[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_969, "g_969", print_hash_value); + transparent_crc(g_1055, "g_1055", print_hash_value); + transparent_crc(g_1099, "g_1099", print_hash_value); + transparent_crc(g_1132, "g_1132", print_hash_value); + transparent_crc(g_1189, "g_1189", print_hash_value); + for (i = 0; i < 8; i++) + { + for (j = 0; j < 1; j++) + { + for (k = 0; k < 8; k++) + { + transparent_crc(g_1254[i][j][k], "g_1254[i][j][k]", print_hash_value); + if (print_hash_value) printf("index = [%d][%d][%d]\n", i, j, k); + + } + } + } + transparent_crc(g_1285, "g_1285", print_hash_value); + transparent_crc(g_1298, "g_1298", print_hash_value); + transparent_crc(g_1333, "g_1333", print_hash_value); + transparent_crc(g_1334, "g_1334", print_hash_value); + transparent_crc(g_1509, "g_1509", print_hash_value); + transparent_crc(g_1766, "g_1766", print_hash_value); + transparent_crc(g_1776, "g_1776", print_hash_value); + for (i = 0; i < 6; i++) + { + for (j = 0; j < 8; j++) + { + for (k = 0; k < 5; k++) + { + transparent_crc(g_1782[i][j][k], "g_1782[i][j][k]", print_hash_value); + if (print_hash_value) printf("index = [%d][%d][%d]\n", i, j, k); + + } + } + } + transparent_crc(g_1857, "g_1857", print_hash_value); + transparent_crc(g_1961, "g_1961", print_hash_value); + transparent_crc(g_2067, "g_2067", print_hash_value); + for (i = 0; i < 10; i++) + { + transparent_crc(g_2147[i], "g_2147[i]", print_hash_value); + if (print_hash_value) printf("index = [%d]\n", i); + + } + transparent_crc(g_2148, "g_2148", print_hash_value); + transparent_crc(g_2207, "g_2207", print_hash_value); + platform_main_end(crc32_context ^ 0xFFFFFFFFUL, print_hash_value); + return 0; +} + +/************************ statistics ************************* +XXX max struct depth: 0 +breakdown: + depth: 0, occurrence: 652 +XXX total union variables: 0 + +XXX non-zero bitfields defined in structs: 0 +XXX zero bitfields defined in structs: 0 +XXX const bitfields defined in structs: 0 +XXX volatile bitfields defined in structs: 0 +XXX structs with bitfields in the program: 0 +breakdown: +XXX full-bitfields structs in the program: 0 +breakdown: +XXX times a bitfields struct's address is taken: 0 +XXX times a bitfields struct on LHS: 0 +XXX times a bitfields struct on RHS: 0 +XXX times a single bitfield on LHS: 0 +XXX times a single bitfield on RHS: 0 + +XXX max expression depth: 41 +breakdown: + depth: 1, occurrence: 169 + depth: 2, occurrence: 42 + depth: 3, occurrence: 3 + depth: 4, occurrence: 2 + depth: 6, occurrence: 1 + depth: 7, occurrence: 1 + depth: 8, occurrence: 1 + depth: 10, occurrence: 1 + depth: 13, occurrence: 1 + depth: 14, occurrence: 1 + depth: 15, occurrence: 1 + depth: 16, occurrence: 3 + depth: 19, occurrence: 1 + depth: 20, occurrence: 1 + depth: 21, occurrence: 4 + depth: 22, occurrence: 2 + depth: 23, occurrence: 2 + depth: 24, occurrence: 2 + depth: 25, occurrence: 1 + depth: 26, occurrence: 2 + depth: 27, occurrence: 3 + depth: 28, occurrence: 4 + depth: 30, occurrence: 1 + depth: 31, occurrence: 1 + depth: 33, occurrence: 1 + depth: 35, occurrence: 2 + depth: 36, occurrence: 2 + depth: 39, occurrence: 4 + depth: 41, occurrence: 2 + +XXX total number of pointers: 428 + +XXX times a variable address is taken: 1238 +XXX times a pointer is dereferenced on RHS: 347 +breakdown: + depth: 1, occurrence: 232 + depth: 2, occurrence: 83 + depth: 3, occurrence: 32 +XXX times a pointer is dereferenced on LHS: 261 +breakdown: + depth: 1, occurrence: 220 + depth: 2, occurrence: 32 + depth: 3, occurrence: 9 +XXX times a pointer is compared with null: 37 +XXX times a pointer is compared with address of another variable: 12 +XXX times a pointer is compared with another pointer: 17 +XXX times a pointer is qualified to be dereferenced: 9414 + +XXX max dereference level: 5 +breakdown: + level: 0, occurrence: 0 + level: 1, occurrence: 1507 + level: 2, occurrence: 661 + level: 3, occurrence: 292 + level: 4, occurrence: 45 + level: 5, occurrence: 6 +XXX number of pointers point to pointers: 210 +XXX number of pointers point to scalars: 218 +XXX number of pointers point to structs: 0 +XXX percent of pointers has null in alias set: 29.2 +XXX average alias set size: 1.54 + +XXX times a non-volatile is read: 2082 +XXX times a non-volatile is write: 921 +XXX times a volatile is read: 0 +XXX times read thru a pointer: 0 +XXX times a volatile is write: 0 +XXX times written thru a pointer: 0 +XXX times a volatile is available for access: 0 +XXX percentage of non-volatile access: 100 + +XXX forward jumps: 1 +XXX backward jumps: 7 + +XXX stmts: 175 +XXX max block depth: 5 +breakdown: + depth: 0, occurrence: 34 + depth: 1, occurrence: 30 + depth: 2, occurrence: 19 + depth: 3, occurrence: 27 + depth: 4, occurrence: 30 + depth: 5, occurrence: 35 + +XXX percentage a fresh-made variable is used: 16.5 +XXX percentage an existing variable is used: 83.5 +********************* end of statistics **********************/ + diff --git a/tests/fuzz/19.c.txt b/tests/fuzz/19.c.txt new file mode 100644 index 0000000000000..5fac330bccd57 --- /dev/null +++ b/tests/fuzz/19.c.txt @@ -0,0 +1 @@ +checksum = 150DAD10 diff --git a/tools/eliminator/asm-eliminator-test-output.js b/tools/eliminator/asm-eliminator-test-output.js index 9caf99d0077b3..1a5dca552bd04 100644 --- a/tools/eliminator/asm-eliminator-test-output.js +++ b/tools/eliminator/asm-eliminator-test-output.js @@ -147,27 +147,25 @@ function looop3() { } } function looop4() { - var i = 0, helper = 0; + var i = 0, i$looptemp = 0; while (1) { do_it(); - helper = i + 1 | 0; - f(i, helper); - if (condition()) { - i = helper; - } else { + i$looptemp = i; + i = i + 1 | 0; + f(i$looptemp, i); + if (!condition()) { break; } } } function looop4b() { - var i = 0, helper = 0; + var i = 0, i$looptemp = 0; while (1) { do_it(); - helper = i + 1 | 0; - g(helper); - if (condition(i)) { - i = helper; - } else { + i$looptemp = i; + i = i + 1 | 0; + g(i); + if (!condition(i$looptemp)) { break; } } @@ -251,24 +249,22 @@ function multiloop($n_0, $35) { function multiloop2($n_0, $35) { $n_0 = $n_0 | 0; $35 = $35 | 0; - var $p_0 = 0, $39 = 0, $41 = 0, $46 = 0; + var $p_0 = 0, $41 = 0, $p_0$looptemp = 0; $n_0 = $35; $p_0 = (HEAP32[$15 >> 2] | 0) + ($35 << 1) | 0; while (1) { - $39 = $p_0 - 2 | 0; - $41 = HEAPU16[$39 >> 1] | 0; + $p_0$looptemp = $p_0; + $p_0 = $p_0 - 2 | 0; + $41 = HEAPU16[$p_0 >> 1] | 0; if ($41 >>> 0 < $2 >>> 0) { $_off0 = 0; } else { $_off0 = $41 - $2 & 65535; } - HEAP16[$39 >> 1] = $p_0; - $46 = $n_0 - 1 | 0; - if (($46 | 0) == 0) { + HEAP16[$p_0 >> 1] = $p_0$looptemp; + $n_0 = $n_0 - 1 | 0; + if (($n_0 | 0) == 0) { break; - } else { - $n_0 = $46; - $p_0 = $39; } } } @@ -901,4 +897,18 @@ function elimOneLoopVar4() { } } } +function elimOneLoopVarStillUsed() { + var $call10 = Math_fround(0), $curri$012 = 0, $j$010 = 0, $retval$0 = 0, $j$010$looptemp = 0; + while (1) { + $j$010$looptemp = $j$010; + $j$010 = $j$010 + 1 | 0; + if ((($curri$012 | 0) % ($j$010$looptemp | 0) & -1 | 0) == 0) { + break; + } + if (!(Math_fround($j$010 | 0) < $call10)) { + break; + } + } + return $retval$0 | 0; +} diff --git a/tools/eliminator/asm-eliminator-test.js b/tools/eliminator/asm-eliminator-test.js index a3de3d9d30031..d5bbd8d520bf8 100644 --- a/tools/eliminator/asm-eliminator-test.js +++ b/tools/eliminator/asm-eliminator-test.js @@ -1131,5 +1131,26 @@ function elimOneLoopVar4() { } } } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute", "selfAssign", "elimOneLoopVar", "elimOneLoopVar2", "elimOneLoopVar3", "elimOneLoopVar4"] +function elimOneLoopVarStillUsed() { + var $0 = 0, $1 = 0, $arg$0 = 0, $arrayidx = 0, $call10 = Math_fround(0), $cmp = 0, $cmp11 = 0, $cmp119 = 0, $cmp12 = 0, $cmp7 = 0, $conv = 0, $conv8 = Math_fround(0), $conv9 = Math_fround(0), $curri$012 = 0, $inc = 0, $inc14$primes$0 = 0, $inc16 = 0, $j$010 = 0, $ok$0 = 0; + var $primes$011 = 0, $rem = 0, $retval$0 = 0, $sub = 0, $vararg_buffer1 = 0, label = 0, sp = 0; + while (1) { + $rem = ($curri$012 | 0) % ($j$010 | 0) & -1; + $cmp12 = ($rem | 0) == 0; + $inc = $j$010 + 1 | 0; + if ($cmp12) { + $ok$0 = 0; + break; + } + $conv8 = Math_fround($inc | 0); + $cmp11 = $conv8 < $call10; + if ($cmp11) { + $j$010 = $inc; + } else { + break; + } + } + return $retval$0 | 0; +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["asm", "__Z11printResultPiS_j", "_segment_holding", "__ZN5identC2EiPKcPci", "_vec2Length", "exc", "label", "confuusion", "tempDouble", "_org_apache_harmony_luni_util_NumberConverter_freeFormat__", "__ZN23b2EdgeAndPolygonContact8EvaluateEP10b2ManifoldRK11b2TransformS4_", "_java_nio_charset_Charset_forNameInternal___java_lang_String", "looop2", "looop3", "looop4", "looop5", "looop6", "looop7", "looop8", "multiloop", "multiloop2", "tempDouble2", "watIf", "select2", "binary", "cute", "selfAssign", "elimOneLoopVar", "elimOneLoopVar2", "elimOneLoopVar3", "elimOneLoopVar4", "elimOneLoopVarStillUsed"] diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index c4585b8442b12..32c26c51a400a 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -3519,12 +3519,15 @@ function eliminate(ast, memSafe) { seenUses[name]++; } } else if (type === 'while') { + if (!asm) return; // try to remove loop helper variables specifically var stats = node[2][1]; var last = stats[stats.length-1]; if (last && last[0] === 'if' && last[2][0] === 'block' && last[3] && last[3][0] === 'block') { var ifTrue = last[2]; var ifFalse = last[3]; + clearEmptyNodes(ifTrue[1]); + clearEmptyNodes(ifFalse[1]); var flip = false; if (ifFalse[1][0] && ifFalse[1][0][0] === 'break') { // canonicalize break in the if var temp = ifFalse; @@ -3589,17 +3592,25 @@ function eliminate(ast, memSafe) { } } if (found < 0) return; + // if a loop variable is used after we assigned to the helper, we must save its value and use that. + // (note that this can happen due to elimination, if we eliminate an expression containing the + // loop var far down, past the assignment!) + var temp = looper + '$looptemp'; var looperUsed = false; - for (var i = found+1; i < stats.length && !looperUsed; i++) { + assert(!(temp in asmData.vars)); + for (var i = found+1; i < stats.length; i++) { var curr = i < stats.length-1 ? stats[i] : last[1]; // on the last line, just look in the condition traverse(curr, function(node, type) { if (type === 'name' && node[1] === looper) { + node[1] = temp; looperUsed = true; - return true; } }); } - if (looperUsed) return; + if (looperUsed) { + asmData.vars[temp] = asmData.vars[looper]; + stats.splice(found, 0, ['stat', ['assign', true, ['name', temp], ['name', looper]]]); + } } for (var l = 0; l < helpers.length; l++) { for (var k = 0; k < helpers.length; k++) { From 326078dbfd2d1b412546dffef81964c3d2ca125d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 17 Apr 2014 15:28:58 -0700 Subject: [PATCH 17/67] disable a failing test due to an llvm lto bug --- tests/test_core.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/test_core.py b/tests/test_core.py index ab4897f8e0984..1b116c4acd350 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5272,8 +5272,10 @@ def run_all(x): if 'newfail' in name: continue if os.environ.get('EMCC_FAST_COMPILER') == '0' and os.path.basename(name) in [ '18.cpp', '15.c' - ]: - continue # works only in fastcomp + ]: continue # works only in fastcomp + if x == 'lto' and self.run_name == 'default' and os.path.basename(name) in [ + '19.c' + ]: continue # LLVM LTO bug print name self.do_run(open(path_from_root('tests', 'fuzz', name)).read(), From 6596d145ae24c7accc99c68f341689e5a0a73c1c Mon Sep 17 00:00:00 2001 From: Usagi Ito Date: Sat, 19 Apr 2014 11:18:14 +0900 Subject: [PATCH 18/67] fix GLFW glfwGetMouseWheel is reversed bug --- src/library_glfw.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/library_glfw.js b/src/library_glfw.js index b54205adbd755..148649926eb8c 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -197,7 +197,7 @@ var LibraryGLFW = { }, onMouseWheel: function(event) { - GLFW.wheelPos += Browser.getMouseWheelDelta(event); + GLFW.wheelPos -= Browser.getMouseWheelDelta(event); if (GLFW.mouseWheelFunc && event.target == Module["canvas"]) { Runtime.dynCall('vi', GLFW.mouseWheelFunc, [GLFW.wheelPos]); From fd9e8330eafcdb9112753ed6729954605f357280 Mon Sep 17 00:00:00 2001 From: Guillaume Blanc Date: Tue, 22 Apr 2014 13:40:22 +0200 Subject: [PATCH 19/67] Fixes glfwGetKey that always returns 0 if no callback is set with glfwSetKeyCallback; fixes #1320 --- AUTHORS | 2 +- src/library_glfw.js | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 99703f937a44b..ad372e9290c6a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -134,4 +134,4 @@ a license to everyone to use it as detailed in LICENSE.) * Daniele Di Proietto * Dan Dascalescu * Thomas Borsos - +* Guillaume Blanc diff --git a/src/library_glfw.js b/src/library_glfw.js index f72aeb2414e16..0b3fccd445fd2 100644 --- a/src/library_glfw.js +++ b/src/library_glfw.js @@ -130,9 +130,11 @@ var LibraryGLFW = { onKeyChanged: function(event, status) { var key = GLFW.DOMToGLFWKeyCode(event.keyCode); - if (key && GLFW.keyFunc) { + if (key) { GLFW.keys[key] = status; - Runtime.dynCall('vii', GLFW.keyFunc, [key, status]); + if (GLFW.keyFunc) { + Runtime.dynCall('vii', GLFW.keyFunc, [key, status]); + } } }, From ce5021b9577feacb25474914a796ec4b6f5ff76d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 23 Apr 2014 00:00:39 +0300 Subject: [PATCH 20/67] Updated ChangeLog. --- ChangeLog | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 87 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index 328e3cac7a1f0..18640add85a0c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,7 +10,83 @@ Not all changes are documented here. In particular, new features, user-oriented Current trunk code ------------------ - To see a list of commits in the active development branch 'incoming', which have not yet been packaged in a release, see - https://github.com/kripken/emscripten/compare/1.13.1...incoming + - Emscripten: https://github.com/kripken/emscripten/compare/1.16.0...incoming + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.16.0...incoming + - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.16.0...incoming + +v1.16.0: 4/16/2014 +------------------ + - Removed browser warnings message in VFS library about replacing __proto__ performance issue. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.15.1...1.16.0 + - Emscripten-LLVM: no changes. + - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.15.1...1.16.0 + +v1.15.1: 4/15/2014 +------------------ + - Added support for SDL2 touch api. + - Added new user-controllable emdind-related define #define EMSCRIPTEN_HAS_UNBOUND_TYPE_NAMES, which allows optimizing embind for minimal size when std::type_info is not needed. + - Fixed issues with CMake support where CMAKE_AR and CMAKE_RANLIB were not accessible from CMakeLists.txt files. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.15.0...1.15.1 + - Emscripten-LLVM: no changes. + - Emscripten-Clang: no changes. + +v1.15.0: 4/11/2014 +------------------ + - Fix outlining feature for functions that return a double (#2278) + - Added support for C++11 atomic constructs (#2273) + - Adjusted stdout and stderr stream behavior in the default shell.html to always print out to both web page text log box, and the browser console. + - Fixed an issue with loop variable optimization. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.14.1...1.15.0 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.14.1...1.15.0 + - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.14.1...1.15.0 + +v1.14.1: 4/8/2014 +------------------ + - Added new command line utility 'emcmake', which can be used to call emconfigure for cmake. + - Added a new emcc command line parameter '--valid-abspath', which allows selectively suppressing warning messages that occur when using absolute path names in include and link directories. + - Added a new emcc linker command line parameter '--emit-symbol-map', which will save a map file between minified global names and the original function names. + - Fixed an issue with --default-object-ext not always working properly. + - Added optimizations to eliminate redundant loop variables and redundant self-assignments. + - Migrated several libc functions to use compiled code from musl instead of handwritten JS implementations. + - Improved embind support. + - Renamed the EM_ASM_() macro to the form EM_ASM_ARGS(). + - Fixed mouse button ordering issue in glfw. + - Fixed an issue when creating a path name that ends in a slash (#2258, #2263) + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.14.0...1.14.1 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.14.0...1.14.1 + - Emscripten-Clang: no changes. + +v1.14.0: 3/25/2014 +------------------ + - Added new emcc linker command line option '-profiling', which defaults JS code generation options suited for benchmarking and profiling purposes. + - Implemented the EGL function eglWaitGL(). + - Fixed an issue with the HTML5 API that caused the HTML5 event listener unregistration to fail. + - Fixed issues with numpad keys in SDL support library. + - Added a new JS optimizer pass 'simplifyIfs', which is run when -s SIMPLIFY_IFS=1 link flag is set and -g is not specified. This pass merges multiple nested if()s together into single comparisons, where possible. + - Removed false positive messages on missing internal "emscripten_xxx" symbols at link stage. + - Updated to latest relooper version. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.13.2...1.14.0 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.13.2...1.14.0 + - Emscripten-Clang: no changes. + +v1.13.2: 3/15/2014 +------------------ + - Fixed issues with SDL audio on Safari. + - Fixed issues with HTML5 API mouse scroll events on Safari. + - Fixed issues with HTML5 fullscreen requests in IE11. + - Enabled support for emscripten_get_callstack on IE10+. + - Fixed issues with Closure symbol minification. + - Further improved em_asm()-related error messages. + - Updated to latest relooper version. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.13.1...1.13.2 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.13.1...1.13.2 + - Emscripten-Clang: no changes. v1.13.1: 3/10/2014 ------------------ @@ -21,7 +97,16 @@ v1.13.1: 3/10/2014 - Fix an issue where extraneous system libraries would get included in the generated output (#2191). - Added a new function emscripten_async_wget2_data() that allows reading from an XMLHTTPRequest directly into memory while supporting advanced features. - Fixed esc key code in GLFW. - - Full list of changes: https://github.com/kripken/emscripten/compare/1.13.0...1.13.1 + - Added new emscripten_debugger() intrinsic function, which calls into JS "debugger;" statement to break into a JS debugger. + - Fixed varargs function call alignment of doubles to 8 bytes. + - Switched to using default function local stack alignment to 16 bytes to be SIMD-friendly. + - Improved error messages when user code has a syntax error in em_asm() statements. + - Switched to using a new custom LLVM datalayout format for Emscripten. See https://github.com/kripken/emscripten-fastcomp/commit/65405351ba0b32a8658c65940e0b65ceb2601ad4 + - Optimized function local stack space to use fewer temporary JS variables. + - Full list of changes: + - Emscripten: https://github.com/kripken/emscripten/compare/1.13.0...1.13.1 + - Emscripten-LLVM: https://github.com/kripken/emscripten-fastcomp/compare/1.13.0...1.13.1 + - Emscripten-Clang: https://github.com/kripken/emscripten-fastcomp-clang/compare/1.13.0...1.13.1 v1.13.0: 3/3/2014 ------------------ From 90940429ead09459cc29e8dda86b3d47a7dd20a0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 22 Apr 2014 17:11:08 -0700 Subject: [PATCH 21/67] ignore readnone in params --- src/modules.js | 1 + src/parseTools.js | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/modules.js b/src/modules.js index 2d2a75d0aeb5b..fd5c23cd65039 100644 --- a/src/modules.js +++ b/src/modules.js @@ -21,6 +21,7 @@ var LLVM = { CONVERSIONS: set('inttoptr', 'ptrtoint', 'uitofp', 'sitofp', 'fptosi', 'fptoui', 'fpext', 'fptrunc'), INTRINSICS_32: set('_llvm_memcpy_p0i8_p0i8_i64', '_llvm_memmove_p0i8_p0i8_i64', '_llvm_memset_p0i8_i64'), // intrinsics that need args converted to i32 in USE_TYPED_ARRAYS == 2 MATHOP_IGNORABLES: set('exact', 'nnan', 'ninf', 'nsz', 'arcp', 'fast'), + PARAM_IGNORABLES: set('nocapture', 'readonly', 'readnone'), }; LLVM.GLOBAL_MODIFIERS = set(keys(LLVM.LINKAGES).concat(['constant', 'global', 'hidden'])); diff --git a/src/parseTools.js b/src/parseTools.js index 4fb7619698fb0..4396abd9f1778 100644 --- a/src/parseTools.js +++ b/src/parseTools.js @@ -467,7 +467,7 @@ function parseParamTokens(params) { // handle 'byval' and 'byval align X'. We store the alignment in 'byVal' byVal = QUANTUM_SIZE; segment.splice(1, 1); - if (segment[1] && (segment[1].text === 'nocapture' || segment[1].text === 'readonly')) { + if (segment[1] && (segment[1].text in LLVM.PARAM_IGNORABLES)) { segment.splice(1, 1); } if (segment[1] && segment[1].text === 'align') { @@ -476,7 +476,7 @@ function parseParamTokens(params) { segment.splice(1, 2); } } - if (segment[1] && (segment[1].text === 'nocapture' || segment[1].text === 'readonly')) { + if (segment[1] && (segment[1].text in LLVM.PARAM_IGNORABLES)) { segment.splice(1, 1); } if (segment.length == 1) { From 28ed391308c78e8cda92bfbe22da88ce9767cd25 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 23 Apr 2014 17:52:20 -0700 Subject: [PATCH 22/67] webidl binder --- src/settings.js | 2 +- tests/test_core.py | 16 + tests/webidl/output.txt | 56 + tests/webidl/post.js | 117 + tests/webidl/test.cpp | 8 + tests/webidl/test.h | 72 + tests/webidl/test.idl | 64 + third_party/WebIDL.py | 5030 +++++++++++++++++++++++++++++++++++++++ third_party/__init__.py | 2 + tools/webidl_binder.py | 426 ++++ 10 files changed, 5792 insertions(+), 1 deletion(-) create mode 100644 tests/webidl/output.txt create mode 100644 tests/webidl/post.js create mode 100644 tests/webidl/test.cpp create mode 100644 tests/webidl/test.h create mode 100644 tests/webidl/test.idl create mode 100644 third_party/WebIDL.py create mode 100644 third_party/__init__.py create mode 100644 tools/webidl_binder.py diff --git a/src/settings.js b/src/settings.js index bf16290bbe466..a9a7242539d9f 100644 --- a/src/settings.js +++ b/src/settings.js @@ -338,7 +338,7 @@ var EXPORTED_FUNCTIONS = ['_main', '_malloc']; var EXPORT_ALL = 0; // If true, we export all the symbols. Note that this does *not* affect LLVM, so it can // still eliminate functions as dead. This just exports them on the Module object. var EXPORT_BINDINGS = 0; // Export all bindings generator functions (prefixed with emscripten_bind_). This - // is necessary to use the bindings generator with asm.js + // is necessary to use the WebIDL binder or bindings generator with asm.js var RETAIN_COMPILER_SETTINGS = 0; // Remembers the values of these settings, and makes them accessible // through Runtime.getCompilerSetting and emscripten_get_compiler_setting. // To see what is retained, look for compilerSettings in the generated code. diff --git a/tests/test_core.py b/tests/test_core.py index 1b116c4acd350..b5024309e02e4 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5971,6 +5971,22 @@ def process(filename): ''' self.do_run(src, '|hello|43|world|41|', post_build=post) + def test_webidl(self): + if self.emcc_args is None: return self.skip('requires emcc') + + output = Popen([PYTHON, path_from_root('tools', 'webidl_binder.py'), + path_from_root('tests', 'webidl', 'test.idl'), + 'glue']).communicate()[0] + assert os.path.exists('glue.cpp') + assert os.path.exists('glue.js') + + self.emcc_args += ['--post-js', 'glue.js', + '--post-js', path_from_root('tests', 'webidl', 'post.js')] + shutil.copyfile(path_from_root('tests', 'webidl', 'test.h'), self.in_dir('test.h')) + shutil.copyfile(path_from_root('tests', 'webidl', 'test.cpp'), self.in_dir('test.cpp')) + src = open('test.cpp').read() + self.do_run(src, open(path_from_root('tests', 'webidl', 'output.txt')).read()) + def test_typeinfo(self): if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('fastcomp does not support RUNTIME_TYPE_INFO') diff --git a/tests/webidl/output.txt b/tests/webidl/output.txt new file mode 100644 index 0000000000000..b874d928e26a7 --- /dev/null +++ b/tests/webidl/output.txt @@ -0,0 +1,56 @@ +Parent:42 +* +84 +c1 +Parent:7 +Child1:7 +7 +14 +196 +588 +14 +28 +c1 v2 +Parent:16 +Child1:15 +15 +30 +900 +2700 +c2 +Parent:9 +Child2:9 +9 +18 +5832 +0 +0 +1 +*static* +*virtualf* +*virtualf* +*virtualf2* +Parent:9 +Child2:9 +*js virtualf replacement* +*js virtualf replacement* +*js virtualf2 replacement* +*js virtualf3 replacement 123* +caught: a JSImplementation must implement all functions, you forgot Child2JS::virtualFunc4. +*virtualf* +*virtualf* +*virtualf2* +*ok* +|hello|43|world|41| +12.35 +10 +object +10 +11 +object +10 +11 +21.12 +198 + +done. diff --git a/tests/webidl/post.js b/tests/webidl/post.js new file mode 100644 index 0000000000000..444efcd1c208e --- /dev/null +++ b/tests/webidl/post.js @@ -0,0 +1,117 @@ + +// Part 1 + +var sme = new Module.Parent(42); +sme.mulVal(2); +Module.print('*') +Module.print(sme.getVal()); + +Module.print('c1'); + +var c1 = new Module.Child1(); +Module.print(c1.getVal()); +c1.mulVal(2); +Module.print(c1.getVal()); +Module.print(c1.getValSqr()); +Module.print(c1.getValSqr(3)); +Module.print(c1.getValTimes()); // default argument should be 1 +Module.print(c1.getValTimes(2)); + +Module.print('c1 v2'); + +c1 = new Module.Child1(8); // now with a parameter, we should handle the overloading automatically and properly and use constructor #2 +Module.print(c1.getVal()); +c1.mulVal(2); +Module.print(c1.getVal()); +Module.print(c1.getValSqr()); +Module.print(c1.getValSqr(3)); + +Module.print('c2') + +var c2 = new Module.Child2(); +Module.print(c2.getVal()); +c2.mulVal(2); +Module.print(c2.getVal()); +Module.print(c2.getValCube()); +var succeeded; +try { + succeeded = 0; + Module.print(c2.doSomethingSecret()); // should fail since private + succeeded = 1; +} catch(e) {} +Module.print(succeeded); +try { + succeeded = 0; + Module.print(c2.getValSqr()); // function from the other class + succeeded = 1; +} catch(e) {} +Module.print(succeeded); +try { + succeeded = 0; + c2.getValCube(); // sanity + succeeded = 1; +} catch(e) {} +Module.print(succeeded); + +Module.Child2.prototype.printStatic(); // static calls go through the prototype + +// virtual function +c2.virtualFunc(); +Module.Child2.prototype.runVirtualFunc(c2); +c2.virtualFunc2(); + +// extend a class from JS +var c3 = new Module.Child2JS; + +c3.virtualFunc = function() { + Module.print('*js virtualf replacement*'); +}; +c3.virtualFunc2 = function() { + Module.print('*js virtualf2 replacement*'); +}; +c3.virtualFunc3 = function(x) { + Module.print('*js virtualf3 replacement ' + x + '*'); +}; + +c3.virtualFunc(); +Module.Child2.prototype.runVirtualFunc(c3); +c3.virtualFunc2(); +c3.virtualFunc3(123); // this one is not replaced! +try { + c3.virtualFunc4(123); +} catch(e) { + Module.print('caught: ' + e); +} + +c2.virtualFunc(); // original should remain the same +Module.Child2.prototype.runVirtualFunc(c2); +c2.virtualFunc2(); +Module.print('*ok*'); + +// Part 2 + +var suser = new Module.StringUser("hello", 43); +suser.Print(41, "world"); +suser.PrintFloat(12.3456); + +var bv = new Module.RefUser(10); +var bv2 = new Module.RefUser(11); +Module.print(bv2.getValue(bv)); + +Module.print(typeof bv2.getMe()); +Module.print(bv2.getMe().getValue(bv)); +Module.print(bv2.getMe().getValue(bv2)); + +Module.print(typeof bv2.getCopy()); +Module.print(bv2.getCopy().getValue(bv)); +Module.print(bv2.getCopy().getValue(bv2)); + +bv2.getAnother().PrintFloat(21.12); + +Module.print(new Module.Inner().get()); +new Module.Inner().mul(2); + +// + +Module.print('\ndone.') + diff --git a/tests/webidl/test.cpp b/tests/webidl/test.cpp new file mode 100644 index 0000000000000..8a2b5c72fc03a --- /dev/null +++ b/tests/webidl/test.cpp @@ -0,0 +1,8 @@ +#include "test.h" + +Parent::Parent(int val) : value(val) { printf("Parent:%d\n", val); } +Parent::Parent(Parent *p, Parent *q) : value(p->value + q->value) { printf("Parent:%d\n", value); } +void Parent::mulVal(int mul) { value *= mul; } + +#include "glue.cpp" + diff --git a/tests/webidl/test.h b/tests/webidl/test.h new file mode 100644 index 0000000000000..903f8f78d6e18 --- /dev/null +++ b/tests/webidl/test.h @@ -0,0 +1,72 @@ +#include + +// Part 1 + +class Parent { +protected: + int value; +public: + Parent(int val); + Parent(Parent *p, Parent *q); // overload constructor + int getVal() { return value; }; // inline should work just fine here, unlike Way 1 before + void mulVal(int mul); +}; + +class Child1 : public Parent { +public: + Child1() : Parent(7) { printf("Child1:%d\n", value); }; + Child1(int val) : Parent(val*2) { value -= 1; printf("Child1:%d\n", value); }; + int getValSqr() { return value*value; } + int getValSqr(int more) { return value*value*more; } + int getValTimes(int times=1) { return value*times; } +}; + +// Child2 has vtable, parent does not. Checks we cast child->parent properly - (Parent*)child is not a no-op, must offset +class Child2 : public Parent { +public: + Child2() : Parent(9) { printf("Child2:%d\n", value); }; + int getValCube() { return value*value*value; } + static void printStatic() { printf("*static*\n"); } + + virtual void virtualFunc() { printf("*virtualf*\n"); } + virtual void virtualFunc2() { printf("*virtualf2*\n"); } + static void runVirtualFunc(Child2 *self) { self->virtualFunc(); }; + virtual void virtualFunc3(int x) { printf("*virtualf3: %d*\n", x); } + virtual void virtualFunc4(int x) { printf("*virtualf4: %d*\n", x); } + +private: + void doSomethingSecret() { printf("security breached!\n"); }; // we should not be able to do this +}; + +// Part 2 + +#include + +class StringUser { + char *s; + int i; +public: + StringUser(char *string="NO", int integer=99) : s(strdup(string)), i(integer) {} + void Print(int anotherInteger, char *anotherString) { + printf("|%s|%d|%s|%d|\n", s, i, anotherString, anotherInteger); + } + void PrintFloat(float f) { printf("%.2f\n", f); } +}; + +struct RefUser { + int value; + RefUser(int x = 77) : value(x) {} + int getValue(RefUser b) { return b.value; } + RefUser &getMe() { return *this; } + RefUser getCopy() { return RefUser(value*2); } + StringUser getAnother() { return StringUser("another", 5); } +}; + +namespace Space { + struct Inner { + Inner() {} + int get() { return 198; } + Inner& operator*=(float x) { return *this; } + }; +} + diff --git a/tests/webidl/test.idl b/tests/webidl/test.idl new file mode 100644 index 0000000000000..98ab50703938e --- /dev/null +++ b/tests/webidl/test.idl @@ -0,0 +1,64 @@ + +// Part 1 + +interface Parent { + void Parent(long val); + long getVal(); + void mulVal(long mul); +}; + +interface Child1 { + void Child1(optional long val); + long getValSqr(optional long more); + long getValTimes(optional long times=1); +}; + +Child1 implements Parent; + +interface Child2 { + void Child2(); + long getValCube(); + static void printStatic(); + void virtualFunc(); + void virtualFunc2(); + void virtualFunc3(long x); + void virtualFunc4(long x); + static void runVirtualFunc(Child2 self); +}; + +Child2 implements Parent; + +[JSImplementation="Child2"] +interface Child2JS { + void Child2JS(); + void virtualFunc(); + void virtualFunc2(); + void virtualFunc3(long x); + void virtualFunc4(long x); +}; + +// Part 2 + +interface StringUser { + void StringUser(); + void StringUser(DOMString str, long i); + void Print(long anotherInteger, DOMString anotherString); + void PrintFloat(float f); +}; + +interface RefUser { + void RefUser(); + void RefUser(long value); + long getValue([Ref] RefUser b); + [Ref] RefUser getMe(); + [Value] RefUser getCopy(); // must have zero-arg constructor + [Value] StringUser getAnother(); +}; + +[Prefix="Space::"] +interface Inner { + void Inner(); + long get(); + [Operator="*=", Ref] Inner mul(float x); +}; + diff --git a/third_party/WebIDL.py b/third_party/WebIDL.py new file mode 100644 index 0000000000000..867a7cbc3dfd0 --- /dev/null +++ b/third_party/WebIDL.py @@ -0,0 +1,5030 @@ +# from http://mxr.mozilla.org/mozilla-central/source/dom/bindings/parser/WebIDL.py +# rev 501baeb3a034 + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +""" A WebIDL parser. """ + +from ply import lex, yacc +import re +import os +import traceback +import math + +# Machinery + +def parseInt(literal): + string = literal + sign = 0 + base = 0 + + if string[0] == '-': + sign = -1 + string = string[1:] + else: + sign = 1 + + if string[0] == '0' and len(string) > 1: + if string[1] == 'x' or string[1] == 'X': + base = 16 + string = string[2:] + else: + base = 8 + string = string[1:] + else: + base = 10 + + value = int(string, base) + return value * sign + +# Magic for creating enums +def M_add_class_attribs(attribs, start): + def foo(name, bases, dict_): + for v, k in enumerate(attribs): + dict_[k] = start + v + assert 'length' not in dict_ + dict_['length'] = start + len(attribs) + return type(name, bases, dict_) + return foo + +def enum(*names, **kw): + if len(kw) == 1: + base = kw['base'].__class__ + start = base.length + else: + assert len(kw) == 0 + base = object + start = 0 + class Foo(base): + __metaclass__ = M_add_class_attribs(names, start) + def __setattr__(self, name, value): # this makes it read-only + raise NotImplementedError + return Foo() + +class WebIDLError(Exception): + def __init__(self, message, locations, warning=False): + self.message = message + self.locations = [str(loc) for loc in locations] + self.warning = warning + + def __str__(self): + return "%s: %s%s%s" % (self.warning and 'warning' or 'error', + self.message, + ", " if len(self.locations) != 0 else "", + "\n".join(self.locations)) + +class Location(object): + def __init__(self, lexer, lineno, lexpos, filename): + self._line = None + self._lineno = lineno + self._lexpos = lexpos + self._lexdata = lexer.lexdata + self._file = filename if filename else "" + + def __eq__(self, other): + return self._lexpos == other._lexpos and \ + self._file == other._file + + def filename(self): + return self._file + + def resolve(self): + if self._line: + return + + startofline = self._lexdata.rfind('\n', 0, self._lexpos) + 1 + endofline = self._lexdata.find('\n', self._lexpos, self._lexpos + 80) + if endofline != -1: + self._line = self._lexdata[startofline:endofline] + else: + self._line = self._lexdata[startofline:] + self._colno = self._lexpos - startofline + + # Our line number seems to point to the start of self._lexdata + self._lineno += self._lexdata.count('\n', 0, startofline) + + def get(self): + self.resolve() + return "%s line %s:%s" % (self._file, self._lineno, self._colno) + + def _pointerline(self): + return " " * self._colno + "^" + + def __str__(self): + self.resolve() + return "%s line %s:%s\n%s\n%s" % (self._file, self._lineno, self._colno, + self._line, self._pointerline()) + +class BuiltinLocation(object): + def __init__(self, text): + self.msg = text + "\n" + + def __eq__(self, other): + return isinstance(other, BuiltinLocation) and \ + self.msg == other.msg + + def filename(self): + return '' + + def resolve(self): + pass + + def get(self): + return self.msg + + def __str__(self): + return self.get() + + +# Data Model + +class IDLObject(object): + def __init__(self, location): + self.location = location + self.userData = dict() + + def filename(self): + return self.location.filename() + + def isInterface(self): + return False + + def isEnum(self): + return False + + def isCallback(self): + return False + + def isType(self): + return False + + def isDictionary(self): + return False; + + def isUnion(self): + return False + + def getUserData(self, key, default): + return self.userData.get(key, default) + + def setUserData(self, key, value): + self.userData[key] = value + + def addExtendedAttributes(self, attrs): + assert False # Override me! + + def handleExtendedAttribute(self, attr): + assert False # Override me! + + def _getDependentObjects(self): + assert False # Override me! + + def getDeps(self, visited=None): + """ Return a set of files that this object depends on. If any of + these files are changed the parser needs to be rerun to regenerate + a new IDLObject. + + The visited argument is a set of all the objects already visited. + We must test to see if we are in it, and if so, do nothing. This + prevents infinite recursion.""" + + # NB: We can't use visited=set() above because the default value is + # evaluated when the def statement is evaluated, not when the function + # is executed, so there would be one set for all invocations. + if visited == None: + visited = set() + + if self in visited: + return set() + + visited.add(self) + + deps = set() + if self.filename() != "": + deps.add(self.filename()) + + for d in self._getDependentObjects(): + deps = deps.union(d.getDeps(visited)) + + return deps + +class IDLScope(IDLObject): + def __init__(self, location, parentScope, identifier): + IDLObject.__init__(self, location) + + self.parentScope = parentScope + if identifier: + assert isinstance(identifier, IDLIdentifier) + self._name = identifier + else: + self._name = None + + self._dict = {} + + def __str__(self): + return self.QName() + + def QName(self): + if self._name: + return self._name.QName() + "::" + return "::" + + def ensureUnique(self, identifier, object): + """ + Ensure that there is at most one 'identifier' in scope ('self'). + Note that object can be None. This occurs if we end up here for an + interface type we haven't seen yet. + """ + assert isinstance(identifier, IDLUnresolvedIdentifier) + assert not object or isinstance(object, IDLObjectWithIdentifier) + assert not object or object.identifier == identifier + + if identifier.name in self._dict: + if not object: + return + + # ensureUnique twice with the same object is not allowed + assert id(object) != id(self._dict[identifier.name]) + + replacement = self.resolveIdentifierConflict(self, identifier, + self._dict[identifier.name], + object) + self._dict[identifier.name] = replacement + return + + assert object + + self._dict[identifier.name] = object + + def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): + if isinstance(originalObject, IDLExternalInterface) and \ + isinstance(newObject, IDLExternalInterface) and \ + originalObject.identifier.name == newObject.identifier.name: + return originalObject + + if (isinstance(originalObject, IDLExternalInterface) or + isinstance(newObject, IDLExternalInterface)): + raise WebIDLError( + "Name collision between " + "interface declarations for identifier '%s' at '%s' and '%s'" + % (identifier.name, + originalObject.location, newObject.location), []) + + # We do the merging of overloads here as opposed to in IDLInterface + # because we need to merge overloads of NamedConstructors and we need to + # detect conflicts in those across interfaces. See also the comment in + # IDLInterface.addExtendedAttributes for "NamedConstructor". + if originalObject.tag == IDLInterfaceMember.Tags.Method and \ + newObject.tag == IDLInterfaceMember.Tags.Method: + return originalObject.addOverload(newObject) + + # Default to throwing, derived classes can override. + conflictdesc = "\n\t%s at %s\n\t%s at %s" % \ + (originalObject, originalObject.location, newObject, newObject.location) + + raise WebIDLError( + "Multiple unresolvable definitions of identifier '%s' in scope '%s%s" + % (identifier.name, str(self), conflictdesc), []) + + def _lookupIdentifier(self, identifier): + return self._dict[identifier.name] + + def lookupIdentifier(self, identifier): + assert isinstance(identifier, IDLIdentifier) + assert identifier.scope == self + return self._lookupIdentifier(identifier) + +class IDLIdentifier(IDLObject): + def __init__(self, location, scope, name): + IDLObject.__init__(self, location) + + self.name = name + assert isinstance(scope, IDLScope) + self.scope = scope + + def __str__(self): + return self.QName() + + def QName(self): + return self.scope.QName() + self.name + + def __hash__(self): + return self.QName().__hash__() + + def __eq__(self, other): + return self.QName() == other.QName() + + def object(self): + return self.scope.lookupIdentifier(self) + +class IDLUnresolvedIdentifier(IDLObject): + def __init__(self, location, name, allowDoubleUnderscore = False, + allowForbidden = False): + IDLObject.__init__(self, location) + + assert len(name) > 0 + + if name[:2] == "__" and name != "__content" and name != "___noSuchMethod__" and not allowDoubleUnderscore: + raise WebIDLError("Identifiers beginning with __ are reserved", + [location]) + if name[0] == '_' and not allowDoubleUnderscore: + name = name[1:] + # TODO: Bug 872377, Restore "toJSON" to below list. + # We sometimes need custom serialization, so allow toJSON for now. + if (name in ["constructor", "toString"] and + not allowForbidden): + raise WebIDLError("Cannot use reserved identifier '%s'" % (name), + [location]) + + self.name = name + + def __str__(self): + return self.QName() + + def QName(self): + return "::" + self.name + + def resolve(self, scope, object): + assert isinstance(scope, IDLScope) + assert not object or isinstance(object, IDLObjectWithIdentifier) + assert not object or object.identifier == self + + scope.ensureUnique(self, object) + + identifier = IDLIdentifier(self.location, scope, self.name) + if object: + object.identifier = identifier + return identifier + + def finish(self): + assert False # Should replace with a resolved identifier first. + +class IDLObjectWithIdentifier(IDLObject): + def __init__(self, location, parentScope, identifier): + IDLObject.__init__(self, location) + + assert isinstance(identifier, IDLUnresolvedIdentifier) + + self.identifier = identifier + + if parentScope: + self.resolve(parentScope) + + self.treatNullAs = "Default" + + def resolve(self, parentScope): + assert isinstance(parentScope, IDLScope) + assert isinstance(self.identifier, IDLUnresolvedIdentifier) + self.identifier.resolve(parentScope, self) + + def checkForStringHandlingExtendedAttributes(self, attrs, + isDictionaryMember=False, + isOptional=False): + """ + A helper function to deal with TreatNullAs. Returns the list + of attrs it didn't handle itself. + """ + assert isinstance(self, IDLArgument) or isinstance(self, IDLAttribute) + unhandledAttrs = list() + for attr in attrs: + if not attr.hasValue(): + unhandledAttrs.append(attr) + continue + + identifier = attr.identifier() + value = attr.value() + if identifier == "TreatNullAs": + if not self.type.isDOMString() or self.type.nullable(): + raise WebIDLError("[TreatNullAs] is only allowed on " + "arguments or attributes whose type is " + "DOMString", + [self.location]) + if isDictionaryMember: + raise WebIDLError("[TreatNullAs] is not allowed for " + "dictionary members", [self.location]) + if value != 'EmptyString': + raise WebIDLError("[TreatNullAs] must take the identifier " + "'EmptyString', not '%s'" % value, + [self.location]) + self.treatNullAs = value + else: + unhandledAttrs.append(attr) + + return unhandledAttrs + +class IDLObjectWithScope(IDLObjectWithIdentifier, IDLScope): + def __init__(self, location, parentScope, identifier): + assert isinstance(identifier, IDLUnresolvedIdentifier) + + IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) + IDLScope.__init__(self, location, parentScope, self.identifier) + +class IDLIdentifierPlaceholder(IDLObjectWithIdentifier): + def __init__(self, location, identifier): + assert isinstance(identifier, IDLUnresolvedIdentifier) + IDLObjectWithIdentifier.__init__(self, location, None, identifier) + + def finish(self, scope): + try: + scope._lookupIdentifier(self.identifier) + except: + raise WebIDLError("Unresolved type '%s'." % self.identifier, + [self.location]) + + obj = self.identifier.resolve(scope, None) + return scope.lookupIdentifier(obj) + +class IDLExternalInterface(IDLObjectWithIdentifier): + def __init__(self, location, parentScope, identifier): + assert isinstance(identifier, IDLUnresolvedIdentifier) + assert isinstance(parentScope, IDLScope) + self.parent = None + IDLObjectWithIdentifier.__init__(self, location, parentScope, identifier) + IDLObjectWithIdentifier.resolve(self, parentScope) + + def finish(self, scope): + pass + + def validate(self): + pass + + def isExternal(self): + return True + + def isInterface(self): + return True + + def isConsequential(self): + return False + + def addExtendedAttributes(self, attrs): + assert len(attrs) == 0 + + def resolve(self, parentScope): + pass + + def getJSImplementation(self): + return None + + def isJSImplemented(self): + return False + + def getNavigatorProperty(self): + return None + + def _getDependentObjects(self): + return set() + +class IDLInterface(IDLObjectWithScope): + def __init__(self, location, parentScope, name, parent, members, + isPartial): + assert isinstance(parentScope, IDLScope) + assert isinstance(name, IDLUnresolvedIdentifier) + assert not isPartial or not parent + + self.parent = None + self._callback = False + self._finished = False + self.members = [] + # namedConstructors needs deterministic ordering because bindings code + # outputs the constructs in the order that namedConstructors enumerates + # them. + self.namedConstructors = list() + self.implementedInterfaces = set() + self._consequential = False + self._isPartial = True + # self.interfacesBasedOnSelf is the set of interfaces that inherit from + # self or have self as a consequential interface, including self itself. + # Used for distinguishability checking. + self.interfacesBasedOnSelf = set([self]) + # self.interfacesImplementingSelf is the set of interfaces that directly + # have self as a consequential interface + self.interfacesImplementingSelf = set() + self._hasChildInterfaces = False + self._isOnGlobalProtoChain = False + # Tracking of the number of reserved slots we need for our + # members and those of ancestor interfaces. + self.totalMembersInSlots = 0 + # Tracking of the number of own own members we have in slots + self._ownMembersInSlots = 0 + + IDLObjectWithScope.__init__(self, location, parentScope, name) + + if not isPartial: + self.setNonPartial(location, parent, members) + else: + # Just remember our members for now + self.members = members + + def __str__(self): + return "Interface '%s'" % self.identifier.name + + def ctor(self): + identifier = IDLUnresolvedIdentifier(self.location, "constructor", + allowForbidden=True) + try: + return self._lookupIdentifier(identifier) + except: + return None + + def resolveIdentifierConflict(self, scope, identifier, originalObject, newObject): + assert isinstance(scope, IDLScope) + assert isinstance(originalObject, IDLInterfaceMember) + assert isinstance(newObject, IDLInterfaceMember) + + retval = IDLScope.resolveIdentifierConflict(self, scope, identifier, + originalObject, newObject) + + # Might be a ctor, which isn't in self.members + if newObject in self.members: + self.members.remove(newObject) + return retval + + def finish(self, scope): + if self._finished: + return + + self._finished = True + + if self._isPartial: + raise WebIDLError("Interface %s does not have a non-partial " + "declaration" % self.identifier.name, + [self.location]) + + assert not self.parent or isinstance(self.parent, IDLIdentifierPlaceholder) + parent = self.parent.finish(scope) if self.parent else None + if parent and isinstance(parent, IDLExternalInterface): + raise WebIDLError("%s inherits from %s which does not have " + "a definition" % + (self.identifier.name, + self.parent.identifier.name), + [self.location]) + assert not parent or isinstance(parent, IDLInterface) + + self.parent = parent + + assert iter(self.members) + + if self.parent: + self.parent.finish(scope) + + self.parent._hasChildInterfaces = True + + self.totalMembersInSlots = self.parent.totalMembersInSlots + + # Interfaces with [Global] must not have anything inherit from them + if self.parent.getExtendedAttribute("Global"): + # Note: This is not a self.parent.isOnGlobalProtoChain() check + # because ancestors of a [Global] interface can have other + # descendants. + raise WebIDLError("[Global] interface has another interface " + "inheriting from it", + [self.location, self.parent.location]) + + # Callbacks must not inherit from non-callbacks or inherit from + # anything that has consequential interfaces. + # XXXbz Can non-callbacks inherit from callbacks? Spec issue pending. + # XXXbz Can callbacks have consequential interfaces? Spec issue pending + if self.isCallback(): + if not self.parent.isCallback(): + raise WebIDLError("Callback interface %s inheriting from " + "non-callback interface %s" % + (self.identifier.name, + self.parent.identifier.name), + [self.location, self.parent.location]) + elif self.parent.isCallback(): + raise WebIDLError("Non-callback interface %s inheriting from " + "callback interface %s" % + (self.identifier.name, + self.parent.identifier.name), + [self.location, self.parent.location]) + + for iface in self.implementedInterfaces: + iface.finish(scope) + + cycleInGraph = self.findInterfaceLoopPoint(self) + if cycleInGraph: + raise WebIDLError("Interface %s has itself as ancestor or " + "implemented interface" % self.identifier.name, + [self.location, cycleInGraph.location]) + + if self.isCallback(): + # "implements" should have made sure we have no + # consequential interfaces. + assert len(self.getConsequentialInterfaces()) == 0 + # And that we're not consequential. + assert not self.isConsequential() + + # Now resolve() and finish() our members before importing the + # ones from our implemented interfaces. + + # resolve() will modify self.members, so we need to iterate + # over a copy of the member list here. + for member in list(self.members): + member.resolve(self) + + for member in self.members: + member.finish(scope) + + ctor = self.ctor() + if ctor is not None: + ctor.finish(scope) + + for ctor in self.namedConstructors: + ctor.finish(scope) + + # Make a copy of our member list, so things that implement us + # can get those without all the stuff we implement ourselves + # admixed. + self.originalMembers = list(self.members) + + # Import everything from our consequential interfaces into + # self.members. Sort our consequential interfaces by name + # just so we have a consistent order. + for iface in sorted(self.getConsequentialInterfaces(), + cmp=cmp, + key=lambda x: x.identifier.name): + # Flag the interface as being someone's consequential interface + iface.setIsConsequentialInterfaceOf(self) + additionalMembers = iface.originalMembers; + for additionalMember in additionalMembers: + for member in self.members: + if additionalMember.identifier.name == member.identifier.name: + raise WebIDLError( + "Multiple definitions of %s on %s coming from 'implements' statements" % + (member.identifier.name, self), + [additionalMember.location, member.location]) + self.members.extend(additionalMembers) + iface.interfacesImplementingSelf.add(self) + + for ancestor in self.getInheritedInterfaces(): + ancestor.interfacesBasedOnSelf.add(self) + for ancestorConsequential in ancestor.getConsequentialInterfaces(): + ancestorConsequential.interfacesBasedOnSelf.add(self) + + for member in self.members: + if (member.isAttr() and member.isUnforgeable() and + not hasattr(member, "originatingInterface")): + member.originatingInterface = self + + # Compute slot indices for our members before we pull in + # unforgeable members from our parent. + for member in self.members: + if (member.isAttr() and + (member.getExtendedAttribute("StoreInSlot") or + member.getExtendedAttribute("Cached"))): + member.slotIndex = self.totalMembersInSlots + self.totalMembersInSlots += 1 + if member.getExtendedAttribute("StoreInSlot"): + self._ownMembersInSlots += 1 + + if self.parent: + # Make sure we don't shadow any of the [Unforgeable] attributes on + # our ancestor interfaces. We don't have to worry about + # consequential interfaces here, because those have already been + # imported into the relevant .members lists. And we don't have to + # worry about anything other than our parent, because it has already + # imported its ancestors unforgeable attributes into its member + # list. + for unforgeableAttr in (attr for attr in self.parent.members if + attr.isAttr() and not attr.isStatic() and + attr.isUnforgeable()): + shadows = [ m for m in self.members if + (m.isAttr() or m.isMethod()) and + not m.isStatic() and + m.identifier.name == unforgeableAttr.identifier.name ] + if len(shadows) != 0: + locs = [unforgeableAttr.location] + [ s.location for s + in shadows ] + raise WebIDLError("Interface %s shadows [Unforgeable] " + "members of %s" % + (self.identifier.name, + ancestor.identifier.name), + locs) + # And now just stick it in our members, since we won't be + # inheriting this down the proto chain. If we really cared we + # could try to do something where we set up the unforgeable + # attributes of ancestor interfaces, with their corresponding + # getters, on our interface, but that gets pretty complicated + # and seems unnecessary. + self.members.append(unforgeableAttr) + + # Ensure that there's at most one of each {named,indexed} + # {getter,setter,creator,deleter}, at most one stringifier, + # and at most one legacycaller. Note that this last is not + # quite per spec, but in practice no one overloads + # legacycallers. + specialMembersSeen = {} + for member in self.members: + if not member.isMethod(): + continue + + if member.isGetter(): + memberType = "getters" + elif member.isSetter(): + memberType = "setters" + elif member.isCreator(): + memberType = "creators" + elif member.isDeleter(): + memberType = "deleters" + elif member.isStringifier(): + memberType = "stringifiers" + elif member.isJsonifier(): + memberType = "jsonifiers" + elif member.isLegacycaller(): + memberType = "legacycallers" + else: + continue + + if (memberType != "stringifiers" and memberType != "legacycallers" and + memberType != "jsonifiers"): + if member.isNamed(): + memberType = "named " + memberType + else: + assert member.isIndexed() + memberType = "indexed " + memberType + + if memberType in specialMembersSeen: + raise WebIDLError("Multiple " + memberType + " on %s" % (self), + [self.location, + specialMembersSeen[memberType].location, + member.location]) + + specialMembersSeen[memberType] = member + + if self._isOnGlobalProtoChain: + # Make sure we have no named setters, creators, or deleters + for memberType in ["setter", "creator", "deleter"]: + memberId = "named " + memberType + "s" + if memberId in specialMembersSeen: + raise WebIDLError("Interface with [Global] has a named %s" % + memberType, + [self.location, + specialMembersSeen[memberId].location]) + # Make sure we're not [OverrideBuiltins] + if self.getExtendedAttribute("OverrideBuiltins"): + raise WebIDLError("Interface with [Global] also has " + "[OverrideBuiltins]", + [self.location]) + # Mark all of our ancestors as being on the global's proto chain too + parent = self.parent + while parent: + # Must not inherit from an interface with [OverrideBuiltins] + if parent.getExtendedAttribute("OverrideBuiltins"): + raise WebIDLError("Interface with [Global] inherits from " + "interface with [OverrideBuiltins]", + [self.location, parent.location]) + parent._isOnGlobalProtoChain = True + parent = parent.parent + + def validate(self): + for member in self.members: + member.validate() + + # Check that PutForwards refers to another attribute and that no + # cycles exist in forwarded assignments. + if member.isAttr(): + iface = self + attr = member + putForwards = attr.getExtendedAttribute("PutForwards") + if putForwards and self.isCallback(): + raise WebIDLError("[PutForwards] used on an attribute " + "on interface %s which is a callback " + "interface" % self.identifier.name, + [self.location, member.location]) + + while putForwards is not None: + forwardIface = attr.type.unroll().inner + fowardAttr = None + + for forwardedMember in forwardIface.members: + if (not forwardedMember.isAttr() or + forwardedMember.identifier.name != putForwards[0]): + continue + if forwardedMember == member: + raise WebIDLError("Cycle detected in forwarded " + "assignments for attribute %s on " + "%s" % + (member.identifier.name, self), + [member.location]) + fowardAttr = forwardedMember + break + + if fowardAttr is None: + raise WebIDLError("Attribute %s on %s forwards to " + "missing attribute %s" % + (attr.identifier.name, iface, putForwards), + [attr.location]) + + iface = forwardIface + attr = fowardAttr + putForwards = attr.getExtendedAttribute("PutForwards") + + + def isInterface(self): + return True + + def isExternal(self): + return False + + def setIsConsequentialInterfaceOf(self, other): + self._consequential = True + self.interfacesBasedOnSelf.add(other) + + def isConsequential(self): + return self._consequential + + def setCallback(self, value): + self._callback = value + + def isCallback(self): + return self._callback + + def isSingleOperationInterface(self): + assert self.isCallback() or self.isJSImplemented() + return ( + # JS-implemented things should never need the + # this-handling weirdness of single-operation interfaces. + not self.isJSImplemented() and + # Not inheriting from another interface + not self.parent and + # No consequential interfaces + len(self.getConsequentialInterfaces()) == 0 and + # No attributes of any kinds + not any(m.isAttr() for m in self.members) and + # There is at least one regular operation, and all regular + # operations have the same identifier + len(set(m.identifier.name for m in self.members if + m.isMethod() and not m.isStatic())) == 1) + + def inheritanceDepth(self): + depth = 0 + parent = self.parent + while parent: + depth = depth + 1 + parent = parent.parent + return depth + + def hasConstants(self): + return any(m.isConst() for m in self.members) + + def hasInterfaceObject(self): + if self.isCallback(): + return self.hasConstants() + return not hasattr(self, "_noInterfaceObject") + + def hasInterfacePrototypeObject(self): + return not self.isCallback() and self.getUserData('hasConcreteDescendant', False) + + def addExtendedAttributes(self, attrs): + self._extendedAttrDict = {} + for attr in attrs: + identifier = attr.identifier() + + # Special cased attrs + if identifier == "TreatNonCallableAsNull": + raise WebIDLError("TreatNonCallableAsNull cannot be specified on interfaces", + [attr.location, self.location]) + if identifier == "TreatNonObjectAsNull": + raise WebIDLError("TreatNonObjectAsNull cannot be specified on interfaces", + [attr.location, self.location]) + elif identifier == "NoInterfaceObject": + if not attr.noArguments(): + raise WebIDLError("[NoInterfaceObject] must take no arguments", + [attr.location]) + + if self.ctor(): + raise WebIDLError("Constructor and NoInterfaceObject are incompatible", + [self.location]) + + self._noInterfaceObject = True + elif identifier == "Constructor" or identifier == "NamedConstructor" or identifier == "ChromeConstructor": + if identifier == "Constructor" and not self.hasInterfaceObject(): + raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", + [self.location]) + + if identifier == "NamedConstructor" and not attr.hasValue(): + raise WebIDLError("NamedConstructor must either take an identifier or take a named argument list", + [attr.location]) + + if identifier == "ChromeConstructor" and not self.hasInterfaceObject(): + raise WebIDLError(str(identifier) + " and NoInterfaceObject are incompatible", + [self.location]) + + args = attr.args() if attr.hasArgs() else [] + + retType = IDLWrapperType(self.location, self) + + if identifier == "Constructor" or identifier == "ChromeConstructor": + name = "constructor" + allowForbidden = True + else: + name = attr.value() + allowForbidden = False + + methodIdentifier = IDLUnresolvedIdentifier(self.location, name, + allowForbidden=allowForbidden) + + method = IDLMethod(self.location, methodIdentifier, retType, + args, static=True) + # Constructors are always NewObject and are always + # assumed to be able to throw (since there's no way to + # indicate otherwise) and never have any other + # extended attributes. + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("NewObject",)), + IDLExtendedAttribute(self.location, ("Throws",))]) + if identifier == "ChromeConstructor": + method.addExtendedAttributes( + [IDLExtendedAttribute(self.location, ("ChromeOnly",))]) + + if identifier == "Constructor" or identifier == "ChromeConstructor": + method.resolve(self) + else: + # We need to detect conflicts for NamedConstructors across + # interfaces. We first call resolve on the parentScope, + # which will merge all NamedConstructors with the same + # identifier accross interfaces as overloads. + method.resolve(self.parentScope) + + # Then we look up the identifier on the parentScope. If the + # result is the same as the method we're adding then it + # hasn't been added as an overload and it's the first time + # we've encountered a NamedConstructor with that identifier. + # If the result is not the same as the method we're adding + # then it has been added as an overload and we need to check + # whether the result is actually one of our existing + # NamedConstructors. + newMethod = self.parentScope.lookupIdentifier(method.identifier) + if newMethod == method: + self.namedConstructors.append(method) + elif not newMethod in self.namedConstructors: + raise WebIDLError("NamedConstructor conflicts with a NamedConstructor of a different interface", + [method.location, newMethod.location]) + elif (identifier == "ArrayClass"): + if not attr.noArguments(): + raise WebIDLError("[ArrayClass] must take no arguments", + [attr.location]) + if self.parent: + raise WebIDLError("[ArrayClass] must not be specified on " + "an interface with inherited interfaces", + [attr.location, self.location]) + elif identifier == "Global": + if not attr.noArguments(): + raise WebIDLError("[Global] must take no arguments", + [attr.location]) + self._isOnGlobalProtoChain = True + elif (identifier == "NeedNewResolve" or + identifier == "OverrideBuiltins" or + identifier == "NoDelete" or + identifier == "ChromeOnly"): + # Known extended attributes that do not take values + if not attr.noArguments(): + raise WebIDLError("[%s] must take no arguments" % identifier, + [attr.location]) + elif (identifier == "Pref" or + identifier == "JSImplementation" or + identifier == "HeaderFile" or + identifier == "NavigatorProperty" or + identifier == "AvailableIn" or + identifier == "Prefix" or + identifier == "Func"): + # Known extended attributes that take a string value + if not attr.hasValue(): + raise WebIDLError("[%s] must have a value" % identifier, + [attr.location]) + else: + raise WebIDLError("Unknown extended attribute %s on interface" % identifier, + [attr.location]) + + attrlist = attr.listValue() + self._extendedAttrDict[identifier] = attrlist if len(attrlist) else True + + def addImplementedInterface(self, implementedInterface): + assert(isinstance(implementedInterface, IDLInterface)) + self.implementedInterfaces.add(implementedInterface) + + def getInheritedInterfaces(self): + """ + Returns a list of the interfaces this interface inherits from + (not including this interface itself). The list is in order + from most derived to least derived. + """ + assert(self._finished) + if not self.parent: + return [] + parentInterfaces = self.parent.getInheritedInterfaces() + parentInterfaces.insert(0, self.parent) + return parentInterfaces + + def getConsequentialInterfaces(self): + assert(self._finished) + # The interfaces we implement directly + consequentialInterfaces = set(self.implementedInterfaces) + + # And their inherited interfaces + for iface in self.implementedInterfaces: + consequentialInterfaces |= set(iface.getInheritedInterfaces()) + + # And now collect up the consequential interfaces of all of those + temp = set() + for iface in consequentialInterfaces: + temp |= iface.getConsequentialInterfaces() + + return consequentialInterfaces | temp + + def findInterfaceLoopPoint(self, otherInterface): + """ + Finds an interface, amongst our ancestors and consequential interfaces, + that inherits from otherInterface or implements otherInterface + directly. If there is no such interface, returns None. + """ + if self.parent: + if self.parent == otherInterface: + return self + loopPoint = self.parent.findInterfaceLoopPoint(otherInterface) + if loopPoint: + return loopPoint + if otherInterface in self.implementedInterfaces: + return self + for iface in self.implementedInterfaces: + loopPoint = iface.findInterfaceLoopPoint(otherInterface) + if loopPoint: + return loopPoint + return None + + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) + + def setNonPartial(self, location, parent, members): + assert not parent or isinstance(parent, IDLIdentifierPlaceholder) + if not self._isPartial: + raise WebIDLError("Two non-partial definitions for the " + "same interface", + [location, self.location]) + self._isPartial = False + # Now make it look like we were parsed at this new location, since + # that's the place where the interface is "really" defined + self.location = location + assert not self.parent + self.parent = parent + # Put the new members at the beginning + self.members = members + self.members + + def getJSImplementation(self): + classId = self.getExtendedAttribute("JSImplementation") + if not classId: + return classId + assert isinstance(classId, list) + assert len(classId) == 1 + return classId[0] + + def isJSImplemented(self): + return bool(self.getJSImplementation()) + + def getNavigatorProperty(self): + naviProp = self.getExtendedAttribute("NavigatorProperty") + if not naviProp: + return None + assert len(naviProp) == 1 + assert isinstance(naviProp, list) + assert len(naviProp[0]) != 0 + return naviProp[0] + + def hasChildInterfaces(self): + return self._hasChildInterfaces + + def isOnGlobalProtoChain(self): + return self._isOnGlobalProtoChain + + def _getDependentObjects(self): + deps = set(self.members) + deps.union(self.implementedInterfaces) + if self.parent: + deps.add(self.parent) + return deps + + def hasMembersInSlots(self): + return self._ownMembersInSlots != 0 + +class IDLDictionary(IDLObjectWithScope): + def __init__(self, location, parentScope, name, parent, members): + assert isinstance(parentScope, IDLScope) + assert isinstance(name, IDLUnresolvedIdentifier) + assert not parent or isinstance(parent, IDLIdentifierPlaceholder) + + self.parent = parent + self._finished = False + self.members = list(members) + + IDLObjectWithScope.__init__(self, location, parentScope, name) + + def __str__(self): + return "Dictionary '%s'" % self.identifier.name + + def isDictionary(self): + return True; + + def finish(self, scope): + if self._finished: + return + + self._finished = True + + if self.parent: + assert isinstance(self.parent, IDLIdentifierPlaceholder) + oldParent = self.parent + self.parent = self.parent.finish(scope) + if not isinstance(self.parent, IDLDictionary): + raise WebIDLError("Dictionary %s has parent that is not a dictionary" % + self.identifier.name, + [oldParent.location, self.parent.location]) + + # Make sure the parent resolves all its members before we start + # looking at them. + self.parent.finish(scope) + + for member in self.members: + member.resolve(self) + if not member.isComplete(): + member.complete(scope) + assert member.type.isComplete() + + # Members of a dictionary are sorted in lexicographic order + self.members.sort(cmp=cmp, key=lambda x: x.identifier.name) + + inheritedMembers = [] + ancestor = self.parent + while ancestor: + if ancestor == self: + raise WebIDLError("Dictionary %s has itself as an ancestor" % + self.identifier.name, + [self.identifier.location]) + inheritedMembers.extend(ancestor.members) + ancestor = ancestor.parent + + # Catch name duplication + for inheritedMember in inheritedMembers: + for member in self.members: + if member.identifier.name == inheritedMember.identifier.name: + raise WebIDLError("Dictionary %s has two members with name %s" % + (self.identifier.name, member.identifier.name), + [member.location, inheritedMember.location]) + + def validate(self): + def typeContainsDictionary(memberType, dictionary): + """ + Returns a tuple whose: + + - First element is a Boolean value indicating whether + memberType contains dictionary. + + - Second element is: + A list of locations that leads from the type that was passed in + the memberType argument, to the dictionary being validated, + if the boolean value in the first element is True. + + None, if the boolean value in the first element is False. + """ + + if memberType.nullable() or \ + memberType.isArray() or \ + memberType.isSequence(): + return typeContainsDictionary(memberType.inner, dictionary) + + if memberType.isDictionary(): + if memberType.inner == dictionary: + return (True, [memberType.location]) + + (contains, locations) = dictionaryContainsDictionary(memberType.inner, \ + dictionary) + if contains: + return (True, [memberType.location] + locations) + + if memberType.isUnion(): + for member in memberType.flatMemberTypes: + (contains, locations) = typeContainsDictionary(member, dictionary) + if contains: + return (True, locations) + + return (False, None) + + def dictionaryContainsDictionary(dictMember, dictionary): + for member in dictMember.members: + (contains, locations) = typeContainsDictionary(member.type, dictionary) + if contains: + return (True, [member.location] + locations) + + if dictMember.parent: + if dictMember.parent == dictionary: + return (True, [dictMember.location]) + else: + (contains, locations) = dictionaryContainsDictionary(dictMember.parent, dictionary) + if contains: + return (True, [dictMember.location] + locations) + + return (False, None) + + for member in self.members: + if member.type.isDictionary() and member.type.nullable(): + raise WebIDLError("Dictionary %s has member with nullable " + "dictionary type" % self.identifier.name, + [member.location]) + (contains, locations) = typeContainsDictionary(member.type, self) + if contains: + raise WebIDLError("Dictionary %s has member with itself as type." % + self.identifier.name, + [member.location] + locations) + + def addExtendedAttributes(self, attrs): + assert len(attrs) == 0 + + def _getDependentObjects(self): + deps = set(self.members) + if (self.parent): + deps.add(self.parent) + return deps + +class IDLEnum(IDLObjectWithIdentifier): + def __init__(self, location, parentScope, name, values): + assert isinstance(parentScope, IDLScope) + assert isinstance(name, IDLUnresolvedIdentifier) + + if len(values) != len(set(values)): + raise WebIDLError("Enum %s has multiple identical strings" % name.name, + [location]) + + IDLObjectWithIdentifier.__init__(self, location, parentScope, name) + self._values = values + + def values(self): + return self._values + + def finish(self, scope): + pass + + def validate(self): + pass + + def isEnum(self): + return True + + def addExtendedAttributes(self, attrs): + assert len(attrs) == 0 + + def _getDependentObjects(self): + return set() + +class IDLType(IDLObject): + Tags = enum( + # The integer types + 'int8', + 'uint8', + 'int16', + 'uint16', + 'int32', + 'uint32', + 'int64', + 'uint64', + # Additional primitive types + 'bool', + 'unrestricted_float', + 'float', + 'unrestricted_double', + # "double" last primitive type to match IDLBuiltinType + 'double', + # Other types + 'any', + 'domstring', + 'bytestring', + 'object', + 'date', + 'void', + # Funny stuff + 'interface', + 'dictionary', + 'enum', + 'callback', + 'union', + 'sequence', + 'array' + ) + + def __init__(self, location, name): + IDLObject.__init__(self, location) + self.name = name + self.builtin = False + + def __eq__(self, other): + return other and self.builtin == other.builtin and self.name == other.name + + def __ne__(self, other): + return not self == other + + def __str__(self): + return str(self.name) + + def isType(self): + return True + + def nullable(self): + return False + + def isPrimitive(self): + return False + + def isBoolean(self): + return False + + def isNumeric(self): + return False + + def isString(self): + return False + + def isByteString(self): + return False + + def isDOMString(self): + return False + + def isVoid(self): + return self.name == "Void" + + def isSequence(self): + return False + + def isArray(self): + return False + + def isArrayBuffer(self): + return False + + def isArrayBufferView(self): + return False + + def isTypedArray(self): + return False + + def isCallbackInterface(self): + return False + + def isNonCallbackInterface(self): + return False + + def isGeckoInterface(self): + """ Returns a boolean indicating whether this type is an 'interface' + type that is implemented in Gecko. At the moment, this returns + true for all interface types that are not types from the TypedArray + spec.""" + return self.isInterface() and not self.isSpiderMonkeyInterface() + + def isSpiderMonkeyInterface(self): + """ Returns a boolean indicating whether this type is an 'interface' + type that is implemented in Spidermonkey. At the moment, this + only returns true for the types from the TypedArray spec. """ + return self.isInterface() and (self.isArrayBuffer() or \ + self.isArrayBufferView() or \ + self.isTypedArray()) + + def isDictionary(self): + return False + + def isInterface(self): + return False + + def isAny(self): + return self.tag() == IDLType.Tags.any + + def isDate(self): + return self.tag() == IDLType.Tags.date + + def isObject(self): + return self.tag() == IDLType.Tags.object + + def isPromise(self): + return False + + def isComplete(self): + return True + + def includesRestrictedFloat(self): + return False + + def isFloat(self): + return False + + def isUnrestricted(self): + # Should only call this on float types + assert self.isFloat() + + def isSerializable(self): + return False + + def tag(self): + assert False # Override me! + + def treatNonCallableAsNull(self): + assert self.tag() == IDLType.Tags.callback + return self.nullable() and self.inner._treatNonCallableAsNull + + def treatNonObjectAsNull(self): + assert self.tag() == IDLType.Tags.callback + return self.nullable() and self.inner._treatNonObjectAsNull + + def addExtendedAttributes(self, attrs): + assert len(attrs) == 0 + + def resolveType(self, parentScope): + pass + + def unroll(self): + return self + + def isDistinguishableFrom(self, other): + raise TypeError("Can't tell whether a generic type is or is not " + "distinguishable from other things") + +class IDLUnresolvedType(IDLType): + """ + Unresolved types are interface types + """ + + def __init__(self, location, name): + IDLType.__init__(self, location, name) + + def isComplete(self): + return False + + def complete(self, scope): + obj = None + try: + obj = scope._lookupIdentifier(self.name) + except: + raise WebIDLError("Unresolved type '%s'." % self.name, + [self.location]) + + assert obj + if obj.isType(): + # obj itself might not be complete; deal with that. + assert obj != self + if not obj.isComplete(): + obj = obj.complete(scope) + return obj + + name = self.name.resolve(scope, None) + return IDLWrapperType(self.location, obj) + + def isDistinguishableFrom(self, other): + raise TypeError("Can't tell whether an unresolved type is or is not " + "distinguishable from other things") + +class IDLNullableType(IDLType): + def __init__(self, location, innerType): + assert not innerType.isVoid() + assert not innerType == BuiltinTypes[IDLBuiltinType.Types.any] + + IDLType.__init__(self, location, innerType.name) + self.inner = innerType + self.builtin = False + + def __eq__(self, other): + return isinstance(other, IDLNullableType) and self.inner == other.inner + + def __str__(self): + return self.inner.__str__() + "OrNull" + + def nullable(self): + return True + + def isCallback(self): + return self.inner.isCallback() + + def isPrimitive(self): + return self.inner.isPrimitive() + + def isBoolean(self): + return self.inner.isBoolean() + + def isNumeric(self): + return self.inner.isNumeric() + + def isString(self): + return self.inner.isString() + + def isByteString(self): + return self.inner.isByteString() + + def isDOMString(self): + return self.inner.isDOMString() + + def isFloat(self): + return self.inner.isFloat() + + def isUnrestricted(self): + return self.inner.isUnrestricted() + + def includesRestrictedFloat(self): + return self.inner.includesRestrictedFloat() + + def isInteger(self): + return self.inner.isInteger() + + def isVoid(self): + return False + + def isSequence(self): + return self.inner.isSequence() + + def isArray(self): + return self.inner.isArray() + + def isArrayBuffer(self): + return self.inner.isArrayBuffer() + + def isArrayBufferView(self): + return self.inner.isArrayBufferView() + + def isTypedArray(self): + return self.inner.isTypedArray() + + def isDictionary(self): + return self.inner.isDictionary() + + def isInterface(self): + return self.inner.isInterface() + + def isCallbackInterface(self): + return self.inner.isCallbackInterface() + + def isNonCallbackInterface(self): + return self.inner.isNonCallbackInterface() + + def isEnum(self): + return self.inner.isEnum() + + def isUnion(self): + return self.inner.isUnion() + + def isSerializable(self): + return self.inner.isSerializable() + + def tag(self): + return self.inner.tag() + + def resolveType(self, parentScope): + assert isinstance(parentScope, IDLScope) + self.inner.resolveType(parentScope) + + def isComplete(self): + return self.inner.isComplete() + + def complete(self, scope): + self.inner = self.inner.complete(scope) + if self.inner.nullable(): + raise WebIDLError("The inner type of a nullable type must not be " + "a nullable type", + [self.location, self.inner.location]) + if self.inner.isUnion(): + if self.inner.hasNullableType: + raise WebIDLError("The inner type of a nullable type must not " + "be a union type that itself has a nullable " + "type as a member type", [self.location]) + + self.name = self.inner.name + return self + + def unroll(self): + return self.inner.unroll() + + def isDistinguishableFrom(self, other): + if (other.nullable() or (other.isUnion() and other.hasNullableType) or + other.isDictionary()): + # Can't tell which type null should become + return False + return self.inner.isDistinguishableFrom(other) + + def _getDependentObjects(self): + return self.inner._getDependentObjects() + +class IDLSequenceType(IDLType): + def __init__(self, location, parameterType): + assert not parameterType.isVoid() + + IDLType.__init__(self, location, parameterType.name) + self.inner = parameterType + self.builtin = False + + def __eq__(self, other): + return isinstance(other, IDLSequenceType) and self.inner == other.inner + + def __str__(self): + return self.inner.__str__() + "Sequence" + + def nullable(self): + return False + + def isPrimitive(self): + return False; + + def isString(self): + return False; + + def isByteString(self): + return False + + def isDOMString(self): + return False + + def isVoid(self): + return False + + def isSequence(self): + return True + + def isArray(self): + return False + + def isDictionary(self): + return False + + def isInterface(self): + return False + + def isEnum(self): + return False + + def isSerializable(self): + return self.inner.isSerializable() + + def includesRestrictedFloat(self): + return self.inner.includesRestrictedFloat() + + def tag(self): + return IDLType.Tags.sequence + + def resolveType(self, parentScope): + assert isinstance(parentScope, IDLScope) + self.inner.resolveType(parentScope) + + def isComplete(self): + return self.inner.isComplete() + + def complete(self, scope): + self.inner = self.inner.complete(scope) + self.name = self.inner.name + return self + + def unroll(self): + return self.inner.unroll() + + def isDistinguishableFrom(self, other): + if other.isUnion(): + # Just forward to the union; it'll deal + return other.isDistinguishableFrom(self) + return (other.isPrimitive() or other.isString() or other.isEnum() or + other.isDate() or other.isNonCallbackInterface()) + + def _getDependentObjects(self): + return self.inner._getDependentObjects() + +class IDLUnionType(IDLType): + def __init__(self, location, memberTypes): + IDLType.__init__(self, location, "") + self.memberTypes = memberTypes + self.hasNullableType = False + self.hasDictionaryType = False + self.flatMemberTypes = None + self.builtin = False + + def __eq__(self, other): + return isinstance(other, IDLUnionType) and self.memberTypes == other.memberTypes + + def isVoid(self): + return False + + def isUnion(self): + return True + + def isSerializable(self): + return all(m.isSerializable() for m in self.memberTypes) + + def includesRestrictedFloat(self): + return any(t.includesRestrictedFloat() for t in self.memberTypes) + + def tag(self): + return IDLType.Tags.union + + def resolveType(self, parentScope): + assert isinstance(parentScope, IDLScope) + for t in self.memberTypes: + t.resolveType(parentScope) + + def isComplete(self): + return self.flatMemberTypes is not None + + def complete(self, scope): + def typeName(type): + if isinstance(type, IDLNullableType): + return typeName(type.inner) + "OrNull" + if isinstance(type, IDLWrapperType): + return typeName(type._identifier.object()) + if isinstance(type, IDLObjectWithIdentifier): + return typeName(type.identifier) + if isinstance(type, IDLType) and (type.isArray() or type.isSequence()): + return str(type) + return type.name + + for (i, type) in enumerate(self.memberTypes): + if not type.isComplete(): + self.memberTypes[i] = type.complete(scope) + + self.name = "Or".join(typeName(type) for type in self.memberTypes) + self.flatMemberTypes = list(self.memberTypes) + i = 0 + while i < len(self.flatMemberTypes): + if self.flatMemberTypes[i].nullable(): + if self.hasNullableType: + raise WebIDLError("Can't have more than one nullable types in a union", + [nullableType.location, self.flatMemberTypes[i].location]) + if self.hasDictionaryType: + raise WebIDLError("Can't have a nullable type and a " + "dictionary type in a union", + [dictionaryType.location, + self.flatMemberTypes[i].location]) + self.hasNullableType = True + nullableType = self.flatMemberTypes[i] + self.flatMemberTypes[i] = self.flatMemberTypes[i].inner + continue + if self.flatMemberTypes[i].isDictionary(): + if self.hasNullableType: + raise WebIDLError("Can't have a nullable type and a " + "dictionary type in a union", + [nullableType.location, + self.flatMemberTypes[i].location]) + self.hasDictionaryType = True + dictionaryType = self.flatMemberTypes[i] + elif self.flatMemberTypes[i].isUnion(): + self.flatMemberTypes[i:i + 1] = self.flatMemberTypes[i].memberTypes + continue + i += 1 + + for (i, t) in enumerate(self.flatMemberTypes[:-1]): + for u in self.flatMemberTypes[i + 1:]: + if not t.isDistinguishableFrom(u): + raise WebIDLError("Flat member types of a union should be " + "distinguishable, " + str(t) + " is not " + "distinguishable from " + str(u), + [self.location, t.location, u.location]) + + return self + + def isDistinguishableFrom(self, other): + if self.hasNullableType and other.nullable(): + # Can't tell which type null should become + return False + if other.isUnion(): + otherTypes = other.unroll().memberTypes + else: + otherTypes = [other] + # For every type in otherTypes, check that it's distinguishable from + # every type in our types + for u in otherTypes: + if any(not t.isDistinguishableFrom(u) for t in self.memberTypes): + return False + return True + + def _getDependentObjects(self): + return set(self.memberTypes) + +class IDLArrayType(IDLType): + def __init__(self, location, parameterType): + assert not parameterType.isVoid() + if parameterType.isSequence(): + raise WebIDLError("Array type cannot parameterize over a sequence type", + [location]) + if parameterType.isDictionary(): + raise WebIDLError("Array type cannot parameterize over a dictionary type", + [location]) + + IDLType.__init__(self, location, parameterType.name) + self.inner = parameterType + self.builtin = False + + def __eq__(self, other): + return isinstance(other, IDLArrayType) and self.inner == other.inner + + def __str__(self): + return self.inner.__str__() + "Array" + + def nullable(self): + return False + + def isPrimitive(self): + return False + + def isString(self): + return False + + def isByteString(self): + return False + + def isDOMString(self): + return False + + def isVoid(self): + return False + + def isSequence(self): + assert not self.inner.isSequence() + return False + + def isArray(self): + return True + + def isDictionary(self): + assert not self.inner.isDictionary() + return False + + def isInterface(self): + return False + + def isEnum(self): + return False + + def tag(self): + return IDLType.Tags.array + + def resolveType(self, parentScope): + assert isinstance(parentScope, IDLScope) + self.inner.resolveType(parentScope) + + def isComplete(self): + return self.inner.isComplete() + + def complete(self, scope): + self.inner = self.inner.complete(scope) + self.name = self.inner.name + + if self.inner.isDictionary(): + raise WebIDLError("Array type must not contain " + "dictionary as element type.", + [self.inner.location]) + + assert not self.inner.isSequence() + + return self + + def unroll(self): + return self.inner.unroll() + + def isDistinguishableFrom(self, other): + if other.isUnion(): + # Just forward to the union; it'll deal + return other.isDistinguishableFrom(self) + return (other.isPrimitive() or other.isString() or other.isEnum() or + other.isDate() or other.isNonCallbackInterface()) + + def _getDependentObjects(self): + return self.inner._getDependentObjects() + +class IDLTypedefType(IDLType, IDLObjectWithIdentifier): + def __init__(self, location, innerType, name): + IDLType.__init__(self, location, innerType.name) + + identifier = IDLUnresolvedIdentifier(location, name) + + IDLObjectWithIdentifier.__init__(self, location, None, identifier) + + self.inner = innerType + self.name = name + self.builtin = False + + def __eq__(self, other): + return isinstance(other, IDLTypedefType) and self.inner == other.inner + + def __str__(self): + return self.identifier.name + + def nullable(self): + return self.inner.nullable() + + def isPrimitive(self): + return self.inner.isPrimitive() + + def isBoolean(self): + return self.inner.isBoolean() + + def isNumeric(self): + return self.inner.isNumeric() + + def isString(self): + return self.inner.isString() + + def isByteString(self): + return self.inner.isByteString() + + def isDOMString(self): + return self.inner.isDOMString() + + def isVoid(self): + return self.inner.isVoid() + + def isSequence(self): + return self.inner.isSequence() + + def isArray(self): + return self.inner.isArray() + + def isDictionary(self): + return self.inner.isDictionary() + + def isArrayBuffer(self): + return self.inner.isArrayBuffer() + + def isArrayBufferView(self): + return self.inner.isArrayBufferView() + + def isTypedArray(self): + return self.inner.isTypedArray() + + def isInterface(self): + return self.inner.isInterface() + + def isCallbackInterface(self): + return self.inner.isCallbackInterface() + + def isNonCallbackInterface(self): + return self.inner.isNonCallbackInterface() + + def isComplete(self): + return False + + def complete(self, parentScope): + if not self.inner.isComplete(): + self.inner = self.inner.complete(parentScope) + assert self.inner.isComplete() + return self.inner + + def finish(self, parentScope): + # Maybe the IDLObjectWithIdentifier for the typedef should be + # a separate thing from the type? If that happens, we can + # remove some hackery around avoiding isInterface() in + # Configuration.py. + self.complete(parentScope) + + def validate(self): + pass + + # Do we need a resolveType impl? I don't think it's particularly useful.... + + def tag(self): + return self.inner.tag() + + def unroll(self): + return self.inner.unroll() + + def isDistinguishableFrom(self, other): + return self.inner.isDistinguishableFrom(other) + + def _getDependentObjects(self): + return self.inner._getDependentObjects() + +class IDLWrapperType(IDLType): + def __init__(self, location, inner): + IDLType.__init__(self, location, inner.identifier.name) + self.inner = inner + self._identifier = inner.identifier + self.builtin = False + + def __eq__(self, other): + return isinstance(other, IDLWrapperType) and \ + self._identifier == other._identifier and \ + self.builtin == other.builtin + + def __str__(self): + return str(self.name) + " (Wrapper)" + + def nullable(self): + return False + + def isPrimitive(self): + return False + + def isString(self): + return False + + def isByteString(self): + return False + + def isDOMString(self): + return False + + def isVoid(self): + return False + + def isSequence(self): + return False + + def isArray(self): + return False + + def isDictionary(self): + return isinstance(self.inner, IDLDictionary) + + def isInterface(self): + return isinstance(self.inner, IDLInterface) or \ + isinstance(self.inner, IDLExternalInterface) + + def isCallbackInterface(self): + return self.isInterface() and self.inner.isCallback() + + def isNonCallbackInterface(self): + return self.isInterface() and not self.inner.isCallback() + + def isEnum(self): + return isinstance(self.inner, IDLEnum) + + def isPromise(self): + return isinstance(self.inner, IDLInterface) and \ + self.inner.identifier.name == "Promise" + + def isSerializable(self): + if self.isInterface(): + if self.inner.isExternal(): + return False + return any(m.isMethod() and m.isJsonifier() for m in self.inner.members) + elif self.isEnum(): + return True + elif self.isDictionary(): + return all(m.type.isSerializable() for m in self.inner.members) + else: + raise WebIDLError("IDLWrapperType wraps type %s that we don't know if " + "is serializable" % type(self.inner), [self.location]) + + def resolveType(self, parentScope): + assert isinstance(parentScope, IDLScope) + self.inner.resolve(parentScope) + + def isComplete(self): + return True + + def tag(self): + if self.isInterface(): + return IDLType.Tags.interface + elif self.isEnum(): + return IDLType.Tags.enum + elif self.isDictionary(): + return IDLType.Tags.dictionary + else: + assert False + + def isDistinguishableFrom(self, other): + if other.isUnion(): + # Just forward to the union; it'll deal + return other.isDistinguishableFrom(self) + assert self.isInterface() or self.isEnum() or self.isDictionary() + if self.isEnum(): + return (other.isPrimitive() or other.isInterface() or other.isObject() or + other.isCallback() or other.isDictionary() or + other.isSequence() or other.isArray() or + other.isDate()) + if self.isDictionary() and other.nullable(): + return False + if other.isPrimitive() or other.isString() or other.isEnum() or other.isDate(): + return True + if self.isDictionary(): + return other.isNonCallbackInterface() + + assert self.isInterface() + if other.isInterface(): + if other.isSpiderMonkeyInterface(): + # Just let |other| handle things + return other.isDistinguishableFrom(self) + assert self.isGeckoInterface() and other.isGeckoInterface() + if self.inner.isExternal() or other.unroll().inner.isExternal(): + return self != other + return (len(self.inner.interfacesBasedOnSelf & + other.unroll().inner.interfacesBasedOnSelf) == 0 and + (self.isNonCallbackInterface() or + other.isNonCallbackInterface())) + if (other.isDictionary() or other.isCallback() or + other.isSequence() or other.isArray()): + return self.isNonCallbackInterface() + + # Not much else |other| can be + assert other.isObject() + return False + + def _getDependentObjects(self): + # NB: The codegen for an interface type depends on + # a) That the identifier is in fact an interface (as opposed to + # a dictionary or something else). + # b) The native type of the interface. + # If we depend on the interface object we will also depend on + # anything the interface depends on which is undesirable. We + # considered implementing a dependency just on the interface type + # file, but then every modification to an interface would cause this + # to be regenerated which is still undesirable. We decided not to + # depend on anything, reasoning that: + # 1) Changing the concrete type of the interface requires modifying + # Bindings.conf, which is still a global dependency. + # 2) Changing an interface to a dictionary (or vice versa) with the + # same identifier should be incredibly rare. + return set() + +class IDLBuiltinType(IDLType): + + Types = enum( + # The integer types + 'byte', + 'octet', + 'short', + 'unsigned_short', + 'long', + 'unsigned_long', + 'long_long', + 'unsigned_long_long', + # Additional primitive types + 'boolean', + 'unrestricted_float', + 'float', + 'unrestricted_double', + # IMPORTANT: "double" must be the last primitive type listed + 'double', + # Other types + 'any', + 'domstring', + 'bytestring', + 'object', + 'date', + 'void', + # Funny stuff + 'ArrayBuffer', + 'ArrayBufferView', + 'Int8Array', + 'Uint8Array', + 'Uint8ClampedArray', + 'Int16Array', + 'Uint16Array', + 'Int32Array', + 'Uint32Array', + 'Float32Array', + 'Float64Array' + ) + + TagLookup = { + Types.byte: IDLType.Tags.int8, + Types.octet: IDLType.Tags.uint8, + Types.short: IDLType.Tags.int16, + Types.unsigned_short: IDLType.Tags.uint16, + Types.long: IDLType.Tags.int32, + Types.unsigned_long: IDLType.Tags.uint32, + Types.long_long: IDLType.Tags.int64, + Types.unsigned_long_long: IDLType.Tags.uint64, + Types.boolean: IDLType.Tags.bool, + Types.unrestricted_float: IDLType.Tags.unrestricted_float, + Types.float: IDLType.Tags.float, + Types.unrestricted_double: IDLType.Tags.unrestricted_double, + Types.double: IDLType.Tags.double, + Types.any: IDLType.Tags.any, + Types.domstring: IDLType.Tags.domstring, + Types.bytestring: IDLType.Tags.bytestring, + Types.object: IDLType.Tags.object, + Types.date: IDLType.Tags.date, + Types.void: IDLType.Tags.void, + Types.ArrayBuffer: IDLType.Tags.interface, + Types.ArrayBufferView: IDLType.Tags.interface, + Types.Int8Array: IDLType.Tags.interface, + Types.Uint8Array: IDLType.Tags.interface, + Types.Uint8ClampedArray: IDLType.Tags.interface, + Types.Int16Array: IDLType.Tags.interface, + Types.Uint16Array: IDLType.Tags.interface, + Types.Int32Array: IDLType.Tags.interface, + Types.Uint32Array: IDLType.Tags.interface, + Types.Float32Array: IDLType.Tags.interface, + Types.Float64Array: IDLType.Tags.interface + } + + def __init__(self, location, name, type): + IDLType.__init__(self, location, name) + self.builtin = True + self._typeTag = type + + def isPrimitive(self): + return self._typeTag <= IDLBuiltinType.Types.double + + def isBoolean(self): + return self._typeTag == IDLBuiltinType.Types.boolean + + def isNumeric(self): + return self.isPrimitive() and not self.isBoolean() + + def isString(self): + return self._typeTag == IDLBuiltinType.Types.domstring or \ + self._typeTag == IDLBuiltinType.Types.bytestring + + def isByteString(self): + return self._typeTag == IDLBuiltinType.Types.bytestring + + def isDOMString(self): + return self._typeTag == IDLBuiltinType.Types.domstring + + def isInteger(self): + return self._typeTag <= IDLBuiltinType.Types.unsigned_long_long + + def isArrayBuffer(self): + return self._typeTag == IDLBuiltinType.Types.ArrayBuffer + + def isArrayBufferView(self): + return self._typeTag == IDLBuiltinType.Types.ArrayBufferView + + def isTypedArray(self): + return self._typeTag >= IDLBuiltinType.Types.Int8Array and \ + self._typeTag <= IDLBuiltinType.Types.Float64Array + + def isInterface(self): + # TypedArray things are interface types per the TypedArray spec, + # but we handle them as builtins because SpiderMonkey implements + # all of it internally. + return self.isArrayBuffer() or \ + self.isArrayBufferView() or \ + self.isTypedArray() + + def isNonCallbackInterface(self): + # All the interfaces we can be are non-callback + return self.isInterface() + + def isFloat(self): + return self._typeTag == IDLBuiltinType.Types.float or \ + self._typeTag == IDLBuiltinType.Types.double or \ + self._typeTag == IDLBuiltinType.Types.unrestricted_float or \ + self._typeTag == IDLBuiltinType.Types.unrestricted_double + + def isUnrestricted(self): + assert self.isFloat() + return self._typeTag == IDLBuiltinType.Types.unrestricted_float or \ + self._typeTag == IDLBuiltinType.Types.unrestricted_double + + def isSerializable(self): + return self.isPrimitive() or self.isDOMString() or self.isDate() + + def includesRestrictedFloat(self): + return self.isFloat() and not self.isUnrestricted() + + def tag(self): + return IDLBuiltinType.TagLookup[self._typeTag] + + def isDistinguishableFrom(self, other): + if other.isUnion(): + # Just forward to the union; it'll deal + return other.isDistinguishableFrom(self) + if self.isBoolean(): + return (other.isNumeric() or other.isString() or other.isEnum() or + other.isInterface() or other.isObject() or + other.isCallback() or other.isDictionary() or + other.isSequence() or other.isArray() or + other.isDate()) + if self.isNumeric(): + return (other.isBoolean() or other.isString() or other.isEnum() or + other.isInterface() or other.isObject() or + other.isCallback() or other.isDictionary() or + other.isSequence() or other.isArray() or + other.isDate()) + if self.isString(): + return (other.isPrimitive() or other.isInterface() or + other.isObject() or + other.isCallback() or other.isDictionary() or + other.isSequence() or other.isArray() or + other.isDate()) + if self.isAny(): + # Can't tell "any" apart from anything + return False + if self.isObject(): + return other.isPrimitive() or other.isString() or other.isEnum() + if self.isDate(): + return (other.isPrimitive() or other.isString() or other.isEnum() or + other.isInterface() or other.isCallback() or + other.isDictionary() or other.isSequence() or + other.isArray()) + if self.isVoid(): + return not other.isVoid() + # Not much else we could be! + assert self.isSpiderMonkeyInterface() + # Like interfaces, but we know we're not a callback + return (other.isPrimitive() or other.isString() or other.isEnum() or + other.isCallback() or other.isDictionary() or + other.isSequence() or other.isArray() or other.isDate() or + (other.isInterface() and ( + # ArrayBuffer is distinguishable from everything + # that's not an ArrayBuffer or a callback interface + (self.isArrayBuffer() and not other.isArrayBuffer()) or + # ArrayBufferView is distinguishable from everything + # that's not an ArrayBufferView or typed array. + (self.isArrayBufferView() and not other.isArrayBufferView() and + not other.isTypedArray()) or + # Typed arrays are distinguishable from everything + # except ArrayBufferView and the same type of typed + # array + (self.isTypedArray() and not other.isArrayBufferView() and not + (other.isTypedArray() and other.name == self.name))))) + + def _getDependentObjects(self): + return set() + +BuiltinTypes = { + IDLBuiltinType.Types.byte: + IDLBuiltinType(BuiltinLocation(""), "Byte", + IDLBuiltinType.Types.byte), + IDLBuiltinType.Types.octet: + IDLBuiltinType(BuiltinLocation(""), "Octet", + IDLBuiltinType.Types.octet), + IDLBuiltinType.Types.short: + IDLBuiltinType(BuiltinLocation(""), "Short", + IDLBuiltinType.Types.short), + IDLBuiltinType.Types.unsigned_short: + IDLBuiltinType(BuiltinLocation(""), "UnsignedShort", + IDLBuiltinType.Types.unsigned_short), + IDLBuiltinType.Types.long: + IDLBuiltinType(BuiltinLocation(""), "Long", + IDLBuiltinType.Types.long), + IDLBuiltinType.Types.unsigned_long: + IDLBuiltinType(BuiltinLocation(""), "UnsignedLong", + IDLBuiltinType.Types.unsigned_long), + IDLBuiltinType.Types.long_long: + IDLBuiltinType(BuiltinLocation(""), "LongLong", + IDLBuiltinType.Types.long_long), + IDLBuiltinType.Types.unsigned_long_long: + IDLBuiltinType(BuiltinLocation(""), "UnsignedLongLong", + IDLBuiltinType.Types.unsigned_long_long), + IDLBuiltinType.Types.boolean: + IDLBuiltinType(BuiltinLocation(""), "Boolean", + IDLBuiltinType.Types.boolean), + IDLBuiltinType.Types.float: + IDLBuiltinType(BuiltinLocation(""), "Float", + IDLBuiltinType.Types.float), + IDLBuiltinType.Types.unrestricted_float: + IDLBuiltinType(BuiltinLocation(""), "UnrestrictedFloat", + IDLBuiltinType.Types.unrestricted_float), + IDLBuiltinType.Types.double: + IDLBuiltinType(BuiltinLocation(""), "Double", + IDLBuiltinType.Types.double), + IDLBuiltinType.Types.unrestricted_double: + IDLBuiltinType(BuiltinLocation(""), "UnrestrictedDouble", + IDLBuiltinType.Types.unrestricted_double), + IDLBuiltinType.Types.any: + IDLBuiltinType(BuiltinLocation(""), "Any", + IDLBuiltinType.Types.any), + IDLBuiltinType.Types.domstring: + IDLBuiltinType(BuiltinLocation(""), "String", + IDLBuiltinType.Types.domstring), + IDLBuiltinType.Types.bytestring: + IDLBuiltinType(BuiltinLocation(""), "ByteString", + IDLBuiltinType.Types.bytestring), + IDLBuiltinType.Types.object: + IDLBuiltinType(BuiltinLocation(""), "Object", + IDLBuiltinType.Types.object), + IDLBuiltinType.Types.date: + IDLBuiltinType(BuiltinLocation(""), "Date", + IDLBuiltinType.Types.date), + IDLBuiltinType.Types.void: + IDLBuiltinType(BuiltinLocation(""), "Void", + IDLBuiltinType.Types.void), + IDLBuiltinType.Types.ArrayBuffer: + IDLBuiltinType(BuiltinLocation(""), "ArrayBuffer", + IDLBuiltinType.Types.ArrayBuffer), + IDLBuiltinType.Types.ArrayBufferView: + IDLBuiltinType(BuiltinLocation(""), "ArrayBufferView", + IDLBuiltinType.Types.ArrayBufferView), + IDLBuiltinType.Types.Int8Array: + IDLBuiltinType(BuiltinLocation(""), "Int8Array", + IDLBuiltinType.Types.Int8Array), + IDLBuiltinType.Types.Uint8Array: + IDLBuiltinType(BuiltinLocation(""), "Uint8Array", + IDLBuiltinType.Types.Uint8Array), + IDLBuiltinType.Types.Uint8ClampedArray: + IDLBuiltinType(BuiltinLocation(""), "Uint8ClampedArray", + IDLBuiltinType.Types.Uint8ClampedArray), + IDLBuiltinType.Types.Int16Array: + IDLBuiltinType(BuiltinLocation(""), "Int16Array", + IDLBuiltinType.Types.Int16Array), + IDLBuiltinType.Types.Uint16Array: + IDLBuiltinType(BuiltinLocation(""), "Uint16Array", + IDLBuiltinType.Types.Uint16Array), + IDLBuiltinType.Types.Int32Array: + IDLBuiltinType(BuiltinLocation(""), "Int32Array", + IDLBuiltinType.Types.Int32Array), + IDLBuiltinType.Types.Uint32Array: + IDLBuiltinType(BuiltinLocation(""), "Uint32Array", + IDLBuiltinType.Types.Uint32Array), + IDLBuiltinType.Types.Float32Array: + IDLBuiltinType(BuiltinLocation(""), "Float32Array", + IDLBuiltinType.Types.Float32Array), + IDLBuiltinType.Types.Float64Array: + IDLBuiltinType(BuiltinLocation(""), "Float64Array", + IDLBuiltinType.Types.Float64Array) + } + + +integerTypeSizes = { + IDLBuiltinType.Types.byte: (-128, 127), + IDLBuiltinType.Types.octet: (0, 255), + IDLBuiltinType.Types.short: (-32768, 32767), + IDLBuiltinType.Types.unsigned_short: (0, 65535), + IDLBuiltinType.Types.long: (-2147483648, 2147483647), + IDLBuiltinType.Types.unsigned_long: (0, 4294967295), + IDLBuiltinType.Types.long_long: (-9223372036854775808, + 9223372036854775807), + IDLBuiltinType.Types.unsigned_long_long: (0, 18446744073709551615) + } + +def matchIntegerValueToType(value): + for type, extremes in integerTypeSizes.items(): + (min, max) = extremes + if value <= max and value >= min: + return BuiltinTypes[type] + + return None + +class IDLValue(IDLObject): + def __init__(self, location, type, value): + IDLObject.__init__(self, location) + self.type = type + assert isinstance(type, IDLType) + + self.value = value + + def coerceToType(self, type, location): + if type == self.type: + return self # Nothing to do + + # We first check for unions to ensure that even if the union is nullable + # we end up with the right flat member type, not the union's type. + if type.isUnion(): + # We use the flat member types here, because if we have a nullable + # member type, or a nested union, we want the type the value + # actually coerces to, not the nullable or nested union type. + for subtype in type.unroll().flatMemberTypes: + try: + coercedValue = self.coerceToType(subtype, location) + # Create a new IDLValue to make sure that we have the + # correct float/double type. This is necessary because we + # use the value's type when it is a default value of a + # union, and the union cares about the exact float type. + return IDLValue(self.location, subtype, coercedValue.value) + except: + pass + # If the type allows null, rerun this matching on the inner type, except + # nullable enums. We handle those specially, because we want our + # default string values to stay strings even when assigned to a nullable + # enum. + elif type.nullable() and not type.isEnum(): + innerValue = self.coerceToType(type.inner, location) + return IDLValue(self.location, type, innerValue.value) + + elif self.type.isInteger() and type.isInteger(): + # We're both integer types. See if we fit. + + (min, max) = integerTypeSizes[type._typeTag] + if self.value <= max and self.value >= min: + # Promote + return IDLValue(self.location, type, self.value) + else: + raise WebIDLError("Value %s is out of range for type %s." % + (self.value, type), [location]) + elif self.type.isInteger() and type.isFloat(): + # Convert an integer literal into float + if -2**24 <= self.value <= 2**24: + floatType = BuiltinTypes[IDLBuiltinType.Types.float] + return IDLValue(self.location, floatType, float(self.value)) + else: + raise WebIDLError("Converting value %s to %s will lose precision." % + (self.value, type), [location]) + elif self.type.isString() and type.isEnum(): + # Just keep our string, but make sure it's a valid value for this enum + enum = type.unroll().inner + if self.value not in enum.values(): + raise WebIDLError("'%s' is not a valid default value for enum %s" + % (self.value, enum.identifier.name), + [location, enum.location]) + return self + elif self.type.isFloat() and type.isFloat(): + if (not type.isUnrestricted() and + (self.value == float("inf") or self.value == float("-inf") or + math.isnan(self.value))): + raise WebIDLError("Trying to convert unrestricted value %s to non-unrestricted" + % self.value, [location]); + return self + raise WebIDLError("Cannot coerce type %s to type %s." % + (self.type, type), [location]) + + def _getDependentObjects(self): + return set() + +class IDLNullValue(IDLObject): + def __init__(self, location): + IDLObject.__init__(self, location) + self.type = None + self.value = None + + def coerceToType(self, type, location): + if (not isinstance(type, IDLNullableType) and + not (type.isUnion() and type.hasNullableType) and + not (type.isUnion() and type.hasDictionaryType) and + not type.isDictionary() and + not type.isAny()): + raise WebIDLError("Cannot coerce null value to type %s." % type, + [location]) + + nullValue = IDLNullValue(self.location) + if type.isUnion() and not type.nullable() and type.hasDictionaryType: + # We're actually a default value for the union's dictionary member. + # Use its type. + for t in type.flatMemberTypes: + if t.isDictionary(): + nullValue.type = t + return nullValue + nullValue.type = type + return nullValue + + def _getDependentObjects(self): + return set() + +class IDLUndefinedValue(IDLObject): + def __init__(self, location): + IDLObject.__init__(self, location) + self.type = None + self.value = None + + def coerceToType(self, type, location): + if not type.isAny(): + raise WebIDLError("Cannot coerce undefined value to type %s." % type, + [location]) + + undefinedValue = IDLUndefinedValue(self.location) + undefinedValue.type = type + return undefinedValue + + def _getDependentObjects(self): + return set() + +class IDLInterfaceMember(IDLObjectWithIdentifier): + + Tags = enum( + 'Const', + 'Attr', + 'Method' + ) + + Special = enum( + 'Static', + 'Stringifier' + ) + + def __init__(self, location, identifier, tag): + IDLObjectWithIdentifier.__init__(self, location, None, identifier) + self.tag = tag + self._extendedAttrDict = {} + + def isMethod(self): + return self.tag == IDLInterfaceMember.Tags.Method + + def isAttr(self): + return self.tag == IDLInterfaceMember.Tags.Attr + + def isConst(self): + return self.tag == IDLInterfaceMember.Tags.Const + + def addExtendedAttributes(self, attrs): + for attr in attrs: + self.handleExtendedAttribute(attr) + attrlist = attr.listValue() + self._extendedAttrDict[attr.identifier()] = attrlist if len(attrlist) else True + + def handleExtendedAttribute(self, attr): + pass + + def getExtendedAttribute(self, name): + return self._extendedAttrDict.get(name, None) + +class IDLConst(IDLInterfaceMember): + def __init__(self, location, identifier, type, value): + IDLInterfaceMember.__init__(self, location, identifier, + IDLInterfaceMember.Tags.Const) + + assert isinstance(type, IDLType) + if type.isDictionary(): + raise WebIDLError("A constant cannot be of a dictionary type", + [self.location]) + self.type = type + self.value = value + + if identifier.name == "prototype": + raise WebIDLError("The identifier of a constant must not be 'prototype'", + [location]) + + def __str__(self): + return "'%s' const '%s'" % (self.type, self.identifier) + + def finish(self, scope): + if not self.type.isComplete(): + type = self.type.complete(scope) + if not type.isPrimitive() and not type.isString(): + locations = [self.type.location, type.location] + try: + locations.append(type.inner.location) + except: + pass + raise WebIDLError("Incorrect type for constant", locations) + self.type = type + + # The value might not match the type + coercedValue = self.value.coerceToType(self.type, self.location) + assert coercedValue + + self.value = coercedValue + + def validate(self): + pass + + def _getDependentObjects(self): + return set([self.type, self.value]) + +class IDLAttribute(IDLInterfaceMember): + def __init__(self, location, identifier, type, readonly, inherit=False, + static=False, stringifier=False): + IDLInterfaceMember.__init__(self, location, identifier, + IDLInterfaceMember.Tags.Attr) + + assert isinstance(type, IDLType) + self.type = type + self.readonly = readonly + self.inherit = inherit + self.static = static + self.lenientThis = False + self._unforgeable = False + self.stringifier = stringifier + self.enforceRange = False + self.clamp = False + self.slotIndex = None + + if static and identifier.name == "prototype": + raise WebIDLError("The identifier of a static attribute must not be 'prototype'", + [location]) + + if readonly and inherit: + raise WebIDLError("An attribute cannot be both 'readonly' and 'inherit'", + [self.location]) + + def isStatic(self): + return self.static + + def __str__(self): + return "'%s' attribute '%s'" % (self.type, self.identifier) + + def finish(self, scope): + if not self.type.isComplete(): + t = self.type.complete(scope) + + assert not isinstance(t, IDLUnresolvedType) + assert not isinstance(t, IDLTypedefType) + assert not isinstance(t.name, IDLUnresolvedIdentifier) + self.type = t + + if self.type.isDictionary() and not self.getExtendedAttribute("Cached"): + raise WebIDLError("An attribute cannot be of a dictionary type", + [self.location]) + if self.type.isSequence() and not self.getExtendedAttribute("Cached"): + raise WebIDLError("A non-cached attribute cannot be of a sequence " + "type", [self.location]) + if self.type.isUnion(): + for f in self.type.unroll().flatMemberTypes: + if f.isDictionary(): + raise WebIDLError("An attribute cannot be of a union " + "type if one of its member types (or " + "one of its member types's member " + "types, and so on) is a dictionary " + "type", [self.location, f.location]) + if f.isSequence(): + raise WebIDLError("An attribute cannot be of a union " + "type if one of its member types (or " + "one of its member types's member " + "types, and so on) is a sequence " + "type", [self.location, f.location]) + if not self.type.isInterface() and self.getExtendedAttribute("PutForwards"): + raise WebIDLError("An attribute with [PutForwards] must have an " + "interface type as its type", [self.location]) + + if not self.type.isInterface() and self.getExtendedAttribute("SameObject"): + raise WebIDLError("An attribute with [SameObject] must have an " + "interface type as its type", [self.location]) + + def validate(self): + if ((self.getExtendedAttribute("Cached") or + self.getExtendedAttribute("StoreInSlot")) and + not self.getExtendedAttribute("Constant") and + not self.getExtendedAttribute("Pure")): + raise WebIDLError("Cached attributes and attributes stored in " + "slots must be constant or pure, since the " + "getter won't always be called.", + [self.location]) + if self.getExtendedAttribute("Frozen"): + if not self.type.isSequence() and not self.type.isDictionary(): + raise WebIDLError("[Frozen] is only allowed on sequence-valued " + "and dictionary-valued attributes", + [self.location]) + + def handleExtendedAttribute(self, attr): + identifier = attr.identifier() + if identifier == "SetterThrows" and self.readonly: + raise WebIDLError("Readonly attributes must not be flagged as " + "[SetterThrows]", + [self.location]) + elif (((identifier == "Throws" or identifier == "GetterThrows") and + self.getExtendedAttribute("StoreInSlot")) or + (identifier == "StoreInSlot" and + (self.getExtendedAttribute("Throws") or + self.getExtendedAttribute("GetterThrows")))): + raise WebIDLError("Throwing things can't be [Pure] or [Constant] " + "or [SameObject] or [StoreInSlot]", + [attr.location]) + elif identifier == "LenientThis": + if not attr.noArguments(): + raise WebIDLError("[LenientThis] must take no arguments", + [attr.location]) + if self.isStatic(): + raise WebIDLError("[LenientThis] is only allowed on non-static " + "attributes", [attr.location, self.location]) + if self.getExtendedAttribute("CrossOriginReadable"): + raise WebIDLError("[LenientThis] is not allowed in combination " + "with [CrossOriginReadable]", + [attr.location, self.location]) + if self.getExtendedAttribute("CrossOriginWritable"): + raise WebIDLError("[LenientThis] is not allowed in combination " + "with [CrossOriginWritable]", + [attr.location, self.location]) + self.lenientThis = True + elif identifier == "Unforgeable": + if not self.readonly: + raise WebIDLError("[Unforgeable] is only allowed on readonly " + "attributes", [attr.location, self.location]) + if self.isStatic(): + raise WebIDLError("[Unforgeable] is only allowed on non-static " + "attributes", [attr.location, self.location]) + self._unforgeable = True + elif identifier == "SameObject" and not self.readonly: + raise WebIDLError("[SameObject] only allowed on readonly attributes", + [attr.location, self.location]) + elif identifier == "Constant" and not self.readonly: + raise WebIDLError("[Constant] only allowed on readonly attributes", + [attr.location, self.location]) + elif identifier == "PutForwards": + if not self.readonly: + raise WebIDLError("[PutForwards] is only allowed on readonly " + "attributes", [attr.location, self.location]) + if self.isStatic(): + raise WebIDLError("[PutForwards] is only allowed on non-static " + "attributes", [attr.location, self.location]) + if self.getExtendedAttribute("Replaceable") is not None: + raise WebIDLError("[PutForwards] and [Replaceable] can't both " + "appear on the same attribute", + [attr.location, self.location]) + if not attr.hasValue(): + raise WebIDLError("[PutForwards] takes an identifier", + [attr.location, self.location]) + elif identifier == "Replaceable": + if self.getExtendedAttribute("PutForwards") is not None: + raise WebIDLError("[PutForwards] and [Replaceable] can't both " + "appear on the same attribute", + [attr.location, self.location]) + elif identifier == "LenientFloat": + if self.readonly: + raise WebIDLError("[LenientFloat] used on a readonly attribute", + [attr.location, self.location]) + if not self.type.includesRestrictedFloat(): + raise WebIDLError("[LenientFloat] used on an attribute with a " + "non-restricted-float type", + [attr.location, self.location]) + elif identifier == "EnforceRange": + if self.readonly: + raise WebIDLError("[EnforceRange] used on a readonly attribute", + [attr.location, self.location]) + self.enforceRange = True + elif identifier == "Clamp": + if self.readonly: + raise WebIDLError("[Clamp] used on a readonly attribute", + [attr.location, self.location]) + self.clamp = True + elif identifier == "StoreInSlot": + if self.getExtendedAttribute("Cached"): + raise WebIDLError("[StoreInSlot] and [Cached] must not be " + "specified on the same attribute", + [attr.location, self.location]) + elif identifier == "Cached": + if self.getExtendedAttribute("StoreInSlot"): + raise WebIDLError("[Cached] and [StoreInSlot] must not be " + "specified on the same attribute", + [attr.location, self.location]) + elif (identifier == "CrossOriginReadable" or + identifier == "CrossOriginWritable"): + if not attr.noArguments(): + raise WebIDLError("[%s] must take no arguments" % identifier, + [attr.location]) + if self.isStatic(): + raise WebIDLError("[%s] is only allowed on non-static " + "attributes" % identifier, + [attr.location, self.location]) + if self.getExtendedAttribute("LenientThis"): + raise WebIDLError("[LenientThis] is not allowed in combination " + "with [%s]" % identifier, + [attr.location, self.location]) + elif (identifier == "Pref" or + identifier == "SetterThrows" or + identifier == "Pure" or + identifier == "Throws" or + identifier == "GetterThrows" or + identifier == "ChromeOnly" or + identifier == "SameObject" or + identifier == "Constant" or + identifier == "Func" or + identifier == "Frozen" or + identifier == "AvailableIn" or + identifier == "Const" or + identifier == "Value" or + identifier == "NewObject"): + # Known attributes that we don't need to do anything with here + pass + else: + raise WebIDLError("Unknown extended attribute %s on attribute" % identifier, + [attr.location]) + IDLInterfaceMember.handleExtendedAttribute(self, attr) + + def resolve(self, parentScope): + assert isinstance(parentScope, IDLScope) + self.type.resolveType(parentScope) + IDLObjectWithIdentifier.resolve(self, parentScope) + + def addExtendedAttributes(self, attrs): + attrs = self.checkForStringHandlingExtendedAttributes(attrs) + IDLInterfaceMember.addExtendedAttributes(self, attrs) + + def hasLenientThis(self): + return self.lenientThis + + def isUnforgeable(self): + return self._unforgeable + + def _getDependentObjects(self): + return set([self.type]) + +class IDLArgument(IDLObjectWithIdentifier): + def __init__(self, location, identifier, type, optional=False, defaultValue=None, variadic=False, dictionaryMember=False): + IDLObjectWithIdentifier.__init__(self, location, None, identifier) + + assert isinstance(type, IDLType) + self.type = type + + self.optional = optional + self.defaultValue = defaultValue + self.variadic = variadic + self.dictionaryMember = dictionaryMember + self._isComplete = False + self.enforceRange = False + self.clamp = False + self._allowTreatNonCallableAsNull = False + + self._extraAttributes = {} + + assert not variadic or optional + + def getExtendedAttribute(self, name): + return self._extraAttributes.get(name) + + def addExtendedAttributes(self, attrs): + attrs = self.checkForStringHandlingExtendedAttributes( + attrs, + isDictionaryMember=self.dictionaryMember, + isOptional=self.optional) + for attribute in attrs: + identifier = attribute.identifier() + if identifier == "Clamp": + if not attribute.noArguments(): + raise WebIDLError("[Clamp] must take no arguments", + [attribute.location]) + if self.enforceRange: + raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", + [self.location]); + self.clamp = True + elif identifier == "EnforceRange": + if not attribute.noArguments(): + raise WebIDLError("[EnforceRange] must take no arguments", + [attribute.location]) + if self.clamp: + raise WebIDLError("[EnforceRange] and [Clamp] are mutually exclusive", + [self.location]); + self.enforceRange = True + elif identifier == "TreatNonCallableAsNull": + self._allowTreatNonCallableAsNull = True + elif identifier in ['Ref', 'Const']: + # ok in emscripten + self._extraAttributes[identifier] = True + else: + raise WebIDLError("Unhandled extended attribute on an argument", + [attribute.location]) + + def isComplete(self): + return self._isComplete + + def complete(self, scope): + if self._isComplete: + return + + self._isComplete = True + + if not self.type.isComplete(): + type = self.type.complete(scope) + assert not isinstance(type, IDLUnresolvedType) + assert not isinstance(type, IDLTypedefType) + assert not isinstance(type.name, IDLUnresolvedIdentifier) + self.type = type + + if ((self.type.isDictionary() or + self.type.isUnion() and self.type.unroll().hasDictionaryType) and + self.optional and not self.defaultValue): + # Default optional dictionaries to null, for simplicity, + # so the codegen doesn't have to special-case this. + self.defaultValue = IDLNullValue(self.location) + elif self.type.isAny(): + assert (self.defaultValue is None or + isinstance(self.defaultValue, IDLNullValue)) + # optional 'any' values always have a default value + if self.optional and not self.defaultValue and not self.variadic: + # Set the default value to undefined, for simplicity, so the + # codegen doesn't have to special-case this. + self.defaultValue = IDLUndefinedValue(self.location) + + # Now do the coercing thing; this needs to happen after the + # above creation of a default value. + if self.defaultValue: + self.defaultValue = self.defaultValue.coerceToType(self.type, + self.location) + assert self.defaultValue + + def allowTreatNonCallableAsNull(self): + return self._allowTreatNonCallableAsNull + + def _getDependentObjects(self): + deps = set([self.type]) + if self.defaultValue: + deps.add(self.defaultValue) + return deps + +class IDLCallbackType(IDLType, IDLObjectWithScope): + def __init__(self, location, parentScope, identifier, returnType, arguments): + assert isinstance(returnType, IDLType) + + IDLType.__init__(self, location, identifier.name) + + self._returnType = returnType + # Clone the list + self._arguments = list(arguments) + + IDLObjectWithScope.__init__(self, location, parentScope, identifier) + + for (returnType, arguments) in self.signatures(): + for argument in arguments: + argument.resolve(self) + + self._treatNonCallableAsNull = False + self._treatNonObjectAsNull = False + + def isCallback(self): + return True + + def signatures(self): + return [(self._returnType, self._arguments)] + + def tag(self): + return IDLType.Tags.callback + + def finish(self, scope): + if not self._returnType.isComplete(): + type = self._returnType.complete(scope) + + assert not isinstance(type, IDLUnresolvedType) + assert not isinstance(type, IDLTypedefType) + assert not isinstance(type.name, IDLUnresolvedIdentifier) + self._returnType = type + + for argument in self._arguments: + if argument.type.isComplete(): + continue + + type = argument.type.complete(scope) + + assert not isinstance(type, IDLUnresolvedType) + assert not isinstance(type, IDLTypedefType) + assert not isinstance(type.name, IDLUnresolvedIdentifier) + argument.type = type + + def validate(self): + pass + + def isDistinguishableFrom(self, other): + if other.isUnion(): + # Just forward to the union; it'll deal + return other.isDistinguishableFrom(self) + return (other.isPrimitive() or other.isString() or other.isEnum() or + other.isNonCallbackInterface() or other.isDate()) + + def addExtendedAttributes(self, attrs): + unhandledAttrs = [] + for attr in attrs: + if attr.identifier() == "TreatNonCallableAsNull": + self._treatNonCallableAsNull = True + elif attr.identifier() == "TreatNonObjectAsNull": + self._treatNonObjectAsNull = True + else: + unhandledAttrs.append(attr) + if self._treatNonCallableAsNull and self._treatNonObjectAsNull: + raise WebIDLError("Cannot specify both [TreatNonCallableAsNull] " + "and [TreatNonObjectAsNull]", [self.location]) + if len(unhandledAttrs) != 0: + IDLType.addExtendedAttributes(self, unhandledAttrs) + + def _getDependentObjects(self): + return set([self._returnType] + self._arguments) + +class IDLMethodOverload: + """ + A class that represents a single overload of a WebIDL method. This is not + quite the same as an element of the "effective overload set" in the spec, + because separate IDLMethodOverloads are not created based on arguments being + optional. Rather, when multiple methods have the same name, there is an + IDLMethodOverload for each one, all hanging off an IDLMethod representing + the full set of overloads. + """ + def __init__(self, returnType, arguments, location): + self.returnType = returnType + # Clone the list of arguments, just in case + self.arguments = list(arguments) + self.location = location + + def _getDependentObjects(self): + deps = set(self.arguments) + deps.add(self.returnType) + return deps + +class IDLMethod(IDLInterfaceMember, IDLScope): + + Special = enum( + 'Getter', + 'Setter', + 'Creator', + 'Deleter', + 'LegacyCaller', + base=IDLInterfaceMember.Special + ) + + TypeSuffixModifier = enum( + 'None', + 'QMark', + 'Brackets' + ) + + NamedOrIndexed = enum( + 'Neither', + 'Named', + 'Indexed' + ) + + def __init__(self, location, identifier, returnType, arguments, + static=False, getter=False, setter=False, creator=False, + deleter=False, specialType=NamedOrIndexed.Neither, + legacycaller=False, stringifier=False, jsonifier=False): + # REVIEW: specialType is NamedOrIndexed -- wow, this is messed up. + IDLInterfaceMember.__init__(self, location, identifier, + IDLInterfaceMember.Tags.Method) + + self._hasOverloads = False + + assert isinstance(returnType, IDLType) + + # self._overloads is a list of IDLMethodOverloads + self._overloads = [IDLMethodOverload(returnType, arguments, location)] + + assert isinstance(static, bool) + self._static = static + assert isinstance(getter, bool) + self._getter = getter + assert isinstance(setter, bool) + self._setter = setter + assert isinstance(creator, bool) + self._creator = creator + assert isinstance(deleter, bool) + self._deleter = deleter + assert isinstance(legacycaller, bool) + self._legacycaller = legacycaller + assert isinstance(stringifier, bool) + self._stringifier = stringifier + assert isinstance(jsonifier, bool) + self._jsonifier = jsonifier + self._specialType = specialType + + if static and identifier.name == "prototype": + raise WebIDLError("The identifier of a static operation must not be 'prototype'", + [location]) + + self.assertSignatureConstraints() + + def __str__(self): + return "Method '%s'" % self.identifier + + def assertSignatureConstraints(self): + if self._getter or self._deleter: + assert len(self._overloads) == 1 + overload = self._overloads[0] + arguments = overload.arguments + assert len(arguments) == 1 + assert arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \ + arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] + assert not arguments[0].optional and not arguments[0].variadic + assert not self._getter or not overload.returnType.isVoid() + + if self._setter or self._creator: + assert len(self._overloads) == 1 + arguments = self._overloads[0].arguments + assert len(arguments) == 2 + assert arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.domstring] or \ + arguments[0].type == BuiltinTypes[IDLBuiltinType.Types.unsigned_long] + assert not arguments[0].optional and not arguments[0].variadic + assert not arguments[1].optional and not arguments[1].variadic + + if self._stringifier: + assert len(self._overloads) == 1 + overload = self._overloads[0] + assert len(overload.arguments) == 0 + assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.domstring] + + if self._jsonifier: + assert len(self._overloads) == 1 + overload = self._overloads[0] + assert len(overload.arguments) == 0 + assert overload.returnType == BuiltinTypes[IDLBuiltinType.Types.object] + + def isStatic(self): + return self._static + + def isGetter(self): + return self._getter + + def isSetter(self): + return self._setter + + def isCreator(self): + return self._creator + + def isDeleter(self): + return self._deleter + + def isNamed(self): + assert self._specialType == IDLMethod.NamedOrIndexed.Named or \ + self._specialType == IDLMethod.NamedOrIndexed.Indexed + return self._specialType == IDLMethod.NamedOrIndexed.Named + + def isIndexed(self): + assert self._specialType == IDLMethod.NamedOrIndexed.Named or \ + self._specialType == IDLMethod.NamedOrIndexed.Indexed + return self._specialType == IDLMethod.NamedOrIndexed.Indexed + + def isLegacycaller(self): + return self._legacycaller + + def isStringifier(self): + return self._stringifier + + def isJsonifier(self): + return self._jsonifier + + def hasOverloads(self): + return self._hasOverloads + + def isIdentifierLess(self): + return self.identifier.name[:2] == "__" and self.identifier.name != "__noSuchMethod__" + + def resolve(self, parentScope): + assert isinstance(parentScope, IDLScope) + IDLObjectWithIdentifier.resolve(self, parentScope) + IDLScope.__init__(self, self.location, parentScope, self.identifier) + for (returnType, arguments) in self.signatures(): + for argument in arguments: + argument.resolve(self) + + def addOverload(self, method): + assert len(method._overloads) == 1 + + if self._extendedAttrDict != method ._extendedAttrDict: + raise WebIDLError("Extended attributes differ on different " + "overloads of %s" % method.identifier, + [self.location, method.location]) + + self._overloads.extend(method._overloads) + + self._hasOverloads = True + + if self.isStatic() != method.isStatic(): + raise WebIDLError("Overloaded identifier %s appears with different values of the 'static' attribute" % method.identifier, + [method.location]) + + if self.isLegacycaller() != method.isLegacycaller(): + raise WebIDLError("Overloaded identifier %s appears with different values of the 'legacycaller' attribute" % method.identifier, + [method.location]) + + # Can't overload special things! + assert not self.isGetter() + assert not method.isGetter() + assert not self.isSetter() + assert not method.isSetter() + assert not self.isCreator() + assert not method.isCreator() + assert not self.isDeleter() + assert not method.isDeleter() + assert not self.isStringifier() + assert not method.isStringifier() + assert not self.isJsonifier() + assert not method.isJsonifier() + + return self + + def signatures(self): + return [(overload.returnType, overload.arguments) for overload in + self._overloads] + + def finish(self, scope): + overloadWithPromiseReturnType = None + overloadWithoutPromiseReturnType = None + for overload in self._overloads: + variadicArgument = None + + arguments = overload.arguments + for (idx, argument) in enumerate(arguments): + if not argument.isComplete(): + argument.complete(scope) + assert argument.type.isComplete() + + if (argument.type.isDictionary() or + (argument.type.isUnion() and + argument.type.unroll().hasDictionaryType)): + # Dictionaries and unions containing dictionaries at the + # end of the list or followed by optional arguments must be + # optional. + if (not argument.optional and + all(arg.optional for arg in arguments[idx+1:])): + raise WebIDLError("Dictionary argument or union " + "argument containing a dictionary " + "not followed by a required argument " + "must be optional", + [argument.location]) + + # An argument cannot be a Nullable Dictionary + if argument.type.nullable(): + raise WebIDLError("An argument cannot be a nullable " + "dictionary or nullable union " + "containing a dictionary", + [argument.location]) + + # Only the last argument can be variadic + if variadicArgument: + raise WebIDLError("Variadic argument is not last argument", + [variadicArgument.location]) + if argument.variadic: + variadicArgument = argument + + returnType = overload.returnType + if not returnType.isComplete(): + returnType = returnType.complete(scope) + assert not isinstance(returnType, IDLUnresolvedType) + assert not isinstance(returnType, IDLTypedefType) + assert not isinstance(returnType.name, IDLUnresolvedIdentifier) + overload.returnType = returnType + + if returnType.isPromise(): + overloadWithPromiseReturnType = overload + else: + overloadWithoutPromiseReturnType = overload + + # Make sure either all our overloads return Promises or none do + if overloadWithPromiseReturnType and overloadWithoutPromiseReturnType: + raise WebIDLError("We have overloads with both Promise and " + "non-Promise return types", + [overloadWithPromiseReturnType.location, + overloadWithoutPromiseReturnType.location]) + + if overloadWithPromiseReturnType and self._legacycaller: + raise WebIDLError("May not have a Promise return type for a " + "legacycaller.", + [overloadWithPromiseReturnType.location]) + + # Now compute various information that will be used by the + # WebIDL overload resolution algorithm. + self.maxArgCount = max(len(s[1]) for s in self.signatures()) + self.allowedArgCounts = [ i for i in range(self.maxArgCount+1) + if len(self.signaturesForArgCount(i)) != 0 ] + + def validate(self): + # Make sure our overloads are properly distinguishable and don't have + # different argument types before the distinguishing args. + for argCount in self.allowedArgCounts: + possibleOverloads = self.overloadsForArgCount(argCount) + if len(possibleOverloads) == 1: + continue + distinguishingIndex = self.distinguishingIndexForArgCount(argCount) + for idx in range(distinguishingIndex): + firstSigType = possibleOverloads[0].arguments[idx].type + for overload in possibleOverloads[1:]: + if overload.arguments[idx].type != firstSigType: + raise WebIDLError( + "Signatures for method '%s' with %d arguments have " + "different types of arguments at index %d, which " + "is before distinguishing index %d" % + (self.identifier.name, argCount, idx, + distinguishingIndex), + [self.location, overload.location]) + + def overloadsForArgCount(self, argc): + return [overload for overload in self._overloads if + len(overload.arguments) == argc or + (len(overload.arguments) > argc and + all(arg.optional for arg in overload.arguments[argc:])) or + (len(overload.arguments) < argc and + len(overload.arguments) > 0 and + overload.arguments[-1].variadic)] + + def signaturesForArgCount(self, argc): + return [(overload.returnType, overload.arguments) for overload + in self.overloadsForArgCount(argc)] + + def locationsForArgCount(self, argc): + return [overload.location for overload in self.overloadsForArgCount(argc)] + + def distinguishingIndexForArgCount(self, argc): + def isValidDistinguishingIndex(idx, signatures): + for (firstSigIndex, (firstRetval, firstArgs)) in enumerate(signatures[:-1]): + for (secondRetval, secondArgs) in signatures[firstSigIndex+1:]: + if idx < len(firstArgs): + firstType = firstArgs[idx].type + else: + assert(firstArgs[-1].variadic) + firstType = firstArgs[-1].type + if idx < len(secondArgs): + secondType = secondArgs[idx].type + else: + assert(secondArgs[-1].variadic) + secondType = secondArgs[-1].type + if not firstType.isDistinguishableFrom(secondType): + return False + return True + signatures = self.signaturesForArgCount(argc) + for idx in range(argc): + if isValidDistinguishingIndex(idx, signatures): + return idx + # No valid distinguishing index. Time to throw + locations = self.locationsForArgCount(argc) + raise WebIDLError("Signatures with %d arguments for method '%s' are not " + "distinguishable" % (argc, self.identifier.name), + locations) + + def handleExtendedAttribute(self, attr): + identifier = attr.identifier() + if identifier == "GetterThrows": + raise WebIDLError("Methods must not be flagged as " + "[GetterThrows]", + [attr.location, self.location]) + elif identifier == "SetterThrows": + raise WebIDLError("Methods must not be flagged as " + "[SetterThrows]", + [attr.location, self.location]) + elif identifier == "Unforgeable": + raise WebIDLError("Methods must not be flagged as " + "[Unforgeable]", + [attr.location, self.location]) + elif identifier == "SameObject": + raise WebIDLError("Methods must not be flagged as [SameObject]", + [attr.location, self.location]); + elif identifier == "Constant": + raise WebIDLError("Methods must not be flagged as [Constant]", + [attr.location, self.location]); + elif identifier == "PutForwards": + raise WebIDLError("Only attributes support [PutForwards]", + [attr.location, self.location]) + elif identifier == "LenientFloat": + # This is called before we've done overload resolution + assert len(self.signatures()) == 1 + sig = self.signatures()[0] + if not sig[0].isVoid(): + raise WebIDLError("[LenientFloat] used on a non-void method", + [attr.location, self.location]) + if not any(arg.type.includesRestrictedFloat() for arg in sig[1]): + raise WebIDLError("[LenientFloat] used on an operation with no " + "restricted float type arguments", + [attr.location, self.location]) + elif (identifier == "Throws" or + identifier == "NewObject" or + identifier == "ChromeOnly" or + identifier == "Pref" or + identifier == "Func" or + identifier == "AvailableIn" or + identifier == "Pure" or + identifier == "CrossOriginCallable" or + identifier == "Ref" or + identifier == "Value" or + identifier == "Operator" or + identifier == "WebGLHandlesContextLoss"): + # Known attributes that we don't need to do anything with here + pass + else: + raise WebIDLError("Unknown extended attribute %s on method" % identifier, + [attr.location]) + IDLInterfaceMember.handleExtendedAttribute(self, attr) + + def returnsPromise(self): + return self._overloads[0].returnType.isPromise() + + def _getDependentObjects(self): + deps = set() + for overload in self._overloads: + deps.union(overload._getDependentObjects()) + return deps + +class IDLImplementsStatement(IDLObject): + def __init__(self, location, implementor, implementee): + IDLObject.__init__(self, location) + self.implementor = implementor; + self.implementee = implementee + + def finish(self, scope): + assert(isinstance(self.implementor, IDLIdentifierPlaceholder)) + assert(isinstance(self.implementee, IDLIdentifierPlaceholder)) + implementor = self.implementor.finish(scope) + implementee = self.implementee.finish(scope) + # NOTE: we depend on not setting self.implementor and + # self.implementee here to keep track of the original + # locations. + if not isinstance(implementor, IDLInterface): + raise WebIDLError("Left-hand side of 'implements' is not an " + "interface", + [self.implementor.location]) + if implementor.isCallback(): + raise WebIDLError("Left-hand side of 'implements' is a callback " + "interface", + [self.implementor.location]) + if not isinstance(implementee, IDLInterface): + raise WebIDLError("Right-hand side of 'implements' is not an " + "interface", + [self.implementee.location]) + if implementee.isCallback(): + raise WebIDLError("Right-hand side of 'implements' is a callback " + "interface", + [self.implementee.location]) + implementor.addImplementedInterface(implementee) + + def validate(self): + pass + + def addExtendedAttributes(self, attrs): + assert len(attrs) == 0 + +class IDLExtendedAttribute(IDLObject): + """ + A class to represent IDL extended attributes so we can give them locations + """ + def __init__(self, location, tuple): + IDLObject.__init__(self, location) + self._tuple = tuple + + def identifier(self): + return self._tuple[0] + + def noArguments(self): + return len(self._tuple) == 1 + + def hasValue(self): + return len(self._tuple) >= 2 and isinstance(self._tuple[1], str) + + def value(self): + assert(self.hasValue()) + return self._tuple[1] + + def hasArgs(self): + return (len(self._tuple) == 2 and isinstance(self._tuple[1], list) or + len(self._tuple) == 3) + + def args(self): + assert(self.hasArgs()) + # Our args are our last element + return self._tuple[-1] + + def listValue(self): + """ + Backdoor for storing random data in _extendedAttrDict + """ + return list(self._tuple)[1:] + +# Parser + +class Tokenizer(object): + tokens = [ + "INTEGER", + "FLOATLITERAL", + "IDENTIFIER", + "STRING", + "WHITESPACE", + "OTHER" + ] + + def t_FLOATLITERAL(self, t): + r'(-?(([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)([Ee][+-]?[0-9]+)?|[0-9]+[Ee][+-]?[0-9]+|Infinity))|NaN' + t.value = float(t.value) + return t + + def t_INTEGER(self, t): + r'-?(0([0-7]+|[Xx][0-9A-Fa-f]+)?|[1-9][0-9]*)' + try: + # Can't use int(), because that doesn't handle octal properly. + t.value = parseInt(t.value) + except: + raise WebIDLError("Invalid integer literal", + [Location(lexer=self.lexer, + lineno=self.lexer.lineno, + lexpos=self.lexer.lexpos, + filename=self._filename)]) + return t + + def t_IDENTIFIER(self, t): + r'[A-Z_a-z][0-9A-Z_a-z]*' + t.type = self.keywords.get(t.value, 'IDENTIFIER') + return t + + def t_STRING(self, t): + r'"[^"]*"' + t.value = t.value[1:-1] + return t + + def t_WHITESPACE(self, t): + r'[\t\n\r ]+|[\t\n\r ]*((//[^\n]*|/\*.*?\*/)[\t\n\r ]*)+' + pass + + def t_ELLIPSIS(self, t): + r'\.\.\.' + t.type = self.keywords.get(t.value) + return t + + def t_OTHER(self, t): + r'[^\t\n\r 0-9A-Z_a-z]' + t.type = self.keywords.get(t.value, 'OTHER') + return t + + keywords = { + "module": "MODULE", + "interface": "INTERFACE", + "partial": "PARTIAL", + "dictionary": "DICTIONARY", + "exception": "EXCEPTION", + "enum": "ENUM", + "callback": "CALLBACK", + "typedef": "TYPEDEF", + "implements": "IMPLEMENTS", + "const": "CONST", + "null": "NULL", + "true": "TRUE", + "false": "FALSE", + "serializer": "SERIALIZER", + "stringifier": "STRINGIFIER", + "jsonifier": "JSONIFIER", + "unrestricted": "UNRESTRICTED", + "attribute": "ATTRIBUTE", + "readonly": "READONLY", + "inherit": "INHERIT", + "static": "STATIC", + "getter": "GETTER", + "setter": "SETTER", + "creator": "CREATOR", + "deleter": "DELETER", + "legacycaller": "LEGACYCALLER", + "optional": "OPTIONAL", + "...": "ELLIPSIS", + "::": "SCOPE", + "Date": "DATE", + "DOMString": "DOMSTRING", + "ByteString": "BYTESTRING", + "any": "ANY", + "boolean": "BOOLEAN", + "byte": "BYTE", + "double": "DOUBLE", + "float": "FLOAT", + "long": "LONG", + "object": "OBJECT", + "octet": "OCTET", + "optional": "OPTIONAL", + "sequence": "SEQUENCE", + "short": "SHORT", + "unsigned": "UNSIGNED", + "void": "VOID", + ":": "COLON", + ";": "SEMICOLON", + "{": "LBRACE", + "}": "RBRACE", + "(": "LPAREN", + ")": "RPAREN", + "[": "LBRACKET", + "]": "RBRACKET", + "?": "QUESTIONMARK", + ",": "COMMA", + "=": "EQUALS", + "<": "LT", + ">": "GT", + "ArrayBuffer": "ARRAYBUFFER", + "or": "OR" + } + + tokens.extend(keywords.values()) + + def t_error(self, t): + raise WebIDLError("Unrecognized Input", + [Location(lexer=self.lexer, + lineno=self.lexer.lineno, + lexpos=self.lexer.lexpos, + filename = self.filename)]) + + def __init__(self, outputdir, lexer=None): + if lexer: + self.lexer = lexer + else: + self.lexer = lex.lex(object=self, + outputdir=outputdir, + lextab='webidllex', + reflags=re.DOTALL) + +class Parser(Tokenizer): + def getLocation(self, p, i): + return Location(self.lexer, p.lineno(i), p.lexpos(i), self._filename) + + def globalScope(self): + return self._globalScope + + # The p_Foo functions here must match the WebIDL spec's grammar. + # It's acceptable to split things at '|' boundaries. + def p_Definitions(self, p): + """ + Definitions : ExtendedAttributeList Definition Definitions + """ + if p[2]: + p[0] = [p[2]] + p[2].addExtendedAttributes(p[1]) + else: + assert not p[1] + p[0] = [] + + p[0].extend(p[3]) + + def p_DefinitionsEmpty(self, p): + """ + Definitions : + """ + p[0] = [] + + def p_Definition(self, p): + """ + Definition : CallbackOrInterface + | PartialInterface + | Dictionary + | Exception + | Enum + | Typedef + | ImplementsStatement + """ + p[0] = p[1] + assert p[1] # We might not have implemented something ... + + def p_CallbackOrInterfaceCallback(self, p): + """ + CallbackOrInterface : CALLBACK CallbackRestOrInterface + """ + if p[2].isInterface(): + assert isinstance(p[2], IDLInterface) + p[2].setCallback(True) + + p[0] = p[2] + + def p_CallbackOrInterfaceInterface(self, p): + """ + CallbackOrInterface : Interface + """ + p[0] = p[1] + + def p_CallbackRestOrInterface(self, p): + """ + CallbackRestOrInterface : CallbackRest + | Interface + """ + assert p[1] + p[0] = p[1] + + def p_Interface(self, p): + """ + Interface : INTERFACE IDENTIFIER Inheritance LBRACE InterfaceMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[5] + parent = p[3] + + try: + if self.globalScope()._lookupIdentifier(identifier): + p[0] = self.globalScope()._lookupIdentifier(identifier) + if not isinstance(p[0], IDLInterface): + raise WebIDLError("Partial interface has the same name as " + "non-interface object", + [location, p[0].location]) + p[0].setNonPartial(location, parent, members) + return + except Exception, ex: + if isinstance(ex, WebIDLError): + raise ex + pass + + p[0] = IDLInterface(location, self.globalScope(), identifier, parent, + members, isPartial=False) + + def p_InterfaceForwardDecl(self, p): + """ + Interface : INTERFACE IDENTIFIER SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + + try: + if self.globalScope()._lookupIdentifier(identifier): + p[0] = self.globalScope()._lookupIdentifier(identifier) + if not isinstance(p[0], IDLExternalInterface): + raise WebIDLError("Name collision between external " + "interface declaration for identifier " + "%s and %s" % (identifier.name, p[0]), + [location, p[0].location]) + return + except Exception, ex: + if isinstance(ex, WebIDLError): + raise ex + pass + + p[0] = IDLExternalInterface(location, self.globalScope(), identifier) + + def p_PartialInterface(self, p): + """ + PartialInterface : PARTIAL INTERFACE IDENTIFIER LBRACE InterfaceMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 2) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) + members = p[5] + + try: + if self.globalScope()._lookupIdentifier(identifier): + p[0] = self.globalScope()._lookupIdentifier(identifier) + if not isinstance(p[0], IDLInterface): + raise WebIDLError("Partial interface has the same name as " + "non-interface object", + [location, p[0].location]) + # Just throw our members into the existing IDLInterface. If we + # have extended attributes, those will get added to it + # automatically. + p[0].members.extend(members) + return + except Exception, ex: + if isinstance(ex, WebIDLError): + raise ex + pass + + p[0] = IDLInterface(location, self.globalScope(), identifier, None, + members, isPartial=True) + pass + + def p_Inheritance(self, p): + """ + Inheritance : COLON ScopedName + """ + p[0] = IDLIdentifierPlaceholder(self.getLocation(p, 2), p[2]) + + def p_InheritanceEmpty(self, p): + """ + Inheritance : + """ + pass + + def p_InterfaceMembers(self, p): + """ + InterfaceMembers : ExtendedAttributeList InterfaceMember InterfaceMembers + """ + p[0] = [p[2]] if p[2] else [] + + assert not p[1] or p[2] + p[2].addExtendedAttributes(p[1]) + + p[0].extend(p[3]) + + def p_InterfaceMembersEmpty(self, p): + """ + InterfaceMembers : + """ + p[0] = [] + + def p_InterfaceMember(self, p): + """ + InterfaceMember : Const + | AttributeOrOperation + """ + p[0] = p[1] + + def p_Dictionary(self, p): + """ + Dictionary : DICTIONARY IDENTIFIER Inheritance LBRACE DictionaryMembers RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + members = p[5] + p[0] = IDLDictionary(location, self.globalScope(), identifier, p[3], members) + + def p_DictionaryMembers(self, p): + """ + DictionaryMembers : ExtendedAttributeList DictionaryMember DictionaryMembers + | + """ + if len(p) == 1: + # We're at the end of the list + p[0] = [] + return + # Add our extended attributes + p[2].addExtendedAttributes(p[1]) + p[0] = [p[2]] + p[0].extend(p[3]) + + def p_DictionaryMember(self, p): + """ + DictionaryMember : Type IDENTIFIER DefaultValue SEMICOLON + """ + # These quack a lot like optional arguments, so just treat them that way. + t = p[1] + assert isinstance(t, IDLType) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + defaultValue = p[3] + + p[0] = IDLArgument(self.getLocation(p, 2), identifier, t, optional=True, + defaultValue=defaultValue, variadic=False, + dictionaryMember=True) + + def p_DefaultValue(self, p): + """ + DefaultValue : EQUALS ConstValue + | + """ + if len(p) > 1: + p[0] = p[2] + else: + p[0] = None + + def p_Exception(self, p): + """ + Exception : EXCEPTION IDENTIFIER Inheritance LBRACE ExceptionMembers RBRACE SEMICOLON + """ + pass + + def p_Enum(self, p): + """ + Enum : ENUM IDENTIFIER LBRACE EnumValueList RBRACE SEMICOLON + """ + location = self.getLocation(p, 1) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 2), p[2]) + + values = p[4] + assert values + p[0] = IDLEnum(location, self.globalScope(), identifier, values) + + def p_EnumValueList(self, p): + """ + EnumValueList : STRING EnumValueListComma + """ + p[0] = [p[1]] + p[0].extend(p[2]) + + def p_EnumValueListComma(self, p): + """ + EnumValueListComma : COMMA EnumValueListString + """ + p[0] = p[2] + + def p_EnumValueListCommaEmpty(self, p): + """ + EnumValueListComma : + """ + p[0] = [] + + def p_EnumValueListString(self, p): + """ + EnumValueListString : STRING EnumValueListComma + """ + p[0] = [p[1]] + p[0].extend(p[2]) + + def p_EnumValueListStringEmpty(self, p): + """ + EnumValueListString : + """ + p[0] = [] + + def p_CallbackRest(self, p): + """ + CallbackRest : IDENTIFIER EQUALS ReturnType LPAREN ArgumentList RPAREN SEMICOLON + """ + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) + p[0] = IDLCallbackType(self.getLocation(p, 1), self.globalScope(), + identifier, p[3], p[5]) + + def p_ExceptionMembers(self, p): + """ + ExceptionMembers : ExtendedAttributeList ExceptionMember ExceptionMembers + | + """ + pass + + def p_Typedef(self, p): + """ + Typedef : TYPEDEF Type IDENTIFIER SEMICOLON + """ + typedef = IDLTypedefType(self.getLocation(p, 1), p[2], p[3]) + typedef.resolve(self.globalScope()) + p[0] = typedef + + def p_ImplementsStatement(self, p): + """ + ImplementsStatement : ScopedName IMPLEMENTS ScopedName SEMICOLON + """ + assert(p[2] == "implements") + implementor = IDLIdentifierPlaceholder(self.getLocation(p, 1), p[1]) + implementee = IDLIdentifierPlaceholder(self.getLocation(p, 3), p[3]) + p[0] = IDLImplementsStatement(self.getLocation(p, 1), implementor, + implementee) + + def p_Const(self, p): + """ + Const : CONST ConstType IDENTIFIER EQUALS ConstValue SEMICOLON + """ + location = self.getLocation(p, 1) + type = p[2] + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 3), p[3]) + value = p[5] + p[0] = IDLConst(location, identifier, type, value) + + def p_ConstValueBoolean(self, p): + """ + ConstValue : BooleanLiteral + """ + location = self.getLocation(p, 1) + booleanType = BuiltinTypes[IDLBuiltinType.Types.boolean] + p[0] = IDLValue(location, booleanType, p[1]) + + def p_ConstValueInteger(self, p): + """ + ConstValue : INTEGER + """ + location = self.getLocation(p, 1) + + # We don't know ahead of time what type the integer literal is. + # Determine the smallest type it could possibly fit in and use that. + integerType = matchIntegerValueToType(p[1]) + if integerType == None: + raise WebIDLError("Integer literal out of range", [location]) + + p[0] = IDLValue(location, integerType, p[1]) + + def p_ConstValueFloat(self, p): + """ + ConstValue : FLOATLITERAL + """ + location = self.getLocation(p, 1) + p[0] = IDLValue(location, BuiltinTypes[IDLBuiltinType.Types.unrestricted_float], p[1]) + + def p_ConstValueString(self, p): + """ + ConstValue : STRING + """ + location = self.getLocation(p, 1) + stringType = BuiltinTypes[IDLBuiltinType.Types.domstring] + p[0] = IDLValue(location, stringType, p[1]) + + def p_ConstValueNull(self, p): + """ + ConstValue : NULL + """ + p[0] = IDLNullValue(self.getLocation(p, 1)) + + def p_BooleanLiteralTrue(self, p): + """ + BooleanLiteral : TRUE + """ + p[0] = True + + def p_BooleanLiteralFalse(self, p): + """ + BooleanLiteral : FALSE + """ + p[0] = False + + def p_AttributeOrOperation(self, p): + """ + AttributeOrOperation : Attribute + | Operation + """ + p[0] = p[1] + + def p_AttributeWithQualifier(self, p): + """ + Attribute : Qualifier AttributeRest + """ + static = IDLInterfaceMember.Special.Static in p[1] + stringifier = IDLInterfaceMember.Special.Stringifier in p[1] + (location, identifier, type, readonly) = p[2] + p[0] = IDLAttribute(location, identifier, type, readonly, static=static, + stringifier=stringifier) + + def p_Attribute(self, p): + """ + Attribute : Inherit AttributeRest + """ + (location, identifier, type, readonly) = p[2] + p[0] = IDLAttribute(location, identifier, type, readonly, inherit=p[1]) + + def p_AttributeRest(self, p): + """ + AttributeRest : ReadOnly ATTRIBUTE Type IDENTIFIER SEMICOLON + """ + location = self.getLocation(p, 2) + readonly = p[1] + t = p[3] + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 4), p[4]) + p[0] = (location, identifier, t, readonly) + + def p_ReadOnly(self, p): + """ + ReadOnly : READONLY + """ + p[0] = True + + def p_ReadOnlyEmpty(self, p): + """ + ReadOnly : + """ + p[0] = False + + def p_Inherit(self, p): + """ + Inherit : INHERIT + """ + p[0] = True + + def p_InheritEmpty(self, p): + """ + Inherit : + """ + p[0] = False + + def p_Operation(self, p): + """ + Operation : Qualifiers OperationRest + """ + qualifiers = p[1] + + # Disallow duplicates in the qualifier set + if not len(set(qualifiers)) == len(qualifiers): + raise WebIDLError("Duplicate qualifiers are not allowed", + [self.getLocation(p, 1)]) + + static = IDLInterfaceMember.Special.Static in p[1] + # If static is there that's all that's allowed. This is disallowed + # by the parser, so we can assert here. + assert not static or len(qualifiers) == 1 + + stringifier = IDLInterfaceMember.Special.Stringifier in p[1] + # If stringifier is there that's all that's allowed. This is disallowed + # by the parser, so we can assert here. + assert not stringifier or len(qualifiers) == 1 + + getter = True if IDLMethod.Special.Getter in p[1] else False + setter = True if IDLMethod.Special.Setter in p[1] else False + creator = True if IDLMethod.Special.Creator in p[1] else False + deleter = True if IDLMethod.Special.Deleter in p[1] else False + legacycaller = True if IDLMethod.Special.LegacyCaller in p[1] else False + + if getter or deleter: + if setter or creator: + raise WebIDLError("getter and deleter are incompatible with setter and creator", + [self.getLocation(p, 1)]) + + (returnType, identifier, arguments) = p[2] + + assert isinstance(returnType, IDLType) + + specialType = IDLMethod.NamedOrIndexed.Neither + + if getter or deleter: + if len(arguments) != 1: + raise WebIDLError("%s has wrong number of arguments" % + ("getter" if getter else "deleter"), + [self.getLocation(p, 2)]) + argType = arguments[0].type + if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: + specialType = IDLMethod.NamedOrIndexed.Named + elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: + specialType = IDLMethod.NamedOrIndexed.Indexed + else: + raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % + ("getter" if getter else "deleter"), + [arguments[0].location]) + if arguments[0].optional or arguments[0].variadic: + raise WebIDLError("%s cannot have %s argument" % + ("getter" if getter else "deleter", + "optional" if arguments[0].optional else "variadic"), + [arguments[0].location]) + if getter: + if returnType.isVoid(): + raise WebIDLError("getter cannot have void return type", + [self.getLocation(p, 2)]) + if setter or creator: + if len(arguments) != 2: + raise WebIDLError("%s has wrong number of arguments" % + ("setter" if setter else "creator"), + [self.getLocation(p, 2)]) + argType = arguments[0].type + if argType == BuiltinTypes[IDLBuiltinType.Types.domstring]: + specialType = IDLMethod.NamedOrIndexed.Named + elif argType == BuiltinTypes[IDLBuiltinType.Types.unsigned_long]: + specialType = IDLMethod.NamedOrIndexed.Indexed + else: + raise WebIDLError("%s has wrong argument type (must be DOMString or UnsignedLong)" % + ("setter" if setter else "creator"), + [arguments[0].location]) + if arguments[0].optional or arguments[0].variadic: + raise WebIDLError("%s cannot have %s argument" % + ("setter" if setter else "creator", + "optional" if arguments[0].optional else "variadic"), + [arguments[0].location]) + if arguments[1].optional or arguments[1].variadic: + raise WebIDLError("%s cannot have %s argument" % + ("setter" if setter else "creator", + "optional" if arguments[1].optional else "variadic"), + [arguments[1].location]) + + if stringifier: + if len(arguments) != 0: + raise WebIDLError("stringifier has wrong number of arguments", + [self.getLocation(p, 2)]) + if not returnType.isDOMString(): + raise WebIDLError("stringifier must have DOMString return type", + [self.getLocation(p, 2)]) + + # identifier might be None. This is only permitted for special methods. + if not identifier: + if not getter and not setter and not creator and \ + not deleter and not legacycaller and not stringifier: + raise WebIDLError("Identifier required for non-special methods", + [self.getLocation(p, 2)]) + + location = BuiltinLocation("") + identifier = IDLUnresolvedIdentifier(location, "__%s%s%s%s%s%s%s" % + ("named" if specialType == IDLMethod.NamedOrIndexed.Named else \ + "indexed" if specialType == IDLMethod.NamedOrIndexed.Indexed else "", + "getter" if getter else "", + "setter" if setter else "", + "deleter" if deleter else "", + "creator" if creator else "", + "legacycaller" if legacycaller else "", + "stringifier" if stringifier else ""), allowDoubleUnderscore=True) + + method = IDLMethod(self.getLocation(p, 2), identifier, returnType, arguments, + static=static, getter=getter, setter=setter, creator=creator, + deleter=deleter, specialType=specialType, + legacycaller=legacycaller, stringifier=stringifier) + p[0] = method + + def p_Stringifier(self, p): + """ + Operation : STRINGIFIER SEMICOLON + """ + identifier = IDLUnresolvedIdentifier(BuiltinLocation(""), + "__stringifier", + allowDoubleUnderscore=True) + method = IDLMethod(self.getLocation(p, 1), + identifier, + returnType=BuiltinTypes[IDLBuiltinType.Types.domstring], + arguments=[], + stringifier=True) + p[0] = method + + def p_Jsonifier(self, p): + """ + Operation : JSONIFIER SEMICOLON + """ + identifier = IDLUnresolvedIdentifier(BuiltinLocation(""), + "__jsonifier", allowDoubleUnderscore=True) + method = IDLMethod(self.getLocation(p, 1), + identifier, + returnType=BuiltinTypes[IDLBuiltinType.Types.object], + arguments=[], + jsonifier=True) + p[0] = method + + def p_QualifierStatic(self, p): + """ + Qualifier : STATIC + """ + p[0] = [IDLInterfaceMember.Special.Static] + + def p_QualifierStringifier(self, p): + """ + Qualifier : STRINGIFIER + """ + p[0] = [IDLInterfaceMember.Special.Stringifier] + + def p_Qualifiers(self, p): + """ + Qualifiers : Qualifier + | Specials + """ + p[0] = p[1] + + def p_Specials(self, p): + """ + Specials : Special Specials + """ + p[0] = [p[1]] + p[0].extend(p[2]) + + def p_SpecialsEmpty(self, p): + """ + Specials : + """ + p[0] = [] + + def p_SpecialGetter(self, p): + """ + Special : GETTER + """ + p[0] = IDLMethod.Special.Getter + + def p_SpecialSetter(self, p): + """ + Special : SETTER + """ + p[0] = IDLMethod.Special.Setter + + def p_SpecialCreator(self, p): + """ + Special : CREATOR + """ + p[0] = IDLMethod.Special.Creator + + def p_SpecialDeleter(self, p): + """ + Special : DELETER + """ + p[0] = IDLMethod.Special.Deleter + + def p_SpecialLegacyCaller(self, p): + """ + Special : LEGACYCALLER + """ + p[0] = IDLMethod.Special.LegacyCaller + + def p_OperationRest(self, p): + """ + OperationRest : ReturnType OptionalIdentifier LPAREN ArgumentList RPAREN SEMICOLON + """ + p[0] = (p[1], p[2], p[4]) + + def p_OptionalIdentifier(self, p): + """ + OptionalIdentifier : IDENTIFIER + """ + p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) + + def p_OptionalIdentifierEmpty(self, p): + """ + OptionalIdentifier : + """ + pass + + def p_ArgumentList(self, p): + """ + ArgumentList : Argument Arguments + """ + p[0] = [p[1]] if p[1] else [] + p[0].extend(p[2]) + + def p_ArgumentListEmpty(self, p): + """ + ArgumentList : + """ + p[0] = [] + + def p_Arguments(self, p): + """ + Arguments : COMMA Argument Arguments + """ + p[0] = [p[2]] if p[2] else [] + p[0].extend(p[3]) + + def p_ArgumentsEmpty(self, p): + """ + Arguments : + """ + p[0] = [] + + def p_Argument(self, p): + """ + Argument : ExtendedAttributeList Optional Type Ellipsis ArgumentName DefaultValue + """ + t = p[3] + assert isinstance(t, IDLType) + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 5), p[5]) + + optional = p[2] + variadic = p[4] + defaultValue = p[6] + + if not optional and defaultValue: + raise WebIDLError("Mandatory arguments can't have a default value.", + [self.getLocation(p, 6)]) + + # We can't test t.isAny() here and give it a default value as needed, + # since at this point t is not a fully resolved type yet (e.g. it might + # be a typedef). We'll handle the 'any' case in IDLArgument.complete. + + if variadic: + if optional: + raise WebIDLError("Variadic arguments should not be marked optional.", + [self.getLocation(p, 2)]) + optional = variadic + + p[0] = IDLArgument(self.getLocation(p, 5), identifier, t, optional, defaultValue, variadic) + p[0].addExtendedAttributes(p[1]) + + def p_ArgumentName(self, p): + """ + ArgumentName : IDENTIFIER + | ATTRIBUTE + | CALLBACK + | CONST + | CREATOR + | DELETER + | DICTIONARY + | ENUM + | EXCEPTION + | GETTER + | IMPLEMENTS + | INHERIT + | INTERFACE + | LEGACYCALLER + | PARTIAL + | SERIALIZER + | SETTER + | STATIC + | STRINGIFIER + | JSONIFIER + | TYPEDEF + | UNRESTRICTED + """ + p[0] = p[1] + + def p_Optional(self, p): + """ + Optional : OPTIONAL + """ + p[0] = True + + def p_OptionalEmpty(self, p): + """ + Optional : + """ + p[0] = False + + def p_Ellipsis(self, p): + """ + Ellipsis : ELLIPSIS + """ + p[0] = True + + def p_EllipsisEmpty(self, p): + """ + Ellipsis : + """ + p[0] = False + + def p_ExceptionMember(self, p): + """ + ExceptionMember : Const + | ExceptionField + """ + pass + + def p_ExceptionField(self, p): + """ + ExceptionField : Type IDENTIFIER SEMICOLON + """ + pass + + def p_ExtendedAttributeList(self, p): + """ + ExtendedAttributeList : LBRACKET ExtendedAttribute ExtendedAttributes RBRACKET + """ + p[0] = [p[2]] + if p[3]: + p[0].extend(p[3]) + + def p_ExtendedAttributeListEmpty(self, p): + """ + ExtendedAttributeList : + """ + p[0] = [] + + def p_ExtendedAttribute(self, p): + """ + ExtendedAttribute : ExtendedAttributeNoArgs + | ExtendedAttributeArgList + | ExtendedAttributeIdent + | ExtendedAttributeNamedArgList + """ + p[0] = IDLExtendedAttribute(self.getLocation(p, 1), p[1]) + + def p_ExtendedAttributeEmpty(self, p): + """ + ExtendedAttribute : + """ + pass + + def p_ExtendedAttributes(self, p): + """ + ExtendedAttributes : COMMA ExtendedAttribute ExtendedAttributes + """ + p[0] = [p[2]] if p[2] else [] + p[0].extend(p[3]) + + def p_ExtendedAttributesEmpty(self, p): + """ + ExtendedAttributes : + """ + p[0] = [] + + def p_Other(self, p): + """ + Other : INTEGER + | FLOATLITERAL + | IDENTIFIER + | STRING + | OTHER + | ELLIPSIS + | COLON + | SCOPE + | SEMICOLON + | LT + | EQUALS + | GT + | QUESTIONMARK + | DATE + | DOMSTRING + | BYTESTRING + | ANY + | ATTRIBUTE + | BOOLEAN + | BYTE + | LEGACYCALLER + | CONST + | CREATOR + | DELETER + | DOUBLE + | EXCEPTION + | FALSE + | FLOAT + | GETTER + | IMPLEMENTS + | INHERIT + | INTERFACE + | LONG + | MODULE + | NULL + | OBJECT + | OCTET + | OPTIONAL + | SEQUENCE + | SETTER + | SHORT + | STATIC + | STRINGIFIER + | JSONIFIER + | TRUE + | TYPEDEF + | UNSIGNED + | VOID + """ + pass + + def p_OtherOrComma(self, p): + """ + OtherOrComma : Other + | COMMA + """ + pass + + def p_TypeSingleType(self, p): + """ + Type : SingleType + """ + p[0] = p[1] + + def p_TypeUnionType(self, p): + """ + Type : UnionType TypeSuffix + """ + p[0] = self.handleModifiers(p[1], p[2]) + + def p_SingleTypeNonAnyType(self, p): + """ + SingleType : NonAnyType + """ + p[0] = p[1] + + def p_SingleTypeAnyType(self, p): + """ + SingleType : ANY TypeSuffixStartingWithArray + """ + p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.any], p[2]) + + def p_UnionType(self, p): + """ + UnionType : LPAREN UnionMemberType OR UnionMemberType UnionMemberTypes RPAREN + """ + types = [p[2], p[4]] + types.extend(p[5]) + p[0] = IDLUnionType(self.getLocation(p, 1), types) + + def p_UnionMemberTypeNonAnyType(self, p): + """ + UnionMemberType : NonAnyType + """ + p[0] = p[1] + + def p_UnionMemberTypeArrayOfAny(self, p): + """ + UnionMemberTypeArrayOfAny : ANY LBRACKET RBRACKET + """ + p[0] = IDLArrayType(self.getLocation(p, 2), + BuiltinTypes[IDLBuiltinType.Types.any]) + + def p_UnionMemberType(self, p): + """ + UnionMemberType : UnionType TypeSuffix + | UnionMemberTypeArrayOfAny TypeSuffix + """ + p[0] = self.handleModifiers(p[1], p[2]) + + def p_UnionMemberTypes(self, p): + """ + UnionMemberTypes : OR UnionMemberType UnionMemberTypes + """ + p[0] = [p[2]] + p[0].extend(p[3]) + + def p_UnionMemberTypesEmpty(self, p): + """ + UnionMemberTypes : + """ + p[0] = [] + + def p_NonAnyType(self, p): + """ + NonAnyType : PrimitiveOrStringType TypeSuffix + | ARRAYBUFFER TypeSuffix + | OBJECT TypeSuffix + """ + if p[1] == "object": + type = BuiltinTypes[IDLBuiltinType.Types.object] + elif p[1] == "ArrayBuffer": + type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer] + else: + type = BuiltinTypes[p[1]] + + p[0] = self.handleModifiers(type, p[2]) + + def p_NonAnyTypeSequenceType(self, p): + """ + NonAnyType : SEQUENCE LT Type GT Null + """ + innerType = p[3] + type = IDLSequenceType(self.getLocation(p, 1), innerType) + if p[5]: + type = IDLNullableType(self.getLocation(p, 5), type) + p[0] = type + + def p_NonAnyTypeScopedName(self, p): + """ + NonAnyType : ScopedName TypeSuffix + """ + assert isinstance(p[1], IDLUnresolvedIdentifier) + + type = None + + try: + if self.globalScope()._lookupIdentifier(p[1]): + obj = self.globalScope()._lookupIdentifier(p[1]) + if obj.isType(): + type = obj + else: + type = IDLWrapperType(self.getLocation(p, 1), p[1]) + p[0] = self.handleModifiers(type, p[2]) + return + except: + pass + + type = IDLUnresolvedType(self.getLocation(p, 1), p[1]) + p[0] = self.handleModifiers(type, p[2]) + + def p_NonAnyTypeDate(self, p): + """ + NonAnyType : DATE TypeSuffix + """ + p[0] = self.handleModifiers(BuiltinTypes[IDLBuiltinType.Types.date], + p[2]) + + def p_ConstType(self, p): + """ + ConstType : PrimitiveOrStringType Null + """ + type = BuiltinTypes[p[1]] + if p[2]: + type = IDLNullableType(self.getLocation(p, 1), type) + p[0] = type + + def p_ConstTypeIdentifier(self, p): + """ + ConstType : IDENTIFIER Null + """ + identifier = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) + + type = IDLUnresolvedType(self.getLocation(p, 1), identifier) + if p[2]: + type = IDLNullableType(self.getLocation(p, 1), type) + p[0] = type + + def p_PrimitiveOrStringTypeUint(self, p): + """ + PrimitiveOrStringType : UnsignedIntegerType + """ + p[0] = p[1] + + def p_PrimitiveOrStringTypeBoolean(self, p): + """ + PrimitiveOrStringType : BOOLEAN + """ + p[0] = IDLBuiltinType.Types.boolean + + def p_PrimitiveOrStringTypeByte(self, p): + """ + PrimitiveOrStringType : BYTE + """ + p[0] = IDLBuiltinType.Types.byte + + def p_PrimitiveOrStringTypeOctet(self, p): + """ + PrimitiveOrStringType : OCTET + """ + p[0] = IDLBuiltinType.Types.octet + + def p_PrimitiveOrStringTypeFloat(self, p): + """ + PrimitiveOrStringType : FLOAT + """ + p[0] = IDLBuiltinType.Types.float + + def p_PrimitiveOrStringTypeUnrestictedFloat(self, p): + """ + PrimitiveOrStringType : UNRESTRICTED FLOAT + """ + p[0] = IDLBuiltinType.Types.unrestricted_float + + def p_PrimitiveOrStringTypeDouble(self, p): + """ + PrimitiveOrStringType : DOUBLE + """ + p[0] = IDLBuiltinType.Types.double + + def p_PrimitiveOrStringTypeUnrestictedDouble(self, p): + """ + PrimitiveOrStringType : UNRESTRICTED DOUBLE + """ + p[0] = IDLBuiltinType.Types.unrestricted_double + + def p_PrimitiveOrStringTypeDOMString(self, p): + """ + PrimitiveOrStringType : DOMSTRING + """ + p[0] = IDLBuiltinType.Types.domstring + + def p_PrimitiveOrStringTypeBytestring(self, p): + """ + PrimitiveOrStringType : BYTESTRING + """ + p[0] = IDLBuiltinType.Types.bytestring + + def p_UnsignedIntegerTypeUnsigned(self, p): + """ + UnsignedIntegerType : UNSIGNED IntegerType + """ + p[0] = p[2] + 1 # Adding one to a given signed integer type + # gets you the unsigned type. + + def p_UnsignedIntegerType(self, p): + """ + UnsignedIntegerType : IntegerType + """ + p[0] = p[1] + + def p_IntegerTypeShort(self, p): + """ + IntegerType : SHORT + """ + p[0] = IDLBuiltinType.Types.short + + def p_IntegerTypeLong(self, p): + """ + IntegerType : LONG OptionalLong + """ + if p[2]: + p[0] = IDLBuiltinType.Types.long_long + else: + p[0] = IDLBuiltinType.Types.long + + def p_OptionalLong(self, p): + """ + OptionalLong : LONG + """ + p[0] = True + + def p_OptionalLongEmpty(self, p): + """ + OptionalLong : + """ + p[0] = False + + def p_TypeSuffixBrackets(self, p): + """ + TypeSuffix : LBRACKET RBRACKET TypeSuffix + """ + p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] + p[0].extend(p[3]) + + def p_TypeSuffixQMark(self, p): + """ + TypeSuffix : QUESTIONMARK TypeSuffixStartingWithArray + """ + p[0] = [(IDLMethod.TypeSuffixModifier.QMark, self.getLocation(p, 1))] + p[0].extend(p[2]) + + def p_TypeSuffixEmpty(self, p): + """ + TypeSuffix : + """ + p[0] = [] + + def p_TypeSuffixStartingWithArray(self, p): + """ + TypeSuffixStartingWithArray : LBRACKET RBRACKET TypeSuffix + """ + p[0] = [(IDLMethod.TypeSuffixModifier.Brackets, self.getLocation(p, 1))] + p[0].extend(p[3]) + + def p_TypeSuffixStartingWithArrayEmpty(self, p): + """ + TypeSuffixStartingWithArray : + """ + p[0] = [] + + def p_Null(self, p): + """ + Null : QUESTIONMARK + | + """ + if len(p) > 1: + p[0] = True + else: + p[0] = False + + def p_ReturnTypeType(self, p): + """ + ReturnType : Type + """ + p[0] = p[1] + + def p_ReturnTypeVoid(self, p): + """ + ReturnType : VOID + """ + p[0] = BuiltinTypes[IDLBuiltinType.Types.void] + + def p_ScopedName(self, p): + """ + ScopedName : AbsoluteScopedName + | RelativeScopedName + """ + p[0] = p[1] + + def p_AbsoluteScopedName(self, p): + """ + AbsoluteScopedName : SCOPE IDENTIFIER ScopedNameParts + """ + assert False + pass + + def p_RelativeScopedName(self, p): + """ + RelativeScopedName : IDENTIFIER ScopedNameParts + """ + assert not p[2] # Not implemented! + + p[0] = IDLUnresolvedIdentifier(self.getLocation(p, 1), p[1]) + + def p_ScopedNameParts(self, p): + """ + ScopedNameParts : SCOPE IDENTIFIER ScopedNameParts + """ + assert False + pass + + def p_ScopedNamePartsEmpty(self, p): + """ + ScopedNameParts : + """ + p[0] = None + + def p_ExtendedAttributeNoArgs(self, p): + """ + ExtendedAttributeNoArgs : IDENTIFIER + """ + p[0] = (p[1],) + + def p_ExtendedAttributeArgList(self, p): + """ + ExtendedAttributeArgList : IDENTIFIER LPAREN ArgumentList RPAREN + """ + p[0] = (p[1], p[3]) + + def p_ExtendedAttributeIdent(self, p): + """ + ExtendedAttributeIdent : IDENTIFIER EQUALS STRING + | IDENTIFIER EQUALS IDENTIFIER + """ + p[0] = (p[1], p[3]) + + def p_ExtendedAttributeNamedArgList(self, p): + """ + ExtendedAttributeNamedArgList : IDENTIFIER EQUALS IDENTIFIER LPAREN ArgumentList RPAREN + """ + p[0] = (p[1], p[3], p[5]) + + def p_error(self, p): + if not p: + raise WebIDLError("Syntax Error at end of file. Possibly due to missing semicolon(;), braces(}) or both", + [self._filename]) + else: + raise WebIDLError("invalid syntax", [Location(self.lexer, p.lineno, p.lexpos, self._filename)]) + + def __init__(self, outputdir='', lexer=None): + Tokenizer.__init__(self, outputdir, lexer) + self.parser = yacc.yacc(module=self, + outputdir=outputdir, + tabmodule='webidlyacc', + errorlog=yacc.NullLogger(), + picklefile='WebIDLGrammar.pkl') + self._globalScope = IDLScope(BuiltinLocation(""), None, None) + self._installBuiltins(self._globalScope) + self._productions = [] + + self._filename = "" + self.lexer.input(Parser._builtins) + self._filename = None + + self.parser.parse(lexer=self.lexer,tracking=True) + + def _installBuiltins(self, scope): + assert isinstance(scope, IDLScope) + + # xrange omits the last value. + for x in xrange(IDLBuiltinType.Types.ArrayBuffer, IDLBuiltinType.Types.Float64Array + 1): + builtin = BuiltinTypes[x] + name = builtin.name + + typedef = IDLTypedefType(BuiltinLocation(""), builtin, name) + typedef.resolve(scope) + + @ staticmethod + def handleModifiers(type, modifiers): + for (modifier, modifierLocation) in modifiers: + assert modifier == IDLMethod.TypeSuffixModifier.QMark or \ + modifier == IDLMethod.TypeSuffixModifier.Brackets + + if modifier == IDLMethod.TypeSuffixModifier.QMark: + type = IDLNullableType(modifierLocation, type) + elif modifier == IDLMethod.TypeSuffixModifier.Brackets: + type = IDLArrayType(modifierLocation, type) + + return type + + def parse(self, t, filename=None): + self.lexer.input(t) + + #for tok in iter(self.lexer.token, None): + # print tok + + self._filename = filename + self._productions.extend(self.parser.parse(lexer=self.lexer,tracking=True)) + self._filename = None + + def finish(self): + # First, finish all the IDLImplementsStatements. In particular, we + # have to make sure we do those before we do the IDLInterfaces. + # XXX khuey hates this bit and wants to nuke it from orbit. + implementsStatements = [ p for p in self._productions if + isinstance(p, IDLImplementsStatement)] + otherStatements = [ p for p in self._productions if + not isinstance(p, IDLImplementsStatement)] + for production in implementsStatements: + production.finish(self.globalScope()) + for production in otherStatements: + production.finish(self.globalScope()) + + # Do any post-finish validation we need to do + for production in self._productions: + production.validate() + + # De-duplicate self._productions, without modifying its order. + seen = set() + result = [] + for p in self._productions: + if p not in seen: + seen.add(p) + result.append(p) + return result + + def reset(self): + return Parser(lexer=self.lexer) + + # Builtin IDL defined by WebIDL + _builtins = """ + typedef unsigned long long DOMTimeStamp; + """ + +def main(): + # Parse arguments. + from optparse import OptionParser + usageString = "usage: %prog [options] files" + o = OptionParser(usage=usageString) + o.add_option("--cachedir", dest='cachedir', default=None, + help="Directory in which to cache lex/parse tables.") + o.add_option("--verbose-errors", action='store_true', default=False, + help="When an error happens, display the Python traceback.") + (options, args) = o.parse_args() + + if len(args) < 1: + o.error(usageString) + + fileList = args + baseDir = os.getcwd() + + # Parse the WebIDL. + parser = Parser(options.cachedir) + try: + for filename in fileList: + fullPath = os.path.normpath(os.path.join(baseDir, filename)) + f = open(fullPath, 'rb') + lines = f.readlines() + f.close() + print fullPath + parser.parse(''.join(lines), fullPath) + parser.finish() + except WebIDLError, e: + if options.verbose_errors: + traceback.print_exc() + else: + print e + +if __name__ == '__main__': + main() + diff --git a/third_party/__init__.py b/third_party/__init__.py new file mode 100644 index 0000000000000..8fa2136f68851 --- /dev/null +++ b/third_party/__init__.py @@ -0,0 +1,2 @@ +# + diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py new file mode 100644 index 0000000000000..1fecdf9e4b2fc --- /dev/null +++ b/tools/webidl_binder.py @@ -0,0 +1,426 @@ + +import os, sys + +import shared + +sys.path.append(shared.path_from_root('third_party')) +sys.path.append(shared.path_from_root('third_party', 'ply')) + +import WebIDL + +class Dummy: + def __init__(self, init): + for k, v in init.iteritems(): + self.__dict__[k] = v + + def getExtendedAttribute(self, name): + return None + +input_file = sys.argv[1] +output_base = sys.argv[2] + +shared.try_delete(output_base + '.cpp') +shared.try_delete(output_base + '.js') + +p = WebIDL.Parser() +p.parse(open(input_file).read()) +data = p.finish() + +interfaces = {} +implements = {} + +for thing in data: + if isinstance(thing, WebIDL.IDLInterface): + interfaces[thing.identifier.name] = thing + elif isinstance(thing, WebIDL.IDLImplementsStatement): + implements.setdefault(thing.implementor.identifier.name, []).append(thing.implementee.identifier.name) + +#print interfaces +#print implements + +pre_c = [] +mid_c = [] +mid_js = [] + +pre_c += [r''' +#include +'''] + +mid_c += [r''' +extern "C" { +'''] + +def emit_constructor(name): + global mid_js + mid_js += [r'''%s.prototype = %s; +%s.prototype.constructor = %s; +%s.prototype.__class__ = %s; +%s.__cache__ = {}; +Module['%s'] = %s; +''' % (name, 'Object.create(%s.prototype)' % (implements[name][0] if implements.get(name) else 'WrapperObject'), name, name, name, name, name, name, name)] + + +mid_js += [''' +// Bindings utilities + +function WrapperObject() { +} +'''] + +emit_constructor('WrapperObject') + +mid_js += [''' +function getCache(__class__) { + return (__class__ || WrapperObject).__cache__; +} +Module['getCache'] = getCache; + +function wrapPointer(ptr, __class__) { + var cache = getCache(__class__); + var ret = cache[ptr]; + if (ret) return ret; + ret = Object.create((__class__ || WrapperObject).prototype); + ret.ptr = ptr; + return cache[ptr] = ret; +} +Module['wrapPointer'] = wrapPointer; + +function castObject(obj, __class__) { + return wrapPointer(obj.ptr, __class__); +} +Module['castObject'] = castObject; + +Module['NULL'] = wrapPointer(0); + +function destroy(obj) { + if (!obj['__destroy__']) throw 'Error: Cannot destroy object. (Did you create it yourself?)'; + obj['__destroy__'](); + // Remove from cache, so the object can be GC'd and refs added onto it released + delete getCache(obj.__class__)[obj.ptr]; +} +Module['destroy'] = destroy; + +function compare(obj1, obj2) { + return obj1.ptr === obj2.ptr; +} +Module['compare'] = compare; + +function getPointer(obj) { + return obj.ptr; +} +Module['getPointer'] = getPointer; + +function getClass(obj) { + return obj.__class__; +} +Module['getClass'] = getClass; + +// Converts a value into a C-style string. +function ensureString(value) { + if (typeof value == 'string') return allocate(intArrayFromString(value), 'i8', ALLOC_STACK); + return value; +} + +'''] + +C_FLOATS = ['float', 'double'] + +def type_to_c(t, non_pointing=False): + #print 'to c ', t + t = t.replace(' (Wrapper)', '') + if t == 'Long': + return 'int' + elif t == 'Short': + return 'short' + elif t == 'Void': + return 'void' + elif t == 'String': + return 'char*' + elif t == 'Float': + return 'float' + elif t == 'Double': + return 'double' + elif t == 'Boolean': + return 'bool' + elif t in interfaces: + return (interfaces[t].getExtendedAttribute('Prefix') or [''])[0] + t + ('' if non_pointing else '*') + else: + return t + +def take_addr_if_nonpointer(m): + if m.getExtendedAttribute('Ref') or m.getExtendedAttribute('Value'): + return '&' + return '' + +def deref_if_nonpointer(m): + if m.getExtendedAttribute('Ref') or m.getExtendedAttribute('Value'): + return '*' + return '' + +def type_to_cdec(raw): + name = ret = type_to_c(raw.type.name, non_pointing=True) + if raw.getExtendedAttribute('Const'): ret = 'const ' + ret + if name not in interfaces: return ret + if raw.getExtendedAttribute('Ref'): + return ret + '&' + if raw.getExtendedAttribute('Value'): + return ret + return ret + '*' + +def render_function(class_name, func_name, sigs, return_type, non_pointer, copy, operator, constructor, func_scope, call_content=None, const=False): + global mid_c, mid_js, js_impl_methods + + #print 'renderfunc', class_name, func_name, sigs, return_type, constructor + + bindings_name = class_name + '_' + func_name + min_args = min(sigs.keys()) + max_args = max(sigs.keys()) + + c_names = {} + + # JS + + cache = ('getCache(%s)[this.ptr] = this;' % class_name) if constructor else '' + call_prefix = '' if not constructor else 'this.ptr = ' + call_postfix = '' + if return_type != 'Void' and not constructor: call_prefix = 'return ' + if not constructor: + if return_type in interfaces: + call_prefix += 'wrapPointer(' + call_postfix += ', ' + return_type + ')' + + args = ['arg%d' % i for i in range(max_args)] + if not constructor: + body = ' var self = this.ptr;\n' + pre_arg = ['self'] + else: + body = '' + pre_arg = [] + + for i in range(max_args): + # note: null has typeof object, but is ok to leave as is, since we are calling into asm code where null|0 = 0 + body += " if (arg%d && typeof arg%d === 'object') arg%d = arg%d.ptr;\n" % (i, i, i, i) + body += " else arg%d = ensureString(arg%d);\n" % (i, i) + + for i in range(min_args, max_args): + c_names[i] = 'emscripten_bind_%s_%d' % (bindings_name, i) + body += ' if (arg%d === undefined) { %s%s(%s)%s%s }\n' % (i, call_prefix, '_' + c_names[i], ', '.join(pre_arg + args[:i]), call_postfix, '' if 'return ' in call_prefix else '; ' + (cache or ' ') + 'return') + c_names[max_args] = 'emscripten_bind_%s_%d' % (bindings_name, max_args) + body += ' %s%s(%s)%s;\n' % (call_prefix, '_' + c_names[max_args], ', '.join(pre_arg + args), call_postfix) + if cache: + body += ' ' + cache + '\n' + mid_js += [r'''function%s(%s) { +%s +}''' % ((' ' + func_name) if constructor else '', ', '.join(args), body[:-1])] + + # C + + for i in range(min_args, max_args+1): + raw = sigs.get(i) + if raw is None: continue + sig = [arg.type.name for arg in raw] + + c_arg_types = map(type_to_c, sig) + + normal_args = ', '.join(['%s arg%d' % (c_arg_types[j], j) for j in range(i)]) + if constructor: + full_args = normal_args + else: + full_args = type_to_c(class_name, non_pointing=True) + '* self' + ('' if not normal_args else ', ' + normal_args) + call_args = ', '.join(['%sarg%d' % ('*' if raw[j].getExtendedAttribute('Ref') else '', j) for j in range(i)]) + if constructor: + call = 'new ' + type_to_c(class_name, non_pointing=True) + call += '(' + call_args + ')' + elif call_content is not None: + call = call_content + else: + call = 'self->' + func_name + call += '(' + call_args + ')' + + if operator: + assert '=' in operator, 'can only do += *= etc. for now, all with "="' + cast_self = 'self' + if class_name != func_scope: + # this function comes from an ancestor class; for operators, we must cast it + cast_self = 'dynamic_cast<' + type_to_c(func_scope) + '>(' + cast_self + ')' + call = '(*%s %s %sarg0)' % (cast_self, operator, '*' if sig[0] in interfaces else '') + + pre = '' + + basic_return = 'return ' if constructor or return_type is not 'Void' else '' + return_prefix = basic_return + return_postfix = '' + if non_pointer: + return_prefix += '&'; + if copy: + pre += ' static %s temp;\n' % type_to_c(return_type, non_pointing=True) + return_prefix += '(temp = ' + return_postfix += ', &temp)' + + c_return_type = type_to_c(return_type) + mid_c += [r''' +%s%s EMSCRIPTEN_KEEPALIVE %s(%s) { +%s %s%s%s; +} +''' % ('const ' if const else '', type_to_c(class_name) if constructor else c_return_type, c_names[i], full_args, pre, return_prefix, call, return_postfix)] + + if not constructor: + if i == max_args: + dec_args = ', '.join(map(lambda j: type_to_cdec(raw[j]) + ' arg' + str(j), range(i))) + js_call_args = ', '.join(['%sarg%d' % (('(int)' if sig[j] in interfaces else '') + ('&' if raw[j].getExtendedAttribute('Ref') or raw[j].getExtendedAttribute('Value') else ''), j) for j in range(i)]) + + js_impl_methods += [r''' %s %s(%s) { + %sEM_ASM_%s({ + var self = Module['getCache'](Module['%s'])[$0]; + if (!self.hasOwnProperty('%s')) throw 'a JSImplementation must implement all functions, you forgot %s::%s.'; + %sself.%s(%s)%s; + }, (int)this%s); + }''' % (c_return_type, func_name, dec_args, + basic_return, 'INT' if c_return_type not in C_FLOATS else 'DOUBLE', + class_name, + func_name, class_name, func_name, + return_prefix, + func_name, + ','.join(['$%d' % i for i in range(1, max_args)]), + return_postfix, + (', ' if js_call_args else '') + js_call_args)] + + +for name, interface in interfaces.iteritems(): + js_impl = interface.getExtendedAttribute('JSImplementation') + if not js_impl: continue + implements[name] = [js_impl[0]] + +names = interfaces.keys() +names.sort(lambda x, y: 1 if implements.get(x) and implements[x][0] == y else (-1 if implements.get(y) and implements[y][0] == x else 0)) + +for name in names: + interface = interfaces[name] + + mid_js += ['\n// ' + name + '\n'] + mid_c += ['\n// ' + name + '\n'] + + global js_impl_methods + js_impl_methods = [] + + cons = interface.getExtendedAttribute('Constructor') + if type(cons) == list: raise Exception('do not use "Constructor", instead create methods with the name of the interface') + + js_impl = interface.getExtendedAttribute('JSImplementation') + if js_impl: + js_impl = js_impl[0] + + # Methods + + seen_constructor = False # ensure a constructor, even for abstract base classes + for m in interface.members: + if m.identifier.name == name: + seen_constructor = True + break + if not seen_constructor: + mid_js += ['function %s() { throw "cannot construct a %s, no constructor in IDL" }\n' % (name, name)] + emit_constructor(name) + + for m in interface.members: + if not m.isMethod(): continue + constructor = m.identifier.name == name + if not constructor: + parent_constructor = False + temp = m.parentScope + while temp.parentScope: + if temp.identifier.name == m.identifier.name: + parent_constructor = True + temp = temp.parentScope + if parent_constructor: + continue + if not constructor: + mid_js += [r''' +%s.prototype.%s = ''' % (name, m.identifier.name)] + sigs = {} + return_type = None + for ret, args in m.signatures(): + if return_type is None: + return_type = ret.name + else: + assert return_type == ret.name, 'overloads must have the same return type' + for i in range(len(args)+1): + if i == len(args) or args[i].optional: + assert i not in sigs, 'overloading must differentiate by # of arguments (cannot have two signatures that differ by types but not by length)' + sigs[i] = args[:i] + render_function(name, + m.identifier.name, sigs, return_type, + m.getExtendedAttribute('Ref'), + m.getExtendedAttribute('Value'), + (m.getExtendedAttribute('Operator') or [None])[0], + constructor, + func_scope=m.parentScope.identifier.name) + mid_js += [';\n'] + if constructor: + emit_constructor(name) + + for m in interface.members: + if not m.isAttr(): continue + attr = m.identifier.name + + get_name = 'get_' + attr + mid_js += [r''' + %s.prototype.%s= ''' % (name, get_name)] + render_function(name, + get_name, { 0: [] }, m.type.name, + None, + None, + None, + False, + func_scope=interface, + call_content=take_addr_if_nonpointer(m) + 'self->' + attr, + const=m.getExtendedAttribute('Const')) + + set_name = 'set_' + attr + mid_js += [r''' + %s.prototype.%s= ''' % (name, set_name)] + render_function(name, + set_name, { 1: [Dummy({ 'type': m.type })] }, 'Void', + None, + None, + None, + False, + func_scope=interface, + call_content='self->' + attr + ' = ' + deref_if_nonpointer(m) + 'arg0', + const=m.getExtendedAttribute('Const')) + + if not interface.getExtendedAttribute('NoDelete'): + mid_js += [r''' + %s.prototype.__destroy__ = ''' % name] + render_function(name, + '__destroy__', { 0: [] }, 'Void', + None, + None, + None, + False, + func_scope=interface, + call_content='delete self') + + # Emit C++ class implementation that calls into JS implementation + + if js_impl: + pre_c += [r''' +class %s : public %s { +public: +%s +}; +''' % (name, type_to_c(js_impl, non_pointing=True), '\n'.join(js_impl_methods))] + +mid_c += ['\n}\n\n'] +mid_js += ['\n'] + +# Write + +c = open(output_base + '.cpp', 'w') +for x in pre_c: c.write(x) +for x in mid_c: c.write(x) +c.close() + +js = open(output_base + '.js', 'w') +for x in mid_js: js.write(x) +js.close() + From 34e58f9c073eca117ea890d14ad3f5f6ad374e30 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 23 Apr 2014 17:55:29 -0700 Subject: [PATCH 23/67] link to docs --- tools/webidl_binder.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tools/webidl_binder.py b/tools/webidl_binder.py index 1fecdf9e4b2fc..0507cc7811938 100644 --- a/tools/webidl_binder.py +++ b/tools/webidl_binder.py @@ -1,4 +1,10 @@ +''' +WebIDL binder + +https://github.com/kripken/emscripten/wiki/WebIDL-Binder +''' + import os, sys import shared From 2ad793ffc9402a09c393a5cc0f6916dc5cb9f7da Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 24 Apr 2014 00:12:56 -0700 Subject: [PATCH 24/67] Revert "Export FUNCTION_TABLE_xxx entries to the global asm object for direct access. See issue #2249." This reverts commit 50bcf89f21c098aa54033733b33cb66c6c56d7ce. It broke asm.js validation. --- emscripten.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/emscripten.py b/emscripten.py index 3d75335f59e38..c8122cb9fd61c 100755 --- a/emscripten.py +++ b/emscripten.py @@ -480,7 +480,6 @@ def fix_item(item): asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] - function_tables_arrays = ['FUNCTION_TABLE_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] for sig in last_forwarded_json['Functions']['tables'].iterkeys(): @@ -517,7 +516,7 @@ def fix_item(item): exported_implemented_functions.append('runPostSets') exports = [] if not simple: - for export in exported_implemented_functions + asm_runtime_funcs + function_tables + function_tables_arrays: + for export in exported_implemented_functions + asm_runtime_funcs + function_tables: exports.append("%s: %s" % (export, export)) exports = '{ ' + ', '.join(exports) + ' }' else: @@ -1060,7 +1059,6 @@ def keyfunc(other): asm_runtime_funcs = ['stackAlloc', 'stackSave', 'stackRestore', 'setThrew'] + ['setTempRet%d' % i for i in range(10)] # function tables function_tables = ['dynCall_' + table for table in last_forwarded_json['Functions']['tables']] - function_tables_arrays = ['FUNCTION_TABLE_' + table for table in last_forwarded_json['Functions']['tables']] function_tables_impls = [] for sig in last_forwarded_json['Functions']['tables'].iterkeys(): @@ -1097,7 +1095,7 @@ def keyfunc(other): exported_implemented_functions.append('runPostSets') exports = [] if not simple: - for export in exported_implemented_functions + asm_runtime_funcs + function_tables + function_tables_arrays: + for export in exported_implemented_functions + asm_runtime_funcs + function_tables: exports.append("%s: %s" % (export, export)) exports = '{ ' + ', '.join(exports) + ' }' else: From c7b472ab5ac60c67cae8ab95d0363fd328dd4571 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 24 Apr 2014 00:34:18 -0700 Subject: [PATCH 25/67] have asm.js embind go through dynCall --- src/embind/embind.js | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 124892e32f9c8..058bd5c1303cb 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,4 +1,4 @@ -/*global Module, asm*/ +/*global Module*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64*/ /*global readLatin1String*/ @@ -707,9 +707,21 @@ function craftInvokerFunction(humanName, argTypes, classType, cppInvokerFunc, cp function requireFunction(signature, rawFunction) { signature = readLatin1String(signature); var fp; + // asm.js does not define FUNCTION_TABLE if (typeof FUNCTION_TABLE === "undefined") { - // asm.js style - fp = asm['FUNCTION_TABLE_' + signature][rawFunction]; + // asm.js does not give direct access to the function tables, + // and thus we must go through the dynCall interface which allows + // calling into a signature's function table by pointer value. + // + // https://github.com/dherman/asm.js/issues/83 + // + // This has three main penalties: + // - dynCall is another function call in the path from JavaScript to C++. + // - JITs may not predict through the function table indirection at runtime. + // - Function.prototype.bind generally benchmarks poorly relative to + // function objects, but using 'arguments' would confound JITs and + // possibly allocate. + fp = Module['dynCall_' + signature].bind(undefined, rawFunction); } else { fp = FUNCTION_TABLE[rawFunction]; } From 0471c2bf4fbdf9cc407ec01e3cabd04095c843d0 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 24 Apr 2014 01:18:32 -0700 Subject: [PATCH 26/67] enable embind/asm.js tests. --- src/embind/embind.js | 4 ++-- tests/test_core.py | 3 +-- tests/test_other.py | 1 - 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 058bd5c1303cb..c729aff5632a5 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1,4 +1,4 @@ -/*global Module*/ +/*global Module, asm*/ /*global _malloc, _free, _memcpy*/ /*global FUNCTION_TABLE, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64*/ /*global readLatin1String*/ @@ -721,7 +721,7 @@ function requireFunction(signature, rawFunction) { // - Function.prototype.bind generally benchmarks poorly relative to // function objects, but using 'arguments' would confound JITs and // possibly allocate. - fp = Module['dynCall_' + signature].bind(undefined, rawFunction); + fp = asm['dynCall_' + signature].bind(undefined, rawFunction); } else { fp = FUNCTION_TABLE[rawFunction]; } diff --git a/tests/test_core.py b/tests/test_core.py index 07a7bf7794f5d..083d468ada2ee 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5633,7 +5633,6 @@ def test_demangle_stacks(self): def test_embind(self): if self.emcc_args is None: return self.skip('requires emcc') - if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp') Building.COMPILER_TEST_OPTS += ['--bind'] src = r''' @@ -5656,7 +5655,7 @@ def test_embind(self): def test_embind_2(self): if self.emcc_args is None: return self.skip('requires emcc') - if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp') + if self.run_name == 'slow2asm': return self.skip('embind/asm.js requires fastcomp') Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js'] open('post.js', 'w').write(''' Module.print('lerp ' + Module.lerp(1, 2, 0.66) + '.'); diff --git a/tests/test_other.py b/tests/test_other.py index cdea493a2c29c..af522807c4557 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1880,7 +1880,6 @@ def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1 def test_embind(self): def nonfc(): - if os.environ.get('EMCC_FAST_COMPILER') != '0': return self.skip('todo in fastcomp') for args, fail in [ ([], True), # without --bind, we fail (['--bind'], False), From 9a530d0e76ea951f761d93ce3aa739b5605acb25 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Thu, 24 Apr 2014 01:43:38 -0700 Subject: [PATCH 27/67] passes tests --- src/embind/embind.js | 4 ++++ tests/test_core.py | 1 + 2 files changed, 5 insertions(+) diff --git a/src/embind/embind.js b/src/embind/embind.js index c729aff5632a5..bb9793655b198 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -721,6 +721,10 @@ function requireFunction(signature, rawFunction) { // - Function.prototype.bind generally benchmarks poorly relative to // function objects, but using 'arguments' would confound JITs and // possibly allocate. + var dc = asm['dynCall_' + signature]; + if (dc === undefined) { + throwBindingError("No dynCall invoker for signature: " + signature); + } fp = asm['dynCall_' + signature].bind(undefined, rawFunction); } else { fp = FUNCTION_TABLE[rawFunction]; diff --git a/tests/test_core.py b/tests/test_core.py index 083d468ada2ee..2e2f55870eac3 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5655,6 +5655,7 @@ def test_embind(self): def test_embind_2(self): if self.emcc_args is None: return self.skip('requires emcc') + if self.run_name == 'asm2f': return self.skip('embind/asm.js not compatible with PRECISE_F32 because it changes signature strings') if self.run_name == 'slow2asm': return self.skip('embind/asm.js requires fastcomp') Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js'] open('post.js', 'w').write(''' From 13f1516d15c72fe3b2a6ea70a2ab643f1eedd825 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 24 Apr 2014 13:51:17 -0700 Subject: [PATCH 28/67] if no canvas, do not set up canvas event listeners --- src/library_browser.js | 67 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 33 deletions(-) diff --git a/src/library_browser.js b/src/library_browser.js index 4be7315e73fd8..4cd8b3921ea1e 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -196,41 +196,42 @@ mergeInto(LibraryManager.library, { // Canvas event setup var canvas = Module['canvas']; - - // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module - // Module['forcedAspectRatio'] = 4 / 3; - - canvas.requestPointerLock = canvas['requestPointerLock'] || - canvas['mozRequestPointerLock'] || - canvas['webkitRequestPointerLock'] || - canvas['msRequestPointerLock'] || - function(){}; - canvas.exitPointerLock = document['exitPointerLock'] || - document['mozExitPointerLock'] || - document['webkitExitPointerLock'] || - document['msExitPointerLock'] || - function(){}; // no-op if function does not exist - canvas.exitPointerLock = canvas.exitPointerLock.bind(document); - - function pointerLockChange() { - Browser.pointerLock = document['pointerLockElement'] === canvas || - document['mozPointerLockElement'] === canvas || - document['webkitPointerLockElement'] === canvas || - document['msPointerLockElement'] === canvas; - } + if (canvas) { + // forced aspect ratio can be enabled by defining 'forcedAspectRatio' on Module + // Module['forcedAspectRatio'] = 4 / 3; + + canvas.requestPointerLock = canvas['requestPointerLock'] || + canvas['mozRequestPointerLock'] || + canvas['webkitRequestPointerLock'] || + canvas['msRequestPointerLock'] || + function(){}; + canvas.exitPointerLock = document['exitPointerLock'] || + document['mozExitPointerLock'] || + document['webkitExitPointerLock'] || + document['msExitPointerLock'] || + function(){}; // no-op if function does not exist + canvas.exitPointerLock = canvas.exitPointerLock.bind(document); + + function pointerLockChange() { + Browser.pointerLock = document['pointerLockElement'] === canvas || + document['mozPointerLockElement'] === canvas || + document['webkitPointerLockElement'] === canvas || + document['msPointerLockElement'] === canvas; + } - document.addEventListener('pointerlockchange', pointerLockChange, false); - document.addEventListener('mozpointerlockchange', pointerLockChange, false); - document.addEventListener('webkitpointerlockchange', pointerLockChange, false); - document.addEventListener('mspointerlockchange', pointerLockChange, false); + document.addEventListener('pointerlockchange', pointerLockChange, false); + document.addEventListener('mozpointerlockchange', pointerLockChange, false); + document.addEventListener('webkitpointerlockchange', pointerLockChange, false); + document.addEventListener('mspointerlockchange', pointerLockChange, false); - if (Module['elementPointerLock']) { - canvas.addEventListener("click", function(ev) { - if (!Browser.pointerLock && canvas.requestPointerLock) { - canvas.requestPointerLock(); - ev.preventDefault(); - } - }, false); + if (Module['elementPointerLock']) { + canvas.addEventListener("click", function(ev) { + if (!Browser.pointerLock && canvas.requestPointerLock) { + canvas.requestPointerLock(); + ev.preventDefault(); + } + }, false); + } } }, From 0689e43ae61723dde87ec9a2b6210a349d080b31 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 24 Apr 2014 16:52:27 -0700 Subject: [PATCH 29/67] check function table masks in safe heap mode --- emscripten.py | 2 +- src/preamble.js | 8 ++++++ tests/test_other.py | 32 +++++++++++++++++++++ tools/js-optimizer.js | 66 ++++++++++++++++++++++++------------------- 4 files changed, 78 insertions(+), 30 deletions(-) diff --git a/emscripten.py b/emscripten.py index c8122cb9fd61c..c8fab3be81cf4 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1003,7 +1003,7 @@ def fix_item(item): basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') - if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE'] + if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_FT_MASK'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] if settings['ASSERTIONS']: if settings['ASSERTIONS'] >= 2: import difflib diff --git a/src/preamble.js b/src/preamble.js index 89ab5026ccf6f..5dd8ada1ab993 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -207,6 +207,14 @@ function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) { return ret; } +function SAFE_FT_MASK(value, mask) { + var ret = value & mask; + if (ret !== value) { + abort('Function table mask error: function pointer is ' + value + ' which is masked by ' + mask + ', the likely cause of this is that the function pointer is being called by the wrong type.'); + } + return ret; +} + #endif #endif diff --git a/tests/test_other.py b/tests/test_other.py index cdea493a2c29c..e4d91ba67041d 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -2710,3 +2710,35 @@ def test_bc_to_bc(self): assert os.path.exists('hello_world.o') assert os.path.exists('hello_world.bc') + def test_bad_function_pointer_cast(self): + open('src.cpp', 'w').write(r''' +#include + +typedef int (*callback) (int, ...); + +int impl(int foo) { + printf("Hello, world.\n"); + return 0; +} + +int main() { + volatile callback f = (callback) impl; + f(0); /* This fails with or without additional arguments. */ + return 0; +} +''') + + for opts in [0, 1, 2]: + for safe in [0, 1]: + cmd = [PYTHON, EMCC, 'src.cpp', '-O' + str(opts), '-s', 'SAFE_HEAP=' + str(safe)] + print cmd + Popen(cmd).communicate() + output = run_js('a.out.js', stderr=PIPE, full_output=True) + if safe: + assert 'Function table mask error' in output, output + else: + if opts == 0: + assert 'Invalid function pointer called' in output, output + else: + assert 'abort()' in output, output + diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index 32c26c51a400a..db85965dca952 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -4926,36 +4926,44 @@ function safeHeap(ast) { } } } else if (type === 'sub') { - var heap = node[1][1]; - if (heap[0] !== 'H') return; - var ptr = fixPtr(node[2], heap); - // SAFE_HEAP_LOAD(ptr, bytes, isFloat) - switch (heap) { - case 'HEAP8': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT); - } - case 'HEAPU8': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT); - } - case 'HEAP16': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT); - } - case 'HEAPU16': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT); - } - case 'HEAP32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT); - } - case 'HEAPU32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT); - } - case 'HEAPF32': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE); - } - case 'HEAPF64': { - return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + var target = node[1][1]; + if (target[0] === 'H') { + // heap access + var heap = target; + var ptr = fixPtr(node[2], heap); + // SAFE_HEAP_LOAD(ptr, bytes, isFloat) + switch (heap) { + case 'HEAP8': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU8': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 1], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAP16': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU16': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 2], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAP32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '0']]], ASM_INT); + } + case 'HEAPU32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '0'], ['num', '1']]], ASM_INT); + } + case 'HEAPF32': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 4], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + } + case 'HEAPF64': { + return makeAsmCoercion(['call', ['name', 'SAFE_HEAP_LOAD'], [ptr, ['num', 8], ['num', '1'], ['num', '0']]], ASM_DOUBLE); + } + default: throw 'bad heap ' + heap; } - default: throw 'bad heap ' + heap; + } else { + assert(target[0] == 'F'); + // function table indexing mask + assert(node[2][0] === 'binary' && node[2][1] === '&'); + node[2][2] = makeAsmCoercion(['call', ['name', 'SAFE_FT_MASK'], [makeAsmCoercion(node[2][2], ASM_INT), makeAsmCoercion(node[2][3], ASM_INT)]], ASM_INT); } } }); From 763177a52d0f48198192375f1b912c8a37230425 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 24 Apr 2014 17:41:11 -0700 Subject: [PATCH 30/67] improve test_polymorph --- tests/core/test_polymorph.in | 8 ++++++++ tests/core/test_polymorph.out | 4 +++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/core/test_polymorph.in b/tests/core/test_polymorph.in index 1f24a1aa5adda..af07dc05de2ee 100644 --- a/tests/core/test_polymorph.in +++ b/tests/core/test_polymorph.in @@ -16,6 +16,8 @@ struct Child : Parent { struct Other { int one() { return 11; } int two() { return 22; } + virtual int three() { return 33; } + virtual int four() { return 44; } }; int main() { @@ -24,10 +26,16 @@ int main() { printf("*%d,%d,%d,%d*\n", x->getit(), y->getit(), x->implme(), y->implme()); Other *o = new Other; + int (Other::*Ls)() = &Other::one; printf("*%d*\n", (o->*(Ls))()); Ls = &Other::two; printf("*%d*\n", (o->*(Ls))()); + Ls = &Other::three; + printf("*%d*\n", (o->*(Ls))()); + Ls = &Other::four; + printf("*%d*\n", (o->*(Ls))()); + return 0; } diff --git a/tests/core/test_polymorph.out b/tests/core/test_polymorph.out index 0d036bf0f9dd4..5163ea8e809f1 100644 --- a/tests/core/test_polymorph.out +++ b/tests/core/test_polymorph.out @@ -1,3 +1,5 @@ *11,74,32,1012* *11* -*22* \ No newline at end of file +*22* +*33* +*44* From b302308c7d451f17eb6dd2bade749800ea2d3925 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Thu, 24 Apr 2014 19:38:17 -0700 Subject: [PATCH 31/67] deprecate bindings generator --- tools/bindings_generator.py | 55 +++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/tools/bindings_generator.py b/tools/bindings_generator.py index 5bf0996ed9449..9bc8b9295aa31 100755 --- a/tools/bindings_generator.py +++ b/tools/bindings_generator.py @@ -1,6 +1,61 @@ #!/usr/bin/env python2 ''' + + + + + + + + + + + + + + + + + + + + + + + + +XXX THIS IS DEPRECATED, see webidl_binder.py XXX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use CppHeaderParser to parse some C++ headers, and generate binding code for them. Usage: From ffa17762a625018c557a39056ac8eb0b54251694 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 25 Apr 2014 10:12:01 -0700 Subject: [PATCH 32/67] indicate an error in the html shell when an exception is not caught --- src/shell.html | 7 +++++++ src/shell_minimal.html | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/shell.html b/src/shell.html index 226f12b9362f5..1e213024b3dab 100644 --- a/src/shell.html +++ b/src/shell.html @@ -1273,6 +1273,13 @@ } }; Module.setStatus('Downloading...'); + window.onerror = function() { + Module.setStatus('Exception thrown, see JavaScript console'); + spinnerElement.style.display = 'none'; + Module.setStatus = function(text) { + if (text) Module.printErr('[post-exception status] ' + text); + }; + }; {{{ SCRIPT }}} diff --git a/src/shell_minimal.html b/src/shell_minimal.html index 6f48371986fb2..7dd67929447f0 100644 --- a/src/shell_minimal.html +++ b/src/shell_minimal.html @@ -129,6 +129,13 @@ } }; Module.setStatus('Downloading...'); + window.onerror = function() { + Module.setStatus('Exception thrown, see JavaScript console'); + spinnerElement.style.display = 'none'; + Module.setStatus = function(text) { + if (text) Module.printErr('[post-exception status] ' + text); + }; + }; {{{ SCRIPT }}} From a7dfddc6abee48cc9484fe8f08f45d053f08dae2 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 25 Apr 2014 17:12:47 -0700 Subject: [PATCH 33/67] support disabling ALIASING_FUNCTION_POINTERS in fastcomp --- emscripten.py | 2 ++ tests/test_other.py | 47 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/emscripten.py b/emscripten.py index c8fab3be81cf4..835b1ec97bf2e 100755 --- a/emscripten.py +++ b/emscripten.py @@ -748,6 +748,8 @@ def emscript_fast(infile, settings, outfile, libraries=[], compiler_engine=None, backend_args += ['-emscripten-reserved-function-pointers=%d' % settings['RESERVED_FUNCTION_POINTERS']] if settings['ASSERTIONS'] > 0: backend_args += ['-emscripten-assertions=%d' % settings['ASSERTIONS']] + if settings['ALIASING_FUNCTION_POINTERS'] == 0: + backend_args += ['-emscripten-no-aliasing-function-pointers'] backend_args += ['-O' + str(settings['OPT_LEVEL'])] if DEBUG: logging.debug('emscript: llvm backend: ' + ' '.join(backend_args)) diff --git a/tests/test_other.py b/tests/test_other.py index 4b5ed6669aa4b..0721bb35d6acd 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -2741,3 +2741,50 @@ def test_bad_function_pointer_cast(self): else: assert 'abort()' in output, output + def test_aliased_func_pointers(self): + open('src.cpp', 'w').write(r''' +#include + +int impl1(int foo) { return foo; } +float impla(float foo) { return foo; } +int impl2(int foo) { return foo+1; } +float implb(float foo) { return foo+1; } +int impl3(int foo) { return foo+2; } +float implc(float foo) { return foo+2; } + +int main(int argc, char **argv) { + volatile void *f = (void*)impl1; + if (argc == 50) f = (void*)impla; + if (argc == 51) f = (void*)impl2; + if (argc == 52) f = (void*)implb; + if (argc == 53) f = (void*)impl3; + if (argc == 54) f = (void*)implc; + return (int)f; +} +''') + + print 'aliasing' + + sizes_ii = {} + sizes_dd = {} + + for alias in [None, 0, 1]: + cmd = [PYTHON, EMCC, 'src.cpp', '-O1'] + if alias is not None: + cmd += ['-s', 'ALIASING_FUNCTION_POINTERS=' + str(alias)] + else: + alias = -1 + print cmd + Popen(cmd).communicate() + src = open('a.out.js').read().split('\n') + for line in src: + if line.strip().startswith('var FUNCTION_TABLE_ii = '): + sizes_ii[alias] = line.count(',') + if line.strip().startswith('var FUNCTION_TABLE_dd = '): + sizes_dd[alias] = line.count(',') + + for sizes in [sizes_ii, sizes_dd]: + assert sizes[-1] == 3 # default - let them alias + assert sizes[0] == 7 # no aliasing, all unique, fat tables + assert sizes[1] == 3 # aliased once more + From 1640a6a67ecbe2a4d9c0c520878e7b1d90ddf137 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Sat, 19 Apr 2014 14:56:56 +0300 Subject: [PATCH 34/67] Improve SAFE_HEAP assertion messages to be more informative out of the box. --- src/preamble.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/preamble.js b/src/preamble.js index 5dd8ada1ab993..2aec94c6a9293 100644 --- a/src/preamble.js +++ b/src/preamble.js @@ -186,17 +186,17 @@ function SAFE_HEAP_STORE(dest, value, bytes, isFloat) { #if SAFE_HEAP_LOG Module.print('SAFE_HEAP store: ' + [dest, value, bytes, isFloat]); #endif - assert(dest > 0, 'segmentation fault'); - assert(dest % bytes === 0, 'alignment error'); - assert(dest < Math.max(DYNAMICTOP, STATICTOP), 'segmentation fault (high)'); + if (dest <= 0) abort('segmentation fault storing ' + bytes + ' bytes to address ' + dest); + if (dest % bytes !== 0) abort('alignment error storing to address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes); + if (dest + bytes > Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault, exceeded the top of the available heap when storing ' + bytes + ' bytes to address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + DYNAMICTOP); assert(DYNAMICTOP <= TOTAL_MEMORY); setValue(dest, value, getSafeHeapType(bytes, isFloat), 1); } function SAFE_HEAP_LOAD(dest, bytes, isFloat, unsigned) { - assert(dest > 0, 'segmentation fault'); - assert(dest % bytes === 0, 'alignment error'); - assert(dest < Math.max(DYNAMICTOP, STATICTOP), 'segmentation fault (high)'); + if (dest <= 0) abort('segmentation fault loading ' + bytes + ' bytes from address ' + dest); + if (dest % bytes !== 0) abort('alignment error loading from address ' + dest + ', which was expected to be aligned to a multiple of ' + bytes); + if (dest + bytes > Math.max(DYNAMICTOP, STATICTOP)) abort('segmentation fault, exceeded the top of the available heap when loading ' + bytes + ' bytes from address ' + dest + '. STATICTOP=' + STATICTOP + ', DYNAMICTOP=' + DYNAMICTOP); assert(DYNAMICTOP <= TOTAL_MEMORY); var type = getSafeHeapType(bytes, isFloat); var ret = getValue(dest, type, 1); From d341059aaef966f3d9a34519802f451347f679eb Mon Sep 17 00:00:00 2001 From: Michael Bishop Date: Mon, 23 Sep 2013 19:22:37 -0400 Subject: [PATCH 35/67] Added FileSystem tracking Support. --- src/library_fs.js | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/library_fs.js b/src/library_fs.js index d53210f9660c4..e7e194cf4a402 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -26,7 +26,13 @@ mergeInto(LibraryManager.library, { // This is set to false when the runtime is initialized, allowing you // to modify the filesystem freely before run() is called. ignorePermissions: true, - + trackingDelegate: {}, + tracking: { + openFlags: { + READ: 1 << 0, + WRITE: 1 << 1 + } + }, ErrnoError: null, // set during init genericErrors: {}, @@ -725,6 +731,12 @@ mergeInto(LibraryManager.library, { // changed its name) FS.hashAddNode(old_node); } + if (FS.trackingDelegate) { + if (FS.trackingDelegate['didDeleteFile']) + FS.trackingDelegate['didDeleteFile'](old_path); + if (FS.trackingDelegate['didOpenFile']) + FS.trackingDelegate['didOpenFile'](new_path, FS.tracking.openFlags.WRITE); + } }, rmdir: function(path) { var lookup = FS.lookupPath(path, { parent: true }); @@ -771,6 +783,9 @@ mergeInto(LibraryManager.library, { } parent.node_ops.unlink(parent, name); FS.destroyNode(node); + if (FS.trackingDelegate && FS.trackingDelegate['didDeleteFile']) { + FS.trackingDelegate['didDeleteFile'](path); + } }, readlink: function(path) { var lookup = FS.lookupPath(path); @@ -965,6 +980,14 @@ mergeInto(LibraryManager.library, { Module['printErr']('read file: ' + path); } } + if (FS.trackingDelegate && FS.trackingDelegate['didOpenFile']) { + var trackingFlags = 0; + if (!(flags & {{{ cDefine('O_WRONLY')}}})) + trackingFlags != FS.tracking.openFlags.READ; + if (!(flags & {{{ cDefine('O_RDONLY')}}})) + trackingFlags != FS.tracking.openFlags.WRITE; + FS.trackingDelegate['didOpenFile'](path, trackingFlags); + } return stream; }, close: function(stream) { From 288652f0fe673fb218f5ff710f00304e25b87026 Mon Sep 17 00:00:00 2001 From: "Michael J. Bishop" Date: Wed, 25 Sep 2013 15:46:27 -0400 Subject: [PATCH 36/67] Added file closing to the list of tracked events. --- src/library_fs.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/library_fs.js b/src/library_fs.js index e7e194cf4a402..6573fd173ed53 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -736,6 +736,8 @@ mergeInto(LibraryManager.library, { FS.trackingDelegate['didDeleteFile'](old_path); if (FS.trackingDelegate['didOpenFile']) FS.trackingDelegate['didOpenFile'](new_path, FS.tracking.openFlags.WRITE); + if (FS.trackingDelegate['didCloseFile']) + FS.trackingDelegate['didCloseFile'](new_path); } }, rmdir: function(path) { @@ -982,10 +984,10 @@ mergeInto(LibraryManager.library, { } if (FS.trackingDelegate && FS.trackingDelegate['didOpenFile']) { var trackingFlags = 0; - if (!(flags & {{{ cDefine('O_WRONLY')}}})) - trackingFlags != FS.tracking.openFlags.READ; - if (!(flags & {{{ cDefine('O_RDONLY')}}})) - trackingFlags != FS.tracking.openFlags.WRITE; + if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}) + trackingFlags |= FS.tracking.openFlags.READ; + if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}) + trackingFlags |= FS.tracking.openFlags.WRITE; FS.trackingDelegate['didOpenFile'](path, trackingFlags); } return stream; @@ -999,6 +1001,9 @@ mergeInto(LibraryManager.library, { throw e; } finally { FS.closeStream(stream.fd); + if (FS.trackingDelegate && stream.path && FS.trackingDelegate['didCloseFile']) { + FS.trackingDelegate['didCloseFile'](stream.path); + } } }, llseek: function(stream, offset, whence) { From fa9b6011557011c2e65963ab15a1856d33d442b9 Mon Sep 17 00:00:00 2001 From: "Michael J. Bishop" Date: Wed, 25 Sep 2013 22:46:54 -0400 Subject: [PATCH 37/67] Added support for file tracking being used to track when a file has been written to. --- src/library_fs.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/library_fs.js b/src/library_fs.js index 6573fd173ed53..e5c175061590a 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -1062,6 +1062,9 @@ mergeInto(LibraryManager.library, { } var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); if (!seeking) stream.position += bytesWritten; + if (FS.trackingDelegate && stream.path && FS.trackingDelegate['didWriteToFile']) { + FS.trackingDelegate['didWriteToFile'](stream.path); + } return bytesWritten; }, allocate: function(stream, offset, length) { From 583efabba5f0da11fecdebbe1ff3d1c846bfbd1e Mon Sep 17 00:00:00 2001 From: "Michael J. Bishop" Date: Thu, 10 Oct 2013 14:53:00 -0400 Subject: [PATCH 38/67] Added support for moving paths. Removed specific callbacks for directories and files, opting instead for callbacks that apply to generic paths. --- src/library_fs.js | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/library_fs.js b/src/library_fs.js index e5c175061590a..6c083ed5c246f 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -719,6 +719,8 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(err); } } + if (FS.trackingDelegate['willMovePath']) + FS.trackingDelegate['willMovePath'](old_path, new_path); // remove the node from the lookup hash FS.hashRemoveNode(old_node); // do the underlying fs rename @@ -730,14 +732,8 @@ mergeInto(LibraryManager.library, { // add the node back to the hash (in case node_ops.rename // changed its name) FS.hashAddNode(old_node); - } - if (FS.trackingDelegate) { - if (FS.trackingDelegate['didDeleteFile']) - FS.trackingDelegate['didDeleteFile'](old_path); - if (FS.trackingDelegate['didOpenFile']) - FS.trackingDelegate['didOpenFile'](new_path, FS.tracking.openFlags.WRITE); - if (FS.trackingDelegate['didCloseFile']) - FS.trackingDelegate['didCloseFile'](new_path); + if (FS.trackingDelegate['didMovePath']) + FS.trackingDelegate['didMovePath'](old_path, new_path); } }, rmdir: function(path) { @@ -755,8 +751,14 @@ mergeInto(LibraryManager.library, { if (FS.isMountpoint(node)) { throw new FS.ErrnoError(ERRNO_CODES.EBUSY); } + if (FS.trackingDelegate['willDeletePath']) { + FS.trackingDelegate['willDeletePath'](path); + } parent.node_ops.rmdir(parent, name); FS.destroyNode(node); + if (FS.trackingDelegate['didDeletePath']) { + FS.trackingDelegate['didDeletePath'](path); + } }, readdir: function(path) { var lookup = FS.lookupPath(path, { follow: true }); @@ -783,10 +785,13 @@ mergeInto(LibraryManager.library, { if (FS.isMountpoint(node)) { throw new FS.ErrnoError(ERRNO_CODES.EBUSY); } + if (FS.trackingDelegate['willDeletePath']) { + FS.trackingDelegate['willDeletePath'](path); + } parent.node_ops.unlink(parent, name); FS.destroyNode(node); - if (FS.trackingDelegate && FS.trackingDelegate['didDeleteFile']) { - FS.trackingDelegate['didDeleteFile'](path); + if (FS.trackingDelegate['didDeletePath']) { + FS.trackingDelegate['didDeletePath'](path); } }, readlink: function(path) { From 7ff1046c01ba8b4586576a6c5f29cdf5ab878bc4 Mon Sep 17 00:00:00 2001 From: "Michael J. Bishop" Date: Fri, 11 Oct 2013 14:52:28 -0400 Subject: [PATCH 39/67] Wrapped the delegate calls in exception handlers so the exceptions would be reported, but not bubble up and be caught by the callers of the FS methods since the callers will interpret those as problems with the FS code and report them as such (which is very confusing). Also removed the "willClose" call as I don't use it. --- src/library_fs.js | 77 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 54 insertions(+), 23 deletions(-) diff --git a/src/library_fs.js b/src/library_fs.js index 6c083ed5c246f..e0b73db8f9583 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -719,8 +719,13 @@ mergeInto(LibraryManager.library, { throw new FS.ErrnoError(err); } } - if (FS.trackingDelegate['willMovePath']) - FS.trackingDelegate['willMovePath'](old_path, new_path); + try { + if (FS.trackingDelegate['willMovePath']) { + FS.trackingDelegate['willMovePath'](old_path, new_path); + } + } catch(e) { + console.log("FS.trackingDelegate['willMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message); + } // remove the node from the lookup hash FS.hashRemoveNode(old_node); // do the underlying fs rename @@ -732,8 +737,13 @@ mergeInto(LibraryManager.library, { // add the node back to the hash (in case node_ops.rename // changed its name) FS.hashAddNode(old_node); - if (FS.trackingDelegate['didMovePath']) + } + try { + if (FS.trackingDelegate['didMovePath']) { FS.trackingDelegate['didMovePath'](old_path, new_path); + } + } catch(e) { + console.log("FS.trackingDelegate['didMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message); } }, rmdir: function(path) { @@ -751,13 +761,21 @@ mergeInto(LibraryManager.library, { if (FS.isMountpoint(node)) { throw new FS.ErrnoError(ERRNO_CODES.EBUSY); } - if (FS.trackingDelegate['willDeletePath']) { - FS.trackingDelegate['willDeletePath'](path); + try { + if (FS.trackingDelegate['willDeletePath']) { + FS.trackingDelegate['willDeletePath'](path); + } + } catch(e) { + console.log("FS.trackingDelegate['willDeletePath']('"+path+"') threw an exception: " + e.message); } parent.node_ops.rmdir(parent, name); FS.destroyNode(node); - if (FS.trackingDelegate['didDeletePath']) { - FS.trackingDelegate['didDeletePath'](path); + try { + if (FS.trackingDelegate['didDeletePath']) { + FS.trackingDelegate['didDeletePath'](path); + } + } catch(e) { + console.log("FS.trackingDelegate['didDeletePath']('"+path+"') threw an exception: " + e.message); } }, readdir: function(path) { @@ -785,13 +803,21 @@ mergeInto(LibraryManager.library, { if (FS.isMountpoint(node)) { throw new FS.ErrnoError(ERRNO_CODES.EBUSY); } - if (FS.trackingDelegate['willDeletePath']) { - FS.trackingDelegate['willDeletePath'](path); + try { + if (FS.trackingDelegate['willDeletePath']) { + FS.trackingDelegate['willDeletePath'](path); + } + } catch(e) { + console.log("FS.trackingDelegate['willDeletePath']('"+path+"') threw an exception: " + e.message); } parent.node_ops.unlink(parent, name); FS.destroyNode(node); - if (FS.trackingDelegate['didDeletePath']) { - FS.trackingDelegate['didDeletePath'](path); + try { + if (FS.trackingDelegate['didDeletePath']) { + FS.trackingDelegate['didDeletePath'](path); + } + } catch(e) { + console.log("FS.trackingDelegate['didDeletePath']('"+path+"') threw an exception: " + e.message); } }, readlink: function(path) { @@ -987,13 +1013,17 @@ mergeInto(LibraryManager.library, { Module['printErr']('read file: ' + path); } } - if (FS.trackingDelegate && FS.trackingDelegate['didOpenFile']) { - var trackingFlags = 0; - if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}) - trackingFlags |= FS.tracking.openFlags.READ; - if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}) - trackingFlags |= FS.tracking.openFlags.WRITE; - FS.trackingDelegate['didOpenFile'](path, trackingFlags); + try { + if (FS.trackingDelegate['didOpenFile']) { + var trackingFlags = 0; + if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}) + trackingFlags |= FS.tracking.openFlags.READ; + if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}) + trackingFlags |= FS.tracking.openFlags.WRITE; + FS.trackingDelegate['didOpenFile'](path, trackingFlags); + } + } catch(e) { + console.log("FS.trackingDelegate['didOpenFile']('"+path+"', flags) threw an exception: " + e.message); } return stream; }, @@ -1006,9 +1036,6 @@ mergeInto(LibraryManager.library, { throw e; } finally { FS.closeStream(stream.fd); - if (FS.trackingDelegate && stream.path && FS.trackingDelegate['didCloseFile']) { - FS.trackingDelegate['didCloseFile'](stream.path); - } } }, llseek: function(stream, offset, whence) { @@ -1067,8 +1094,12 @@ mergeInto(LibraryManager.library, { } var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); if (!seeking) stream.position += bytesWritten; - if (FS.trackingDelegate && stream.path && FS.trackingDelegate['didWriteToFile']) { - FS.trackingDelegate['didWriteToFile'](stream.path); + try { + if (stream.path && FS.trackingDelegate['didWriteToFile']) { + FS.trackingDelegate['didWriteToFile'](stream.path); + } + } catch(e) { + console.log("FS.trackingDelegate['didWriteToFile']('"+path+"') threw an exception: " + e.message); } return bytesWritten; }, From 71e46835b826351815b94ca059756eaf65595fae Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 29 Apr 2014 13:39:45 -0700 Subject: [PATCH 40/67] fix bug where we tried to emit switches in fused multiples, which led to labels on ifs in some cases; fixes #2302 --- src/relooper/Relooper.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index ce9232d9947f5..cd001df98362e 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -17,6 +17,10 @@ typedef std::string ministring; #endif +// uncomment these out to get LLVM errs() debugging support +//#include +//using namespace llvm; + template static bool contains(const T& container, const U& contained) { return container.count(contained); } @@ -202,6 +206,7 @@ void Block::Render(bool InLoop) { if (Fused) { PrintDebug("Fusing Multiple to Simple\n"); Parent->Next = Parent->Next->Next; + Fused->UseSwitch = false; // TODO: emit switches here Fused->RenderLoopPrefix(); // When the Multiple has the same number of groups as we have branches, From 5d50ac51fe1ed4eca6450812b5689142dd406265 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 29 Apr 2014 13:48:27 -0700 Subject: [PATCH 41/67] revert 2ad1070/#2297 due to errors, until we figure out the right solution; see also #2310 --- src/library_sdl.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/library_sdl.js b/src/library_sdl.js index 6e235e903b115..077f72eb0cdae 100644 --- a/src/library_sdl.js +++ b/src/library_sdl.js @@ -686,11 +686,7 @@ var LibrarySDL = { } else { code = SDL.keyCodes[event.keyCode] || event.keyCode; } - - var scan = code & ~(1 << 10); - scan = SDL.scanCodes[scan] || scan; - - {{{ makeSetValue('SDL.keyboardState', 'scan', 'down', 'i8') }}}; + {{{ makeSetValue('SDL.keyboardState', 'code', 'down', 'i8') }}}; // TODO: lmeta, rmeta, numlock, capslock, KMOD_MODE, KMOD_RESERVED SDL.modState = ({{{ makeGetValue('SDL.keyboardState', '1248', 'i8') }}} ? 0x0040 | 0x0080 : 0) | // KMOD_LCTRL & KMOD_RCTRL ({{{ makeGetValue('SDL.keyboardState', '1249', 'i8') }}} ? 0x0001 | 0x0002 : 0) | // KMOD_LSHIFT & KMOD_RSHIFT From 066eb33d5f169c1d0e8a3eddd41b1f21ceced6c5 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 29 Apr 2014 14:07:03 -0700 Subject: [PATCH 42/67] remove unneeded code --- src/relooper/Relooper.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/relooper/Relooper.cpp b/src/relooper/Relooper.cpp index cd001df98362e..568dd381d9046 100644 --- a/src/relooper/Relooper.cpp +++ b/src/relooper/Relooper.cpp @@ -324,11 +324,7 @@ void MultipleShape::RenderLoopPrefix() { } } else { if (Labeled) { - if (UseSwitch) { - PrintIndented("L%d: ", Id); - } else { - PrintIndented("L%d: do {\n", Id); - } + PrintIndented("L%d: do {\n", Id); } else { PrintIndented("do {\n"); } From d00fef35c95285b05352757e512685e0dd657bbb Mon Sep 17 00:00:00 2001 From: Camilo Polymeris Date: Sat, 26 Apr 2014 23:01:07 -0300 Subject: [PATCH 43/67] Bind std::basic_string to js strings --- system/lib/embind/bind.cpp | 1 + tests/embind/embind.test.js | 15 +++++++++++++++ tests/embind/embind_test.cpp | 4 ++++ 3 files changed, 20 insertions(+) diff --git a/system/lib/embind/bind.cpp b/system/lib/embind/bind.cpp index 37918050e7c64..16c24a91869e1 100644 --- a/system/lib/embind/bind.cpp +++ b/system/lib/embind/bind.cpp @@ -78,6 +78,7 @@ EMSCRIPTEN_BINDINGS(native_and_builtin_types) { register_float("double"); _embind_register_std_string(TypeID::get(), "std::string"); + _embind_register_std_string(TypeID >::get(), "std::basic_string"); _embind_register_std_wstring(TypeID::get(), sizeof(wchar_t), "std::wstring"); _embind_register_emval(TypeID::get(), "emscripten::val"); _embind_register_memory_view(TypeID::get(), "emscripten::memory_view"); diff --git a/tests/embind/embind.test.js b/tests/embind/embind.test.js index 6bba4de085d82..3ded811a91590 100644 --- a/tests/embind/embind.test.js +++ b/tests/embind/embind.test.js @@ -442,6 +442,21 @@ module({ var e = cm.emval_test_take_and_return_std_string((new Int8Array([65, 66, 67, 68])).buffer); assert.equal('ABCD', e); }); + + test("can pass Uint8Array to std::basic_string", function() { + var e = cm.emval_test_take_and_return_std_basic_string_unsigned_char(new Uint8Array([65, 66, 67, 68])); + assert.equal('ABCD', e); + }); + + test("can pass Int8Array to std::basic_string", function() { + var e = cm.emval_test_take_and_return_std_basic_string_unsigned_char(new Int8Array([65, 66, 67, 68])); + assert.equal('ABCD', e); + }); + + test("can pass ArrayBuffer to std::basic_string", function() { + var e = cm.emval_test_take_and_return_std_basic_string_unsigned_char((new Int8Array([65, 66, 67, 68])).buffer); + assert.equal('ABCD', e); + }); test("non-ascii wstrings", function() { var expected = String.fromCharCode(10) + diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 1b835751f02fe..2b6a4d1b6c484 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -109,6 +109,10 @@ std::string emval_test_take_and_return_std_string_const_ref(const std::string& s return str; } +std::basic_string emval_test_take_and_return_std_basic_string_unsigned_char(std::basic_string str) { + return str; +} + std::wstring take_and_return_std_wstring(std::wstring str) { return str; } From ef6e3bada9777e5bece9e0b5a6a96e5b80645845 Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Sat, 26 Apr 2014 21:41:52 -0700 Subject: [PATCH 44/67] fix polymeris's tests --- tests/embind/embind_test.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/embind/embind_test.cpp b/tests/embind/embind_test.cpp index 2b6a4d1b6c484..5a83903a83b87 100644 --- a/tests/embind/embind_test.cpp +++ b/tests/embind/embind_test.cpp @@ -1450,6 +1450,7 @@ EMSCRIPTEN_BINDINGS(tests) { //function("emval_test_take_and_return_const_char_star", &emval_test_take_and_return_const_char_star); function("emval_test_take_and_return_std_string", &emval_test_take_and_return_std_string); function("emval_test_take_and_return_std_string_const_ref", &emval_test_take_and_return_std_string_const_ref); + function("emval_test_take_and_return_std_basic_string_unsigned_char", &emval_test_take_and_return_std_basic_string_unsigned_char); function("take_and_return_std_wstring", &take_and_return_std_wstring); //function("emval_test_take_and_return_CustomStruct", &emval_test_take_and_return_CustomStruct); From 6c1b114fa5078dcac3f6617a6f890f0106fcf090 Mon Sep 17 00:00:00 2001 From: Camilo Polymeris Date: Tue, 29 Apr 2014 17:20:09 -0400 Subject: [PATCH 45/67] Add myself to AUTHORS --- AUTHORS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index c162103af2fb2..7994f80e26ba4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -137,4 +137,4 @@ a license to everyone to use it as detailed in LICENSE.) * Ori Avtalion * Guillaume Blanc * Usagi Ito - +* Camilo Polymeris From 9e8d324014afa35df05bdc70ba8f2990909b6d74 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 29 Apr 2014 14:33:56 -0700 Subject: [PATCH 46/67] do not exit runtime if safeSetTimeout|Interval are called --- src/library_browser.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/library_browser.js b/src/library_browser.js index 4cd8b3921ea1e..5cc7e1229edf5 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -430,11 +430,13 @@ mergeInto(LibraryManager.library, { }); }, safeSetTimeout: function(func, timeout) { + Module['noExitRuntime'] = true; return setTimeout(function() { if (!ABORT) func(); }, timeout); }, safeSetInterval: function(func, timeout) { + Module['noExitRuntime'] = true; return setInterval(function() { if (!ABORT) func(); }, timeout); From d5cf59ac87b14eee47e229fe0543c8faa27a2ff4 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 29 Apr 2014 14:45:40 -0700 Subject: [PATCH 47/67] support -o with precompiled headers; fixes #2320 --- emcc | 4 +++- tests/test_other.py | 5 +++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/emcc b/emcc index 47dbc60d8536f..d2de63fc1fb4f 100755 --- a/emcc +++ b/emcc @@ -1366,7 +1366,9 @@ try: for header in input_files: assert header.endswith(HEADER_ENDINGS), 'if you have one header input, we assume you want to precompile headers, and cannot have source files or other inputs as well: ' + str(input_files) + ' : ' + header args = newargs + shared.EMSDK_CXX_OPTS + input_files - logging.debug("running (for precompiled headers: " + call + ' ' + ' '.join(args)) + if specified_target: + args += ['-o', specified_target] + logging.debug("running (for precompiled headers): " + call + ' ' + ' '.join(args)) execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) sys.exit(1) diff --git a/tests/test_other.py b/tests/test_other.py index 0721bb35d6acd..4560ac6ec26e8 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -2380,6 +2380,11 @@ def test_precompiled_headers(self): err = Popen([PYTHON, EMCC, 'src.cpp', '-include', 'header.h', '-Xclang', '-print-stats'], stderr=PIPE).communicate() assert '*** PCH/Modules Loaded:\nModule: header.h.gch' not in err[1], err[1] + # with specified target via -o + try_delete('header.h.gch') + Popen([PYTHON, EMCC, '-xc++-header', 'header.h', '-o', 'my.gch']).communicate() + assert os.path.exists('my.gch') + def test_warn_unaligned(self): if os.environ.get('EMCC_FAST_COMPILER') == '0': return self.skip('need fastcomp') open('src.cpp', 'w').write(r''' From d94a785aea5d9ef1dda385c6f11d50827adb7c33 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 29 Apr 2014 15:54:45 -0700 Subject: [PATCH 48/67] support h and hh in sscanf, and fix non-i32 case in hex sscanf; fixes #2322 --- src/library.js | 23 ++++++++++++++--------- tests/core/test_sscanf_hex.in | 24 ++++++++++++++++++++++-- tests/core/test_sscanf_hex.out | 3 ++- 3 files changed, 38 insertions(+), 12 deletions(-) diff --git a/src/library.js b/src/library.js index c283039728440..c8c5a0ff82916 100644 --- a/src/library.js +++ b/src/library.js @@ -1584,7 +1584,6 @@ LibraryManager.library = { return /^[+-]?[0-9]*\.?[0-9]+([eE][+-]?[0-9]+)?/.exec(text); }, - // TODO: Document. _scanString__deps: ['_getFloat'], _scanString: function(format, get, unget, varargs) { if (!__scanString.whiteSpace) { @@ -1726,6 +1725,7 @@ LibraryManager.library = { } var long_ = false; var half = false; + var quarter = false; var longLong = false; if (format[formatIndex] == 'l') { long_ = true; @@ -1737,6 +1737,10 @@ LibraryManager.library = { } else if (format[formatIndex] == 'h') { half = true; formatIndex++; + if (format[formatIndex] == 'h') { + quarter = true; + formatIndex++; + } } var type = format[formatIndex]; formatIndex++; @@ -1795,20 +1799,21 @@ LibraryManager.library = { var text = buffer.join(''); var argPtr = {{{ makeGetValue('varargs', 'argIndex', 'void*') }}}; argIndex += Runtime.getAlignSize('void*', null, true); + var base = 10; switch (type) { + case 'X': case 'x': + base = 16; case 'd': case 'u': case 'i': - if (half) { - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i16') }}}; + if (quarter) { + {{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i8') }}}; + } else if (half) { + {{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i16') }}}; } else if (longLong) { - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i64') }}}; + {{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i64') }}}; } else { - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 10)', 'i32') }}}; + {{{ makeSetValue('argPtr', 0, 'parseInt(text, base)', 'i32') }}}; } break; - case 'X': - case 'x': - {{{ makeSetValue('argPtr', 0, 'parseInt(text, 16)', 'i32') }}}; - break; case 'F': case 'f': case 'E': diff --git a/tests/core/test_sscanf_hex.in b/tests/core/test_sscanf_hex.in index d8175e827bec9..a05eb89043b56 100644 --- a/tests/core/test_sscanf_hex.in +++ b/tests/core/test_sscanf_hex.in @@ -1,7 +1,27 @@ -#include "stdio.h" +#include +#include +#include -int main() { +int main() +{ unsigned int a, b; sscanf("0x12AB 12AB", "%x %x", &a, &b); printf("%d %d\n", a, b); + + std::string hexstr("0102037F00FF"); + const char * cstr = hexstr.c_str(); + int len = hexstr.length() / 2; + char * tmp_data = new char[len]; + for(int i = 0; i < len; i++) + { + sscanf(cstr, "%2hhx", &tmp_data[i]); + cstr += 2 * sizeof(char); + } + + for (int j = 0; j < len; j++) + printf("%i, ", tmp_data[j]); + printf("\n"); + delete[] tmp_data; } + + diff --git a/tests/core/test_sscanf_hex.out b/tests/core/test_sscanf_hex.out index ac855044ced04..6e7f66aae9762 100644 --- a/tests/core/test_sscanf_hex.out +++ b/tests/core/test_sscanf_hex.out @@ -1 +1,2 @@ -4779 4779 \ No newline at end of file +4779 4779 +1, 2, 3, 127, 0, -1, From fee40ad3a5f44adc4b07f41c8f552949a20ce953 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 29 Apr 2014 17:06:52 -0700 Subject: [PATCH 49/67] testcase for fastcomp issue 32 --- tests/cases/redundantswitch_fastcomp.ll | 28 ++++++++++++++++++++++++ tests/cases/redundantswitch_fastcomp.txt | 2 ++ 2 files changed, 30 insertions(+) create mode 100644 tests/cases/redundantswitch_fastcomp.ll create mode 100644 tests/cases/redundantswitch_fastcomp.txt diff --git a/tests/cases/redundantswitch_fastcomp.ll b/tests/cases/redundantswitch_fastcomp.ll new file mode 100644 index 0000000000000..5b797ac8442ca --- /dev/null +++ b/tests/cases/redundantswitch_fastcomp.ll @@ -0,0 +1,28 @@ +target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:128-n32-S128" +target triple = "asmjs-unknown-emscripten" + +@.str = private constant [18 x i8] c"hello, world: %d\0A\00", align 1 + +declare i32 @printf(i8*, ...) + +define linkonce_odr i32 @main() align 2 { +entry: + %temp32 = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 5) + switch i32 %temp32, label %mid1 [ + i32 1000, label %mid1 + i32 1001, label %mid2 + i32 2000, label %finish + ] + +mid1: + br label %finish + +mid2: + br label %finish + +finish: ; preds = %555 + %last = phi i32 [0, %entry], [1, %mid1], [2, %mid2] + %a333c = call i32 (i8*, ...)* @printf(i8* getelementptr inbounds ([18 x i8]* @.str, i32 0, i32 0), i32 %last) + ret i32 0 +} + diff --git a/tests/cases/redundantswitch_fastcomp.txt b/tests/cases/redundantswitch_fastcomp.txt new file mode 100644 index 0000000000000..72084b0ca5112 --- /dev/null +++ b/tests/cases/redundantswitch_fastcomp.txt @@ -0,0 +1,2 @@ +hello, world: 5 +hello, world: 1 From 7da733906454466f4ae22d1a1541ea152f5025db Mon Sep 17 00:00:00 2001 From: Chad Austin Date: Tue, 29 Apr 2014 22:09:13 -0700 Subject: [PATCH 50/67] fix embind/asm.js in PRECISE_F32 mode --- src/embind/embind.js | 11 +++++++++-- system/include/emscripten/bind.h | 2 +- tests/test_core.py | 1 - 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index bb9793655b198..3eadb85f509ff 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -723,9 +723,16 @@ function requireFunction(signature, rawFunction) { // possibly allocate. var dc = asm['dynCall_' + signature]; if (dc === undefined) { - throwBindingError("No dynCall invoker for signature: " + signature); + // We will always enter this branch if the signature + // contains 'f' and PRECISE_F32 is not enabled. + // + // Try again, replacing 'f' with 'd'. + dc = asm['dynCall_' + signature.replace(/f/g, 'd')]; + if (dc === undefined) { + throwBindingError("No dynCall invoker for signature: " + signature); + } } - fp = asm['dynCall_' + signature].bind(undefined, rawFunction); + fp = dc.bind(undefined, rawFunction); } else { fp = FUNCTION_TABLE[rawFunction]; } diff --git a/system/include/emscripten/bind.h b/system/include/emscripten/bind.h index 699e834bc76e9..eede07553a7fb 100644 --- a/system/include/emscripten/bind.h +++ b/system/include/emscripten/bind.h @@ -330,7 +330,7 @@ namespace emscripten { template<> struct SignatureCode { static constexpr char get() { - return 'd'; + return 'f'; } }; diff --git a/tests/test_core.py b/tests/test_core.py index d25a61be84390..1f698687a7842 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -5657,7 +5657,6 @@ def test_embind(self): def test_embind_2(self): if self.emcc_args is None: return self.skip('requires emcc') - if self.run_name == 'asm2f': return self.skip('embind/asm.js not compatible with PRECISE_F32 because it changes signature strings') if self.run_name == 'slow2asm': return self.skip('embind/asm.js requires fastcomp') Building.COMPILER_TEST_OPTS += ['--bind', '--post-js', 'post.js'] open('post.js', 'w').write(''' From a395d0e4e3027c9facef4450149bbdd0f8520145 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 30 Apr 2014 11:58:32 +0300 Subject: [PATCH 51/67] Rename FS tracking delegate did* to on* as suggested in https://github.com/kripken/emscripten/pull/1673 . --- src/library_fs.js | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/src/library_fs.js b/src/library_fs.js index e0b73db8f9583..5f7f1dea43f91 100644 --- a/src/library_fs.js +++ b/src/library_fs.js @@ -739,11 +739,9 @@ mergeInto(LibraryManager.library, { FS.hashAddNode(old_node); } try { - if (FS.trackingDelegate['didMovePath']) { - FS.trackingDelegate['didMovePath'](old_path, new_path); - } + if (FS.trackingDelegate['onMovePath']) FS.trackingDelegate['onMovePath'](old_path, new_path); } catch(e) { - console.log("FS.trackingDelegate['didMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message); + console.log("FS.trackingDelegate['onMovePath']('"+old_path+"', '"+new_path+"') threw an exception: " + e.message); } }, rmdir: function(path) { @@ -771,11 +769,9 @@ mergeInto(LibraryManager.library, { parent.node_ops.rmdir(parent, name); FS.destroyNode(node); try { - if (FS.trackingDelegate['didDeletePath']) { - FS.trackingDelegate['didDeletePath'](path); - } + if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path); } catch(e) { - console.log("FS.trackingDelegate['didDeletePath']('"+path+"') threw an exception: " + e.message); + console.log("FS.trackingDelegate['onDeletePath']('"+path+"') threw an exception: " + e.message); } }, readdir: function(path) { @@ -813,11 +809,9 @@ mergeInto(LibraryManager.library, { parent.node_ops.unlink(parent, name); FS.destroyNode(node); try { - if (FS.trackingDelegate['didDeletePath']) { - FS.trackingDelegate['didDeletePath'](path); - } + if (FS.trackingDelegate['onDeletePath']) FS.trackingDelegate['onDeletePath'](path); } catch(e) { - console.log("FS.trackingDelegate['didDeletePath']('"+path+"') threw an exception: " + e.message); + console.log("FS.trackingDelegate['onDeletePath']('"+path+"') threw an exception: " + e.message); } }, readlink: function(path) { @@ -1014,16 +1008,18 @@ mergeInto(LibraryManager.library, { } } try { - if (FS.trackingDelegate['didOpenFile']) { + if (FS.trackingDelegate['onOpenFile']) { var trackingFlags = 0; - if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}) + if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_WRONLY') }}}) { trackingFlags |= FS.tracking.openFlags.READ; - if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}) + } + if ((flags & {{{ cDefine('O_ACCMODE') }}}) !== {{{ cDefine('O_RDONLY') }}}) { trackingFlags |= FS.tracking.openFlags.WRITE; - FS.trackingDelegate['didOpenFile'](path, trackingFlags); + } + FS.trackingDelegate['onOpenFile'](path, trackingFlags); } } catch(e) { - console.log("FS.trackingDelegate['didOpenFile']('"+path+"', flags) threw an exception: " + e.message); + console.log("FS.trackingDelegate['onOpenFile']('"+path+"', flags) threw an exception: " + e.message); } return stream; }, @@ -1095,11 +1091,9 @@ mergeInto(LibraryManager.library, { var bytesWritten = stream.stream_ops.write(stream, buffer, offset, length, position, canOwn); if (!seeking) stream.position += bytesWritten; try { - if (stream.path && FS.trackingDelegate['didWriteToFile']) { - FS.trackingDelegate['didWriteToFile'](stream.path); - } + if (stream.path && FS.trackingDelegate['onWriteToFile']) FS.trackingDelegate['onWriteToFile'](stream.path); } catch(e) { - console.log("FS.trackingDelegate['didWriteToFile']('"+path+"') threw an exception: " + e.message); + console.log("FS.trackingDelegate['onWriteToFile']('"+path+"') threw an exception: " + e.message); } return bytesWritten; }, From 439612cf923b70e87b4c4e739b90ec1df23ddda3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Wed, 30 Apr 2014 12:30:26 +0300 Subject: [PATCH 52/67] Add unit test for FS.trackingDelegate operation. --- tests/fs/test_trackingdelegate.c | 39 ++++++++++++++++++++++++++++++ tests/fs/test_trackingdelegate.out | 9 +++++++ tests/test_core.py | 5 ++++ 3 files changed, 53 insertions(+) create mode 100644 tests/fs/test_trackingdelegate.c create mode 100644 tests/fs/test_trackingdelegate.out diff --git a/tests/fs/test_trackingdelegate.c b/tests/fs/test_trackingdelegate.c new file mode 100644 index 0000000000000..6cdece7277176 --- /dev/null +++ b/tests/fs/test_trackingdelegate.c @@ -0,0 +1,39 @@ +#include +#include +#include + +int main() { + + EM_ASM( + FS.trackingDelegate['willMovePath'] = function(oldpath, newpath) { + Module.print('About to move "' + oldpath + '" to "' + newpath + '"'); + }; + FS.trackingDelegate['onMovePath'] = function(oldpath, newpath) { + Module.print('Moved "' + oldpath + '" to "' + newpath + '"'); + }; + FS.trackingDelegate['willDeletePath'] = function(path) { + Module.print('About to delete "' + path + '"'); + }; + FS.trackingDelegate['onDeletePath'] = function(path) { + Module.print('Deleted "' + path + '"'); + }; + FS.trackingDelegate['onOpenFile'] = function(path, flags) { + Module.print('Opened "' + path + '" with flags ' + flags); + }; + FS.trackingDelegate['onWriteToFile'] = function(path) { + Module.print('Wrote to file "' + path + '"'); + }; + ); + + FILE *file; + file = fopen("/file.txt", "w"); + fputs("hello!", file); + fclose(file); + rename("/file.txt", "/renamed.txt"); + file = fopen("/renamed.txt", "r"); + char str[256] = {}; + fgets(str, 255, file); + printf("File read returned '%s'\n", str); + fclose(file); + remove("/renamed.txt"); +} diff --git a/tests/fs/test_trackingdelegate.out b/tests/fs/test_trackingdelegate.out new file mode 100644 index 0000000000000..b3c941c20fee3 --- /dev/null +++ b/tests/fs/test_trackingdelegate.out @@ -0,0 +1,9 @@ +Opened "/file.txt" with flags 2 +Wrote to file "/file.txt" +About to move "/file.txt" to "/renamed.txt" +Moved "/file.txt" to "/renamed.txt" +Opened "/renamed.txt" with flags 1 +File read returned 'hello!' +Wrote to file "/dev/tty" +About to delete "/renamed.txt" +Deleted "/renamed.txt" diff --git a/tests/test_core.py b/tests/test_core.py index d25a61be84390..c9784ec90b0a6 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -4252,6 +4252,11 @@ def test_fs_nodefs_rw(self): src = open(path_from_root('tests', 'fs', 'test_nodefs_rw.c'), 'r').read() self.do_run(src, 'success', force_c=True, js_engines=[NODE_JS]) + def test_fs_trackingdelegate(self): + src = path_from_root('tests', 'fs', 'test_trackingdelegate.c') + out = path_from_root('tests', 'fs', 'test_trackingdelegate.out') + self.do_run_from_file(src, out) + def test_unistd_access(self): self.clear() if not self.is_emscripten_abi(): return self.skip('asmjs-unknown-emscripten needed for inline js') From 9f99c740d82ab87e0febb76ba8231e5efafdaf48 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 30 Apr 2014 13:19:13 -0700 Subject: [PATCH 53/67] allow registerizeHarder with outlining --- emcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc b/emcc index d2de63fc1fb4f..0be81034a1ffc 100755 --- a/emcc +++ b/emcc @@ -1746,7 +1746,7 @@ try: js_optimizer_extra_info['sizeToOutline'] = shared.Settings.OUTLINING_LIMIT if opt_level >= 2 and (not closure or shared.Settings.ASM_JS) and shared.Settings.RELOOP and debug_level < 3: - if shared.Settings.ASM_JS and opt_level >= 3 and shared.Settings.OUTLINING_LIMIT == 0: + if shared.Settings.ASM_JS and opt_level >= 3: js_optimizer_queue += ['registerizeHarder'] else: js_optimizer_queue += ['registerize'] From d7a26a5017f38f5d4dde574fe472d7190609c51d Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 30 Apr 2014 13:21:04 -0700 Subject: [PATCH 54/67] disable test_sscanf_hex in s_x_x --- tests/test_core.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_core.py b/tests/test_core.py index d25a61be84390..4c19afdaeff37 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -3905,6 +3905,8 @@ def test_sscanf_caps(self): self.do_run_from_file(src, output) def test_sscanf_hex(self): + if Settings.USE_TYPED_ARRAYS != 2: return self.skip('requires ta2') + test_path = path_from_root('tests', 'core', 'test_sscanf_hex') src, output = (test_path + s for s in ('.in', '.out')) From 63f913cc533e20cea584d2407de78c933d063b67 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Wed, 30 Apr 2014 13:26:47 -0700 Subject: [PATCH 55/67] fix return code when precompiling headers --- emcc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emcc b/emcc index 0be81034a1ffc..b9d747137da90 100755 --- a/emcc +++ b/emcc @@ -1370,7 +1370,7 @@ try: args += ['-o', specified_target] logging.debug("running (for precompiled headers): " + call + ' ' + ' '.join(args)) execute([call] + args) # let compiler frontend print directly, so colors are saved (PIPE kills that) - sys.exit(1) + sys.exit(0) def get_bitcode_file(input_file): if final_suffix not in JS_CONTAINING_SUFFIXES: From 0c96ee7315fda2dba5f2fde084cd31fa227dfb72 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 May 2014 10:43:12 -0700 Subject: [PATCH 56/67] switch other.test_embind to fastcomp and only ASM_JS --- tests/test_other.py | 32 ++++++++++++++------------------ 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index 4560ac6ec26e8..779335bbbcc40 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1879,24 +1879,20 @@ def test_scons(self): # also incidentally tests c++11 integration in llvm 3.1 assert 'If you see this - the world is all right!' in output def test_embind(self): - def nonfc(): - for args, fail in [ - ([], True), # without --bind, we fail - (['--bind'], False), - (['--bind', '-O1'], False), - (['--bind', '-O2'], False), - (['--bind', '-O1', '-s', 'ASM_JS=0'], False), - (['--bind', '-O2', '-s', 'ASM_JS=0'], False) - ]: - print args, fail - self.clear() - try_delete(self.in_dir('a.out.js')) - Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate() - assert os.path.exists(self.in_dir('a.out.js')) == (not fail) - if not fail: - output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True) - assert "FAIL" not in output, output - nonfastcomp(nonfc) + for args, fail in [ + ([], True), # without --bind, we fail + (['--bind'], False), + (['--bind', '-O1'], False), + (['--bind', '-O2'], False), + ]: + print args, fail + self.clear() + try_delete(self.in_dir('a.out.js')) + Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate() + assert os.path.exists(self.in_dir('a.out.js')) == (not fail) + if not fail: + output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True) + assert "FAIL" not in output, output def test_llvm_nativizer(self): try: From f25f2fa17a59182b34e5f68f725ef14b7c7f38a6 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 May 2014 11:05:04 -0700 Subject: [PATCH 57/67] document and assert on only one browser main loop at a time --- src/library_browser.js | 2 ++ system/include/emscripten/emscripten.h | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/library_browser.js b/src/library_browser.js index 5cc7e1229edf5..44e8c47331c94 100644 --- a/src/library_browser.js +++ b/src/library_browser.js @@ -889,6 +889,8 @@ mergeInto(LibraryManager.library, { emscripten_set_main_loop: function(func, fps, simulateInfiniteLoop, arg) { Module['noExitRuntime'] = true; + assert(!Browser.mainLoop.scheduler, 'there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one, if you want to'); + Browser.mainLoop.runner = function Browser_mainLoop_runner() { if (ABORT) return; if (Browser.mainLoop.queue.length > 0) { diff --git a/system/include/emscripten/emscripten.h b/system/include/emscripten/emscripten.h index 73836018fc182..362a1337548af 100644 --- a/system/include/emscripten/emscripten.h +++ b/system/include/emscripten/emscripten.h @@ -121,7 +121,11 @@ extern void emscripten_async_load_script(const char *script, void (*onload)(void * * If you want your main loop function to receive a void* * argument, use emscripten_set_main_loop_arg. - + * + * There can be only *one* main loop function at a time. You + * can cancel the current one and set another, if you want to + * change it. + * * @simulate_infinite_loop If true, this function will throw an * exception in order to stop execution of the caller. This * will lead to the main loop being entered instead of code From 9fd0afa69c6c088fb80c2e2611cc45301fdc99ef Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 May 2014 11:32:21 -0700 Subject: [PATCH 58/67] use a case-insensitive regex in strptime; fixes #2324 --- src/library.js | 2 +- tests/core/test_strptime_tm.in | 31 +++++++++++++++++++++++++++++++ tests/core/test_strptime_tm.out | 19 ++++++++++++++++++- 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/library.js b/src/library.js index c8c5a0ff82916..751cc6d0ce8b3 100644 --- a/src/library.js +++ b/src/library.js @@ -5782,7 +5782,7 @@ LibraryManager.library = { pattern = pattern.replace(new RegExp('\\%'+pattern[i+1], 'g'), ''); } - var matches = new RegExp('^'+pattern).exec(Pointer_stringify(buf)) + var matches = new RegExp('^'+pattern, "i").exec(Pointer_stringify(buf)) // Module['print'](Pointer_stringify(buf)+ ' is matched by '+((new RegExp('^'+pattern)).source)+' into: '+JSON.stringify(matches)); function initDate() { diff --git a/tests/core/test_strptime_tm.in b/tests/core/test_strptime_tm.in index 93cdb1d5f85e8..2cccfa5561ab6 100644 --- a/tests/core/test_strptime_tm.in +++ b/tests/core/test_strptime_tm.in @@ -2,6 +2,15 @@ #include #include +void ReadMonth(const char *month) +{ + tm value = {0}; + if(strptime(month, "%b", &value)) + { + printf("%s: %d\n", month, value.tm_mon); + } +} + int main() { struct tm tm; char *ptr = strptime("17410105012000", "%H%M%S%d%m%Y", &tm); @@ -24,4 +33,26 @@ int main() { : "ERR")))))), tm.tm_mon + 1, tm.tm_mday, tm.tm_year + 1900, tm.tm_hour, tm.tm_min, tm.tm_sec); + + printf("\n"); + + ReadMonth("jan"); + ReadMonth("january"); + ReadMonth("feb"); + ReadMonth("february"); + ReadMonth("march"); + ReadMonth("mar"); + ReadMonth("april"); + ReadMonth("may"); + ReadMonth("may"); + ReadMonth("june"); + ReadMonth("jul"); + ReadMonth("august"); + ReadMonth("september"); + ReadMonth("oct"); + ReadMonth("nov"); + ReadMonth("november"); + ReadMonth("december"); + + return 0; } diff --git a/tests/core/test_strptime_tm.out b/tests/core/test_strptime_tm.out index 32c321f706d21..c241cbddc384f 100644 --- a/tests/core/test_strptime_tm.out +++ b/tests/core/test_strptime_tm.out @@ -1 +1,18 @@ -OK: Wed, 1/5/2000 17:41:1 \ No newline at end of file +OK: Wed, 1/5/2000 17:41:1 +jan: 0 +january: 0 +feb: 1 +february: 1 +march: 2 +mar: 2 +april: 3 +may: 4 +may: 4 +june: 5 +jul: 6 +august: 7 +september: 8 +oct: 9 +nov: 10 +november: 10 +december: 11 From 2308587a85de571844e71e574fcc63c7955d6012 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Fri, 2 May 2014 13:48:11 -0700 Subject: [PATCH 59/67] handle floats in jsCall properly; fixes asm2f.test_embind_2 --- emscripten.py | 3 ++- tools/shared.py | 9 +++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/emscripten.py b/emscripten.py index 835b1ec97bf2e..bf55ee43f495c 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1076,8 +1076,9 @@ def keyfunc(other): } ''' % (sig, ',' if len(sig) > 1 else '', args, arg_coercions, ret)) + ffi_args = ','.join([shared.JS.make_coercion('a' + str(i), sig[i], settings, ffi_arg=True) for i in range(1, len(sig))]) for i in range(settings['RESERVED_FUNCTION_POINTERS']): - jsret = ('return ' if sig[0] != 'v' else '') + shared.JS.make_coercion('jsCall(%d%s%s)' % (i, ',' if coerced_args else '', coerced_args), sig[0], settings) + jsret = ('return ' if sig[0] != 'v' else '') + shared.JS.make_coercion('jsCall(%d%s%s)' % (i, ',' if ffi_args else '', ffi_args), sig[0], settings, ffi_result=True) function_tables_impls.append(''' function jsCall_%s_%s(%s) { %s diff --git a/tools/shared.py b/tools/shared.py index 82bdd98b917d4..826baa832caba 100644 --- a/tools/shared.py +++ b/tools/shared.py @@ -1650,12 +1650,17 @@ def make_initializer(sig, settings=None): return '+0' @staticmethod - def make_coercion(value, sig, settings=None): + def make_coercion(value, sig, settings=None, ffi_arg=False, ffi_result=False): settings = settings or Settings if sig == 'i': return value + '|0' elif sig == 'f' and settings.get('PRECISE_F32'): - return 'Math_fround(' + value + ')' + if ffi_arg: + return '+Math_fround(' + value + ')' + elif ffi_result: + return 'Math_fround(+(' + value + '))' + else: + return 'Math_fround(' + value + ')' elif sig == 'd' or sig == 'f': return '+' + value else: From 77aa2a72f38d73e71eef48cacfe72cce33fc7201 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 3 May 2014 12:09:37 -0700 Subject: [PATCH 60/67] emit a global const for Math_fround(0) to avoid function call overheads in the fround polyfill --- emcc | 2 +- emscripten.py | 2 +- src/settings.js | 9 ++- tools/js-optimizer.js | 55 ++++++++++--------- tools/test-js-optimizer-asm-pre-f32.js | 8 ++- tools/test-js-optimizer-asm-pre-output-f32.js | 8 ++- 6 files changed, 54 insertions(+), 30 deletions(-) diff --git a/emcc b/emcc index b9d747137da90..1629f5c74fa78 100755 --- a/emcc +++ b/emcc @@ -1727,7 +1727,7 @@ try: # with commaified code breaks late aggressive variable elimination) if shared.Settings.SIMPLIFY_IFS and (debug_level == 0 or profiling) and shared.Settings.OUTLINING_LIMIT == 0: js_optimizer_queue += ['simplifyIfs'] - if opt_level >= 3 and shared.Settings.PRECISE_F32: js_optimizer_queue += ['optimizeFrounds'] + if shared.Settings.PRECISE_F32: js_optimizer_queue += ['optimizeFrounds'] if closure and not shared.Settings.ASM_JS: flush_js_optimizer_queue() diff --git a/emscripten.py b/emscripten.py index bf55ee43f495c..16f9eb330f74a 100755 --- a/emscripten.py +++ b/emscripten.py @@ -1165,7 +1165,7 @@ def math_fix(g): var nan = +env.NaN, inf = +env.Infinity; var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0; ''' + ''.join([''' - var tempRet%d = 0;''' % i for i in range(10)]) + '\n' + asm_global_funcs] + [' var tempFloat = %s;\n' % ('Math_fround(0)' if settings.get('PRECISE_F32') else '0.0')] + [''' + var tempRet%d = 0;''' % i for i in range(10)]) + '\n' + asm_global_funcs] + [' var tempFloat = %s;\n' % ('Math_fround(0)' if settings.get('PRECISE_F32') else '0.0')] + ([' const f0 = Math_fround(0);\n'] if settings.get('PRECISE_F32') else []) + [''' // EMSCRIPTEN_START_FUNCS function stackAlloc(size) { size = size|0; diff --git a/src/settings.js b/src/settings.js index a9a7242539d9f..3289eace66967 100644 --- a/src/settings.js +++ b/src/settings.js @@ -124,13 +124,20 @@ var PRECISE_I32_MUL = 1; // If enabled, i32 multiplication is done with full pre var PRECISE_F32 = 0; // 0: Use JS numbers for floating-point values. These are 64-bit and do not model C++ // floats exactly, which are 32-bit. // 1: Model C++ floats precisely, using Math.fround, polyfilling when necessary. This - // can be slow if the polyfill is used on heavy float32 computation. + // can be slow if the polyfill is used on heavy float32 computation. See note on + // browser support below. // 2: Model C++ floats precisely using Math.fround if available in the JS engine, otherwise // use an empty polyfill. This will have much less of a speed penalty than using the full // polyfill in cases where engine support is not present. In addition, we can // remove the empty polyfill calls themselves on the client when generating html, // which should mean that this gives you the best of both worlds of 0 and 1, and is // therefore recommended. + // XXX Note: To optimize float32-using code, we use the 'const' keyword in the emitted + // code. This allows us to avoid unnecessary calls to Math.fround, which would + // slow down engines not yet supporting that function. 'const' is present in + // all modern browsers, including Firefox, Chrome and Safari, but in IE is only + // present in IE11 and above. Therefore if you need to support legacy versions of + // IE, you should not enable PRECISE_F32 1 or 2. var SIMD = 0; // Whether to emit SIMD code ( https://github.com/johnmccutchan/ecmascript_simd ) var CLOSURE_COMPILER = 0; // Whether closure compiling is being run on this output diff --git a/tools/js-optimizer.js b/tools/js-optimizer.js index db85965dca952..2914b6e849e33 100644 --- a/tools/js-optimizer.js +++ b/tools/js-optimizer.js @@ -1342,13 +1342,21 @@ var ASM_DOUBLE = 1; var ASM_FLOAT = 2; var ASM_NONE = 3; -function detectAsmCoercion(node, asmInfo) { +var ASM_FLOAT_ZERO = null; // TODO: share the entire node? + +function detectAsmCoercion(node, asmInfo, inVarDef) { // for params, +x vs x|0, for vars, 0.0 vs 0 if (node[0] === 'num' && node[1].toString().indexOf('.') >= 0) return ASM_DOUBLE; if (node[0] === 'unary-prefix') return ASM_DOUBLE; if (node[0] === 'call' && node[1][0] === 'name' && node[1][1] === 'Math_fround') return ASM_FLOAT; if (asmInfo && node[0] == 'name') return getAsmType(node[1], asmInfo); - if (node[0] === 'name') return ASM_NONE; + if (node[0] === 'name') { + if (!inVarDef) return ASM_NONE; + // We are in a variable definition, where Math_fround(0) optimized into a global constant becomes f0 = Math_fround(0) + if (!ASM_FLOAT_ZERO) ASM_FLOAT_ZERO = node[1]; + else assert(ASM_FLOAT_ZERO === node[1]); + return ASM_FLOAT; + } return ASM_INT; } @@ -1366,7 +1374,13 @@ function makeAsmVarDef(v, type) { switch (type) { case ASM_INT: return [v, ['num', 0]]; case ASM_DOUBLE: return [v, ['unary-prefix', '+', ['num', 0]]]; - case ASM_FLOAT: return [v, ['call', ['name', 'Math_fround'], [['num', 0]]]]; + case ASM_FLOAT: { + if (ASM_FLOAT_ZERO) { + return [v, ['name', ASM_FLOAT_ZERO]]; + } else { + return [v, ['call', ['name', 'Math_fround'], [['num', 0]]]]; + } + } default: throw 'wha? ' + JSON.stringify([node, type]) + new Error().stack; } } @@ -1409,9 +1423,7 @@ function normalizeAsm(func) { var name = v[0]; var value = v[1]; if (!(name in data.vars)) { - assert(value[0] === 'num' || (value[0] === 'unary-prefix' && value[2][0] === 'num') // must be valid coercion no-op - || (value[0] === 'call' && value[1][0] === 'name' && value[1][1] === 'Math_fround')); - data.vars[name] = detectAsmCoercion(value); + data.vars[name] = detectAsmCoercion(value, null, true); v.length = 1; // make an un-assigning var } else { assert(j === 0, 'cannot break in the middle'); @@ -1425,22 +1437,6 @@ function normalizeAsm(func) { traverse(stats[i], function(node, type) { if (type === 'var') { assert(0, 'should be no vars to fix! ' + func[1] + ' : ' + JSON.stringify(node)); - /* - for (var j = 0; j < node[1].length; j++) { - var v = node[1][j]; - var name = v[0]; - var value = v[1]; - if (!(name in data.vars)) { - if (value[0] != 'name') { - data.vars[name] = detectAsmCoercion(value); // detect by coercion - } else { - var origin = value[1]; - data.vars[name] = data.vars[origin] || ASM_INT; // detect by origin variable, or assume int for non-locals - } - } - } - unVarify(node[1], node); - */ } else if (type === 'call' && node[1][0] === 'function') { assert(!node[1][1]); // anonymous functions only data.inlines.push(node[1]); @@ -3721,7 +3717,7 @@ function minifyGlobals(ast) { var first = true; // do not minify initial 'var asm =' // find the globals traverse(ast, function(node, type) { - if (type === 'var') { + if (type === 'var' || type === 'const') { if (first) { first = false; return; @@ -4971,10 +4967,19 @@ function safeHeap(ast) { function optimizeFrounds(ast) { // collapse fround(fround(..)), which can happen due to elimination + // also emit f0 instead of fround(0) (except in returns) + var inReturn = false; function fix(node) { + if (node[0] === 'return') inReturn = true; traverseChildren(node, fix); - if (node[0] === 'call' && node[1][0] === 'name' && node[1][1] === 'Math_fround' && node[2][0][0] === 'call' && node[2][0][1][0] === 'name' && node[2][0][1][1] === 'Math_fround') { - return node[2][0]; + if (node[0] === 'return') inReturn = false; + if (node[0] === 'call' && node[1][0] === 'name' && node[1][1] === 'Math_fround') { + var arg = node[2][0]; + if (arg[0] === 'num') { + if (!inReturn && arg[1] === 0) return ['name', 'f0']; + } else if (arg[0] === 'call' && arg[1][0] === 'name' && arg[1][1] === 'Math_fround') { + return arg; + } } } traverseChildren(ast, fix); diff --git a/tools/test-js-optimizer-asm-pre-f32.js b/tools/test-js-optimizer-asm-pre-f32.js index 5471deeb80c20..be515b3631ce0 100644 --- a/tools/test-js-optimizer-asm-pre-f32.js +++ b/tools/test-js-optimizer-asm-pre-f32.js @@ -14,4 +14,10 @@ function dupe() { x = Math_fround(Math_fround(Math_fround(x))); x = Math_fround(Math_fround(Math_fround(Math_fround(x)))); } -// EMSCRIPTEN_GENERATED_FUNCTIONS: ["badf", "badf2", "dupe"] +function zeros(x) { + x = Math_fround(x); + var y = Math_fround(0); + print(Math_fround(y) + Math_fround(0)); + return Math_fround(0); // return needs to stay as is +} +// EMSCRIPTEN_GENERATED_FUNCTIONS: ["badf", "badf2", "dupe", "zeros"] diff --git a/tools/test-js-optimizer-asm-pre-output-f32.js b/tools/test-js-optimizer-asm-pre-output-f32.js index 19059619e17fb..f0f2d0daea3e2 100644 --- a/tools/test-js-optimizer-asm-pre-output-f32.js +++ b/tools/test-js-optimizer-asm-pre-output-f32.js @@ -4,7 +4,7 @@ function badf() { HEAP32[$gep23_asptr >> 2] = $9; } function badf2() { - var $9 = Math_fround(0); + var $9 = f0; $9 = Math_fround($8); HEAPF32[$gep23_asptr >> 2] = $9; } @@ -14,4 +14,10 @@ function dupe() { x = Math_fround(x); x = Math_fround(x); } +function zeros(x) { + x = Math_fround(x); + var y = f0; + print(Math_fround(y) + f0); + return Math_fround(0); +} From abad7b6e580a7f0f2ff01f26f0e2814eb05ab815 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sat, 3 May 2014 16:51:26 -0700 Subject: [PATCH 61/67] add f0 in non-fastcomp when needed --- emscripten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index 16f9eb330f74a..f03a81f0626dc 100755 --- a/emscripten.py +++ b/emscripten.py @@ -584,7 +584,7 @@ def math_fix(g): var undef = 0; var tempInt = 0, tempBigInt = 0, tempBigIntP = 0, tempBigIntS = 0, tempBigIntR = 0.0, tempBigIntI = 0, tempBigIntD = 0, tempValue = 0, tempDouble = 0.0; ''' + ''.join([''' - var tempRet%d = 0;''' % i for i in range(10)]) + '\n' + asm_global_funcs] + [' var tempFloat = %s;\n' % ('Math_fround(0)' if settings.get('PRECISE_F32') else '0.0')] + [''' + var tempRet%d = 0;''' % i for i in range(10)]) + '\n' + asm_global_funcs] + [' var tempFloat = %s;\n' % ('Math_fround(0)' if settings.get('PRECISE_F32') else '0.0')] + ([' const f0 = Math_fround(0);\n'] if settings.get('PRECISE_F32') else []) + [''' // EMSCRIPTEN_START_FUNCS function stackAlloc(size) { size = size|0; From f2e20defa5029ba946fab94c79ff23845bed61f0 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Sun, 4 May 2014 14:56:19 -0700 Subject: [PATCH 62/67] add more slack to glgears reftests --- tests/test_browser.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_browser.py b/tests/test_browser.py index c06f11ac7ef09..b85c6e1c6a8a0 100644 --- a/tests/test_browser.py +++ b/tests/test_browser.py @@ -1300,7 +1300,7 @@ def test_chunked_synchronous_xhr(self): time.sleep(2) def test_glgears(self): - self.btest('hello_world_gles.c', reference='gears.png', reference_slack=1, + self.btest('hello_world_gles.c', reference='gears.png', reference_slack=2, args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html', message='You should see animating gears.') @@ -1322,7 +1322,7 @@ def test_fulles2_sdlproc(self): self.btest('full_es2_sdlproc.c', '1', args=['-s', 'GL_TESTING=1', '-DHAVE_BUILTIN_SINCOS', '-s', 'FULL_ES2=1']) def test_glgears_deriv(self): - self.btest('hello_world_gles_deriv.c', reference='gears.png', reference_slack=1, + self.btest('hello_world_gles_deriv.c', reference='gears.png', reference_slack=2, args=['-DHAVE_BUILTIN_SINCOS'], outfile='something.html', message='You should see animating gears.') with open('something.html') as f: From 7b832d4accb054c48495167108323628419ae358 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 5 May 2014 12:29:53 +0300 Subject: [PATCH 63/67] Added first version of tools/ffdb.py, an application that can be used to operate Firefox OS devices from the command line. --- tools/ffdb.py | 342 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100755 tools/ffdb.py diff --git a/tools/ffdb.py b/tools/ffdb.py new file mode 100755 index 0000000000000..c22fd9dbd9930 --- /dev/null +++ b/tools/ffdb.py @@ -0,0 +1,342 @@ +#!/usr/bin/env python + +import socket, json, sys, uuid, datetime, time, logging, cgi, zipfile, os, tempfile, atexit, subprocess + +LOG_VERBOSE = False # Verbose printing enabled with --verbose +HOST = 'localhost' # The remote host to connect to the B2G device +PORT = 6000 # The port on the host on which the B2G device listens on +b2g_socket = None # Python socket object for the active connection to the B2G device +read_queue = '' # Inbound queue of partial data read so far from the device + +webappsActorName = None + +def sizeof_fmt(num): + for x in ['bytes','KB','MB','GB']: + if num < 1024.0: + return "%3.1f%s" % (num, x) + num /= 1024.0 + return "%3.1f%s" % (num, 'TB') + +def zipdir(path, zipfilename): + zipf = zipfile.ZipFile(zipfilename, 'w') + files_to_compress = [] + for root, dirs, files in os.walk(path): + for file in files: + files_to_compress += [(root, file)] + + n = 1 + for tuple in files_to_compress: + (root, file) = tuple + filename = os.path.join(root, file) + filesize = os.path.getsize(filename) + print 'Compressing ' + str(n) + '/' + str(len(files_to_compress)) + ': "' + os.path.relpath(filename, path) + '" (' + sizeof_fmt(filesize) + ')...' + n += 1 + zipf.write(os.path.join(root, file)) + zipf.close() + print 'Done. ' + +# Returns given log message formatted to be outputted on a HTML page. +def format_html(msg): + if not msg.endswith('\n'): + msg += '\n' + msg = cgi.escape(msg) + msg = msg.replace('\r\n', '
').replace('\n', '
') + return msg + +# Prints a verbose log message to stdout channel. Only shown if run with --verbose. +def logv(msg): + if LOG_VERBOSE: + sys.stdout.write(format_html(msg)) + sys.stdout.flush() + +# Reads data from the socket, and tries to parse what we have got so far as a JSON message. +# The messages are of form "bytelength:{jsondict}", where bytelength tells how many bytes +# there are in the data that comes after the colon. +# Returns a JSON dictionary of the received message. +def read_b2g_response(): + global read_queue, b2g_socket + read_queue += b2g_socket.recv(65536*2) + while ':' in read_queue: + semicolon = read_queue.index(':') + payload_len = int(read_queue[:semicolon]) + if semicolon+1+payload_len > len(read_queue): + read_queue += b2g_socket.recv(65536*2) + continue + payload = read_queue[semicolon+1:semicolon+1+payload_len] + read_queue = read_queue[semicolon+1+payload_len:] + logv('Read a message of size ' + str(payload_len) + 'b from socket.') + payload = json.loads(payload) + return payload + +# Sends a command to the B2G device and waits for the response and returns it as a JSON dict. +def send_b2g_cmd(to, cmd, data = {}): + global b2g_socket + msg = { 'to': to, 'type': cmd} + msg = dict(msg.items() + data.items()) + msg = json.dumps(msg, encoding='latin-1') + msg = msg.replace('\\\\', '\\') + msg = str(len(msg))+':'+msg + logv('Sending cmd:' + cmd + ' to:' + to) + b2g_socket.sendall(msg) + return read_b2g_response() + +def escape_bytes(b): + return str(b) + +# Sends a data fragment of a packaged app upload. This is a special-case version of the send_b2g_cmd +# command optimized for performance. +def send_b2g_data_chunk(to, data_blob): + byte_str = [] + e = '\u0000' + # '"' == 34 + # '\' == 92 + i = 0 + while i < len(data_blob): + o = ord(data_blob[i]) +# if o == 34 or o == 92 or o >= 128 or o <= 32:#o <= 32 or o >= 36:# or o == ord('\\'): + if o <= 34 or o >= 128 or o == 92: + c = hex(o)[2:] + byte_str += e[:-len(c)] + c + else: + byte_str += data_blob[i] + i += 1 + message = '{"to":"'+to+'","type":"chunk","chunk":"' + ''.join(byte_str) + '"}' + message = str(len(message)) + ':' + message + b2g_socket.sendall(message) + +# Queries the device for a list of all installed apps. +def b2g_get_appslist(): + global webappsActorName + apps = send_b2g_cmd(webappsActorName, 'getAll') + return apps['apps'] + +# Queries the device for a list of all currently running apps. +def b2g_get_runningapps(): + global webappsActorName + apps = send_b2g_cmd(webappsActorName, 'listRunningApps') + return apps['apps'] # Returns manifestURLs of all running apps + +def print_applist(applist, running_app_manifests, print_removable): + num_printed = 0 + for app in applist: + if print_removable or app['removable']: # Print only removable apps unless --all is specified, skip the built-in apps that can't be uninstalled. + if 'manifest' in app and 'version' in app['manifest']: + version = " version '" + app['manifest']['version'] + "'" + else: + version = '' + if app['manifestURL'] in running_app_manifests: + version += ' RUNNING' + print ' ' + str(app['localId']) + ': "' + app['name'] + '"' + version + num_printed += 1 + return num_printed + +def main(): + global b2g_socket, webappsActorName + if len(sys.argv) < 2 or '--help' in sys.argv or 'help' in sys.argv or '-v' in sys.argv: + print '''Firefox OS Debug Bridge, a tool for automating FFOS device tasks from the command line. + + Usage: ffdb.py , where command is one of: + + list [--running] [--all]: Prints out the user applications installed on the device. + If --running is passed, only the currently opened apps are shown. + If --all is specified, then also uninstallable system applications are listed. + launch : Starts the given application. If already running, brings to front. + close : Terminates the execution of the given application. + uninstall : Removes the given application from the device. + install : Uploads and installs a packaged app that resides in the given local directory. + may either refer to a directory containing a packaged app, or to a prepackaged zip file. + log [--clear]: Starts a persistent log listener that reads web console messages from the given application. + If --clear is passed, the message log for that application is cleared instead. + navigate : Opens the given web page in the B2G browser. + + In the above, whenever a command requires an to be specified, either the human-readable name, + localId or manifestURL of the application can be used.''' + + sys.exit(0) + + b2g_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + try: + b2g_socket.connect((HOST, PORT)) + except Exception, e: + if e[0] == 61: # Connection refused + if HOST == 'localhost' or HOST == '127.0.0.1': + cmd = ['adb', 'forward', 'tcp:'+str(PORT), 'localfilesystem:/data/local/debugger-socket'] + print 'Connection to ' + HOST + ':' + str(PORT) + ' refused, attempting to forward device debugger-socket to local address by calling ' + str(cmd) + ':' + else: + print 'Error! Failed to connect to B2G device debugger socket at address ' + HOST + ':' + str(PORT) + '!' + sys.exit(1) + try: + retcode = subprocess.check_call(cmd) + except Exception, e: + print 'Error! Failed to execute adb: ' + str(e) + print "Check that the device is connected properly, call 'adb devices' to list the detected devices." + sys.exit(1) + if retcode is not 0: + print 'Error! Failed to connect to B2G device and executing adb failed with return code ' + retcode + '!' + sys.exit(1) + time.sleep(3) + # Try again: + try: + b2g_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + b2g_socket.connect((HOST, PORT)) + except Exception, e: + print 'Error! Failed to connect to B2G device debugger socket at address ' + HOST + ':' + str(PORT) + '!' + sys.exit(1) + + handshake = read_b2g_response() + logv('Connected. Handshake: ' + str(handshake)) + + data = send_b2g_cmd('root', 'listTabs') + deviceActorName = data['deviceActor'] + logv('deviceActor: ' + deviceActorName) + webappsActorName = data['webappsActor'] + logv('webappsActor: ' + webappsActorName) + + send_b2g_cmd(deviceActorName, 'getDescription') + send_b2g_cmd(deviceActorName, 'getRawPermissionsTable') + + apps = b2g_get_appslist() + + if sys.argv[1] == 'list': + running_app_manifests = b2g_get_runningapps() + printed_apps = apps + print_only_running = '--running' in sys.argv and not '--all' in sys.argv + if print_only_running: # Print running apps only? + print 'Running applications by id:' + printed_apps = filter(lambda x: x['manifestURL'] in running_app_manifests, apps) + else: + print 'Installed applications by id:' + num_printed = print_applist(printed_apps, running_app_manifests, '--all' in sys.argv or print_only_running) + if num_printed == 0: + if print_only_running: + print ' No applications running.' + else: + print ' No applications installed.' + if not '--all' in sys.argv and not print_only_running: + print 'Not showing built-in apps that cannot be uninstalled. Pass --all to include those in the listing.' + elif sys.argv[1] == 'launch' or sys.argv[1] == 'close' or sys.argv[1] == 'uninstall' or sys.argv[1] == 'getAppActor': + if len(sys.argv) < 3: + print 'Error! No application name given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' ' + return 1 + for app in apps: + if str(app['localId']) == sys.argv[2] or app['name'] == sys.argv[2] or app['manifestURL'] == sys.argv[2]: + send_b2g_cmd(webappsActorName, sys.argv[1], { 'manifestURL': app['manifestURL'] }) + return 0 + print 'Error! Application "' + sys.argv[2] + '" was not found! Use the \'list\' command to find installed applications.' + return 1 + elif sys.argv[1] == 'install': + if len(sys.argv) < 3: + print 'Error! No application path given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' ' + return 1 + target_app_path = sys.argv[2] + if os.path.isdir(target_app_path): + print 'Zipping up the contents of directory "' + target_app_path + '"...' + (oshandle, tempzip) = tempfile.mkstemp(suffix='.zip', prefix='ffdb_temp_') + zipdir(target_app_path, tempzip) + target_app_path = tempzip + # Remember to delete the temporary package after we quit. + def delete_temp_file(): + os.remove(tempzip) + atexit.register(delete_temp_file) + + print 'Uploading application package "' + target_app_path + '"...' + print 'Size of compressed package: ' + sizeof_fmt(os.path.getsize(target_app_path)) + '.' + uploadResponse = send_b2g_cmd(webappsActorName, 'uploadPackage') + packageUploadActor = uploadResponse['actor'] + app_file = open(target_app_path, 'rb') + data = app_file.read() + file_size = len(data) + chunk_size = 4*1024*1024 + i = 0 + start_time = time.time() + while i < file_size: + chunk = data[i:i+chunk_size] + + send_b2g_data_chunk(packageUploadActor, chunk) + i += chunk_size + bytes_uploaded = min(i, file_size) + cur_time = time.time() + secs_elapsed = cur_time - start_time + percentage_done = bytes_uploaded * 1.0 / file_size + total_time = secs_elapsed / percentage_done + time_left = total_time - secs_elapsed + print sizeof_fmt(bytes_uploaded) + " uploaded, {:5.1f} % done.".format(percentage_done*100.0) + ' Elapsed: ' + str(int(secs_elapsed)) + ' seconds. Time left: ' + str(datetime.timedelta(seconds=int(time_left))) + '. Data rate: {:5.2f} KB/second.'.format(bytes_uploaded / 1024.0 / secs_elapsed) + send_b2g_cmd(webappsActorName, 'install', { 'appId': str(uuid.uuid4()), 'upload': packageUploadActor }) + + cur_time = time.time() + secs_elapsed = cur_time - start_time + print 'Upload of ' + sizeof_fmt(file_size) + ' finished. Total time elapsed: ' + str(int(secs_elapsed)) + ' seconds. Data rate: {:5.2f} KB/second.'.format(file_size / 1024.0 / secs_elapsed) + elif sys.argv[1] == 'navigate': + if len(sys.argv) < 3: + print 'Error! No URL given! Usage: ' + sys.argv[0] + ' ' + sys.argv[1] + ' ' + return 1 + browserActor = '' + for app in apps: + if app['name'] == 'Browser': + browserActor = send_b2g_cmd(webappsActorName, 'getAppActor', { 'manifestURL': app['manifestURL'] }) + break + if 'actor' in browserActor: + browserActor = browserActor['actor']['actor'] + send_b2g_cmd(browserActor, 'navigateTo', { 'url': sys.argv[2]}) + else: + print 'Web browser is not running!' + elif sys.argv[1] == 'log': + appActor = '' + for app in apps: + if str(app['localId']) == sys.argv[2] or app['name'] == sys.argv[2] or app['manifestURL'] == sys.argv[2]: + appActor = send_b2g_cmd(webappsActorName, 'getAppActor', { 'manifestURL': app['manifestURL'] }) + break + if 'actor' in appActor: + consoleActor = appActor['actor']['consoleActor'] + + if '-c' in sys.argv or '-clear' in sys.argv or '--clear' in sys.argv: + send_b2g_cmd(consoleActor, 'clearMessagesCache') + print 'Cleared message log.' + sys.exit(0) + + msgs = send_b2g_cmd(consoleActor, 'startListeners', { 'listeners': ['PageError','ConsoleAPI','NetworkActivity','FileActivity'] }) + + def log_b2g_message(msg): + WARNING = '\033[93m' + FAIL = '\033[91m' + ENDC = '\033[0m' + BOLD = "\033[1m" + msgs = [] + if 'type' in msg and msg['type'] == 'consoleAPICall': + msgs = [msg['message']] + elif 'messages' in msg: + msgs = msg['messages'] + + for m in msgs: + args = m['arguments'] + + for arg in args: + if m['level'] == 'log': + color = 'I/' + elif m['level'] == 'warn': + color = WARNING + 'W/' + elif m['level'] == 'error': + color = FAIL + 'E/' + else: + color = m['level'] + '/' + + print color + str(m['functionName']) + '@' + str(m['filename']) + ':' + str(m['lineNumber']) + ': ' + str(arg) + ENDC + + msgs = send_b2g_cmd(consoleActor, 'getCachedMessages', { 'messageTypes': ['PageError', 'ConsoleAPI'] }) + log_b2g_message(msgs) + + while True: + msg = read_b2g_response() + log_b2g_message(msg) + else: + print 'Application "' + sys.argv[2] + '" is not running!' + else: + print "Unknown command '" + sys.argv[1] + "'! Pass --help for instructions." + + b2g_socket.close() + return 0 + +if __name__ == '__main__': + returncode = main() + logv('ffdb.py quitting with process exit code ' + str(returncode)) + sys.exit(returncode) From a4e3a2c456eaaedbef87766da1dcb8b99a95bf52 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Mon, 5 May 2014 13:25:55 -0700 Subject: [PATCH 64/67] export SAFE_FT_MASK in non-fastcomp, to fix some asm validation errors --- emscripten.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten.py b/emscripten.py index f03a81f0626dc..38146c63fdabb 100755 --- a/emscripten.py +++ b/emscripten.py @@ -455,7 +455,7 @@ def fix_item(item): basic_funcs = ['abort', 'assert', 'asmPrintInt', 'asmPrintFloat'] + [m.replace('.', '_') for m in math_envs] if settings['RESERVED_FUNCTION_POINTERS'] > 0: basic_funcs.append('jsCall') - if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE'] + if settings['SAFE_HEAP']: basic_funcs += ['SAFE_HEAP_LOAD', 'SAFE_HEAP_STORE', 'SAFE_FT_MASK'] if settings['CHECK_HEAP_ALIGN']: basic_funcs += ['CHECK_ALIGN_2', 'CHECK_ALIGN_4', 'CHECK_ALIGN_8'] if settings['ASSERTIONS']: basic_funcs += ['nullFunc'] From bce9b33b73f4c3fb4c31fcf513061c776ed87c2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Mon, 5 May 2014 23:32:20 +0300 Subject: [PATCH 65/67] Add support to function run_js() in jsrun.py to assert against a given process return code. This uncovers issues in other.test_embind which were not caught before. See #2335. --- tests/test_other.py | 2 +- tools/jsrun.py | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/tests/test_other.py b/tests/test_other.py index 779335bbbcc40..137a83b136727 100644 --- a/tests/test_other.py +++ b/tests/test_other.py @@ -1891,7 +1891,7 @@ def test_embind(self): Popen([PYTHON, EMCC, path_from_root('tests', 'embind', 'embind_test.cpp'), '--post-js', path_from_root('tests', 'embind', 'underscore-1.4.2.js'), '--post-js', path_from_root('tests', 'embind', 'imvu_test_adapter.js'), '--post-js', path_from_root('tests', 'embind', 'embind.test.js')] + args, stderr=PIPE if fail else None).communicate() assert os.path.exists(self.in_dir('a.out.js')) == (not fail) if not fail: - output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True) + output = run_js(self.in_dir('a.out.js'), stdout=PIPE, stderr=PIPE, full_output=True, assert_returncode=0) assert "FAIL" not in output, output def test_llvm_nativizer(self): diff --git a/tools/jsrun.py b/tools/jsrun.py index f74a149298a24..d63451db84fee 100644 --- a/tools/jsrun.py +++ b/tools/jsrun.py @@ -14,10 +14,10 @@ def timeout_run(proc, timeout=None, note='unnamed process', full_output=False): out = proc.communicate() out = map(lambda o: '' if o is None else o, out) if TRACK_PROCESS_SPAWNS: - logging.info('Process ' + str(proc.pid) + ' finished after ' + str(time.time() - start) + ' seconds.') + logging.info('Process ' + str(proc.pid) + ' finished after ' + str(time.time() - start) + ' seconds. Exit code: ' + str(proc.returncode)) return '\n'.join(out) if full_output else out[0] -def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdout=PIPE, stderr=None, cwd=None, full_output=False): +def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdout=PIPE, stderr=None, cwd=None, full_output=False, assert_returncode=None): if type(engine) is not list: engine = [engine] command = engine + [filename] + (['--'] if 'd8' in engine[0] or 'jsc' in engine[0] else []) + args @@ -30,8 +30,11 @@ def run_js(filename, engine=None, args=[], check_timeout=False, stdin=None, stdo timeout = 15*60 if check_timeout else None if TRACK_PROCESS_SPAWNS: logging.info('Blocking on process ' + str(proc.pid) + ': ' + str(command) + (' for ' + str(timeout) + ' seconds' if timeout else ' until it finishes.')) - return timeout_run( + ret = timeout_run( proc, timeout, 'Execution', full_output=full_output) + if assert_returncode is not None and proc.returncode is not assert_returncode: + raise Exception('Expected the command ' + str(command) + ' to finish with return code ' + str(assert_returncode) + ', but it returned with code ' + str(proc.returncode) + ' instead! Output: ' + str(ret)) + return ret From fd3d9cc489400b90bb578cab7a6fece69e161fe0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jukka=20Jyl=C3=A4nki?= Date: Tue, 6 May 2014 12:53:37 +0300 Subject: [PATCH 66/67] Apply Chad's fix from issue #2335 to fix other.test_embind. --- src/embind/embind.js | 9 ++++++--- tests/embind/imvu_test_adapter.js | 6 ------ 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/embind/embind.js b/src/embind/embind.js index 3eadb85f509ff..4821c77b1c327 100644 --- a/src/embind/embind.js +++ b/src/embind/embind.js @@ -1525,9 +1525,12 @@ function downcastPointer(ptr, ptrClass, desiredClass) { if (undefined === desiredClass.baseClass) { return null; // no conversion } - // O(depth) stack space used - return desiredClass.downcast( - downcastPointer(ptr, ptrClass, desiredClass.baseClass)); + + var rv = downcastPointer(ptr, ptrClass, desiredClass.baseClass); + if (rv === null) { + return null; + } + return desiredClass.downcast(rv); } function upcastPointer(ptr, ptrClass, desiredClass) { diff --git a/tests/embind/imvu_test_adapter.js b/tests/embind/imvu_test_adapter.js index 421e86c8a7854..93eeab37dd194 100644 --- a/tests/embind/imvu_test_adapter.js +++ b/tests/embind/imvu_test_adapter.js @@ -586,12 +586,6 @@ function module(ignore, func) { throw new AssertionError("Don't call setInterval in tests. Use fakes."); }; - if (typeof process !== 'undefined') { - process.nextTick = function() { - throw new AssertionError("Don't call process.nextTick in tests. Use fakes."); - }; - } - Math.random = function() { throw new AssertionError("Don't call Math.random in tests. Use fakes."); }; From 0fdd070030c66338490a031327afe0c5f990fdd8 Mon Sep 17 00:00:00 2001 From: Alon Zakai Date: Tue, 6 May 2014 13:57:59 -0700 Subject: [PATCH 67/67] 1.17.0 --- emscripten-version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/emscripten-version.txt b/emscripten-version.txt index f488f67e2a257..f9505a5cdc480 100644 --- a/emscripten-version.txt +++ b/emscripten-version.txt @@ -1,2 +1,2 @@ -1.16.0 +1.17.0