| Index: compiled/bindings/generator.cpp | 
| =================================================================== | 
| --- a/compiled/bindings/generator.cpp | 
| +++ b/compiled/bindings/generator.cpp | 
| @@ -319,21 +319,25 @@ namespace bindings_internal | 
| result += "    result = null;\n"; | 
| return result; | 
| } | 
| default: | 
| throw std::runtime_error("Unexpected return type for " + std::string(call.name)); | 
| } | 
| } | 
|  | 
| -  const std::string wrapCall(const FunctionInfo& call) | 
| +  const std::string wrapCall(const FunctionInfo& call, bool isFunction) | 
| { | 
| bool hasStringArgs = false; | 
| std::vector<std::string> params; | 
| -    std::string prefix = "function("; | 
| +    std::string prefix; | 
| + | 
| +    if (isFunction) | 
| +      prefix += "function"; | 
| +    prefix += "("; | 
| for (int i = 0; i < call.args.size(); i++) | 
| { | 
| std::string argName("arg" + std::to_string(i)); | 
| if (i > 0) | 
| prefix += ", "; | 
| prefix += argName; | 
|  | 
| if (call.args[i] == TypeCategory::STRING_REF) | 
| @@ -366,27 +370,16 @@ namespace bindings_internal | 
| } | 
|  | 
| if (call.instance_function) | 
| params.insert(params.begin(), "this._pointer"); | 
|  | 
| return prefix + generateCall(call, params) + suffix; | 
| } | 
|  | 
| -  std::string generatePropertyDescriptor(const PropertyInfo& property) | 
| -  { | 
| -    if (!property.jsValue.empty()) | 
| -      return "value: " + property.jsValue; | 
| - | 
| -    std::string result("get: " + wrapCall(property.getter)); | 
| -    if (!property.setter.empty()) | 
| -      result += ", set: " + wrapCall(property.setter); | 
| -    return result; | 
| -  } | 
| - | 
| void printHelpers() | 
| { | 
| printf("var sizeofString = %i;\n", sizeof(String)); | 
|  | 
| puts(R"( | 
| function copyString(str, buffer) | 
| { | 
| var length = str.length; | 
| @@ -412,40 +405,70 @@ namespace bindings_internal | 
|  | 
| function readString(str) | 
| { | 
| var length = Module._GetStringLength(str); | 
| var pointer = Module._GetStringData(str) >> 1; | 
| return String.fromCharCode.apply(String, HEAP16.slice(pointer, pointer + length)); | 
| } | 
|  | 
| -      function createClass(superclass, ref_counted_offset) | 
| +      function createClass(superclass, ref_counted_offset, props) | 
| { | 
| var result = function(pointer) | 
| { | 
| this._pointer = pointer; | 
| }; | 
| -        if (superclass) | 
| -          result.prototype = Object.create(superclass.prototype); | 
| +        var proto = (superclass ? superclass.prototype : null); | 
| +        result.prototype = Object.create(proto, Object.getOwnPropertyDescriptors(props)); | 
| result.prototype.delete = function() | 
| { | 
| Module._ReleaseRef(this._pointer + ref_counted_offset); | 
| }; | 
| return result; | 
| } | 
| )"); | 
| } | 
|  | 
| void printClass(const ClassInfo& cls) | 
| { | 
| +    // Begin class definition | 
| + | 
| ClassInfo* baseClass = find_class(cls.baseClass); | 
| -    printf("exports.%s = createClass(%s, %i);\n", cls.name.c_str(), | 
| +    printf("exports.%s = createClass(%s, %i, {\n", cls.name.c_str(), | 
| (baseClass ? ("exports." + baseClass->name).c_str() : "null"), | 
| cls.ref_counted_offset); | 
|  | 
| +    // Print prototype members | 
| + | 
| +    for (const auto& property : cls.properties) | 
| +    { | 
| +      if (property.jsValue.empty()) | 
| +      { | 
| +        printf("get %s%s,\n", property.name.c_str(), | 
| +               wrapCall(property.getter, false).c_str()); | 
| +        if (!property.setter.empty()) | 
| +        { | 
| +          printf("set %s%s,\n", property.name.c_str(), | 
| +                 wrapCall(property.setter, false).c_str()); | 
| +        } | 
| +      } | 
| +      else | 
| +        printf("%s: %s,\n", property.name.c_str(), property.jsValue.c_str()); | 
| +    } | 
| + | 
| +    for (const auto& method : cls.methods) | 
| +      if (method.call.instance_function) | 
| +        printf("%s: %s,\n", method.name.c_str(), wrapCall(method.call).c_str()); | 
| + | 
| +    // End class definition | 
| + | 
| +    printf("});\n"); | 
| + | 
| +    // Print static members | 
| + | 
| DifferentiatorInfo differentiator = cls.subclass_differentiator; | 
| if (differentiator.offset != SIZE_MAX) | 
| { | 
| printf("var %s_mapping = \n", cls.name.c_str()); | 
| puts("{"); | 
| for (const auto& item : differentiator.mapping) | 
| printf("  %i: '%s',\n", item.first, item.second.c_str()); | 
| puts("};"); | 
| @@ -461,30 +484,23 @@ namespace bindings_internal | 
| else | 
| { | 
| printf("exports.%s.fromPointer = function(ptr)\n", cls.name.c_str()); | 
| puts("{"); | 
| printf("  return new exports.%s(ptr);\n", cls.name.c_str()); | 
| puts("};"); | 
| } | 
|  | 
| -    for (const auto& item : cls.properties) | 
| +    for (const auto& method : cls.methods) | 
| { | 
| -      printf("Object.defineProperty(exports.%s.prototype, '%s', {%s});\n", | 
| -          cls.name.c_str(), item.name.c_str(), | 
| -          generatePropertyDescriptor(item).c_str()); | 
| -    } | 
| - | 
| -    for (const auto& item : cls.methods) | 
| -    { | 
| -      std::string obj("exports." + cls.name); | 
| -      if (item.call.instance_function) | 
| -        obj += ".prototype"; | 
| -      printf("%s.%s = %s;\n", obj.c_str(), item.name.c_str(), | 
| -          wrapCall(item.call).c_str()); | 
| +      if (!method.call.instance_function) | 
| +      { | 
| +        printf("exports.%s.%s = %s;\n", cls.name.c_str(), method.name.c_str(), | 
| +               wrapCall(method.call).c_str()); | 
| +      } | 
| } | 
| } | 
| } | 
|  | 
| void printBindings() | 
| { | 
| bindings_internal::printHelpers(); | 
|  | 
|  |