Pull to refresh
44
0
Артём Пряничников @zebraxxl

QA-Engineer

Send message
Это не так — QPF всегда возращает фиксированную частоту, не зависящую от частоты процессора. См. мой ответ ниже — по последней ссылке как раз проверялось что QPF не зависит от частоты процессора.
QueryPerfomanceFrequency возвращает не частоту процессора, а частоту таймера который сама ОС выбрала при загрузке (таймеров в архитектуре PC довольно много). Таким образом частота действительно остаётся фиксированной в течении работы ОС, а результат QueryPerfomanceQuery монотонно увеличивающимся.

Вот немного ссылок на эту тему:
habrahabr.ru/company/intel/blog/260113 — рассказывается о таймерах на PC
www.gamedev.ru/code/forum/?id=39166#m4 — очень старая тема, но мне кажется довольно понятно объясняет как работают обе функции
www.gamedev.ru/code/forum/?id=142497&page=2#m16 — тоже старая тема, там я выкладывал тестовый код который доказывает что QFP и QFC не зависят от частоты процессора
А вариант github.com/udp/json-parser не рассматривали? ANSI C и возможность переопределения malloc/free присутствует. Из дополнительного ещё использует функцию pow (math.h), но лекго выпиливается.
А почему string нельзя описать через другие типы? Один int для длинны и массив char. Собственно в CLR тип string так и реализован.
Дело в том, что string — это тоже примитивный тип!

Я может быть чего-то не знаю — но всегда считал string — указательный неизменяемый тип. Так по крайней мере говорится в MSDN: https://msdn.microsoft.com/en-us/library/system.type.isprimitive(v=vs.100).aspx.
Например, за последние годы не было выпущено ни одной игры, где была бы строка ввода для пользователя.

В Might and Magic X, вышедшая в январе прошлого года, есть. И именно для ввода ответов на загадки.
Не совсем верно. Именования дженериков классов действительно несколько отличаются от стандартных. Но все отличие заключается лишь в том, что к имени класса добавляется суфикс "`N", где N — количество дженерик параметров. И нужно лишь для того, что бы не было пересечений имен в случаях когда есть три класса: C, C и C<T, F> (после компиляции превратятся в C, C`1 и C`2 соответственно). Это описано в стандарте ECMA-335, раздел II.9, второй абзац:
Цитата
A generic type consists of a name followed by a <…>-delimited list of generic parameters, as in C.
Two or more generic types shall not be defined with the same name, but different numbers of generic
parameters, in the same scope. However, to allow such overloading on generic arity at the source
language level, CLS Rule 43 is defined to map generic type names to unique CIL names. That Rule
states that the CLS-compliant name of a type C having one or more generic parameters, shall have a
suffix of the form `n, where n is a decimal integer constant (without leading zeros) representing the
number of generic parameters that C has. For example: the types C, C, and C<K,V> have CLScompliant
names of C, C`1, and C`2<K,V>, respectively. [Note: The names of all standard library
types are CLS-compliant; e.g., System.Collections.Generic.IEnumerable`1. end note]
Версия class файла — 49, но сам по себе байт код соответствует больше 1.6 и выше. По крайней мере try/finally блоки генерируются похожим образом. class файл — здесь
Имена для временных переменных. Не смотря на то, что переменные в результате переиспользуются, для каждого отдельного использования генерируется новое имя. Вот и получилось столько.
Ради интереса взял аналогичный код на C#:
Код
using System;

namespace TestConsole
{
    public class Program
    {

        public static void Main(string[] args)
        {
            int a;
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            try { a = 0; } finally {
            }}}}}}}}}}}}

            Console.WriteLine(a);
        }

        // Точка входа для Java
        public static void main(string[] args)
        {
            Main(args);
        }
    }
}

Скомпилировал в .NET и натравил на него свой компилятор CIL2Java. Сильно не углублялся что к чему, но статистика получилась такая:
Размер class файла: 184 915 байт
Пул констант: 4127 записей (из за отладочной информации)
Размер кода метода: 40 949 байт
А вот локальных переменных потребовалось всего 14 (CIL2Java всё таки освобождает временную переменную когда она становится не нужна)
Записей в таблице исключений: 4095 (что равно 32 760 байт)
Вот вкратце получилось так. Можно сделать вывод что мой компилятор генерирует даже более компактный код чем java =))
По возможности будет напрямую вызываться java аналог. Но там где аналогов нет, либо он по какой то причине не подходит, будет своя реализация впоследствии компилируемая в java.
В списке нереализованых фич у вас нет stackalloc/localloc — или это подпадает под раздел «указатели»?

В принципе да, пока нет полной поддержки указателей, эти вещи смотреть бесполезно. Для localloc есть заглушка, просто создающая массив байт указанного размера — просто на время сделал так.

В CLR намного более гибкая система с переопределением методов в классах-наследниках — newslot, явное указание переопределяемого метода etc — как именно вы это реализовываете? Генерацией имен при необходимости?

И тут вы правы — такие методы просто переименовываются что бы эмулировать поведение CLR.

(кстати, вот на этом месте сразу возникает вопрос, как будет работать рефлекшн, если там много где нужно делать name mangling...)

В будущем планирую просто добавлять к переименованным методам аннотацию с его настоящим именем. Да и вообще в аннотациях держать всю недостающую информацию для рефлексии (проперти, события и т.д.)

Как вы обрабатываете (или планируете обрабатывать) виртуальные дженерик-методы?

Пока никак =) Забыл про такую ситуацию. Так что спасибо что напомнили =)
Ну а обрабатывать их я вижу только одним способом — если метод был инстансирован, то и все его перегруженные варианты так же должны инстансироваться с тем же списком параметров.

Как насчет vararg-методов, ArgIterator и TypedReference?

Только что выкатил на github поддержку vararg, ArgIterator и частичную поддержку TypedReference

При перегрузке методов, в сигнатуре помимо типов параметров учитываются также модификаторы modopt и modreq. Причем эти штуки могут быть еще и вложенными, что в принципе позволяет пихать в сигнатуры практически произвольную информацию. Вы это как-то транслируете, или код на C++/CLI, где, например, перегружен метод на int и long (они там различаются как раз через modopt), сломается?

Вот за это спасибо. Не думал что modopt и modreq несут ещё и такую функцию. Пока они вообще никак не учитываются (не считая volatile у полей), но я обращу на них внимания.

Дотнет (в отличие от спеки CLI) позволяет в верифицируемом коде методам возвращать managed pointer. Правда, вернуть таким образом они могут только результат ld[s]flda — но это вам может потенциально усложнить жизнь…

Manged pointer у меня подменятся на ByRef[type]. Так что пускай возвращает =) По идее не должно ничего сломаться.
Вы прямо прочитали мои мысли =)
Забыл правда упомянуть что такое не работает с конструкторами (их переименовывать нельзя) и там действительно код перестанет работать (верификатор не пропустит).
Такая ситуация предусмотрена. После трансляции void Foo(MyEnum) превратится в void Foo__0MyEnum(int). То же самое касается и беззнаковых типов.
К сожалению не получится. java.util.Arrays.copyOf(array, newSize); имеет перегруженные версии для примитивных типов, которые нельзя привести к Object[] что бы использовать единый T[] copyOf(T[] original, int newLength). Да и смысл если под капотом у них все тот же System.arraycopy.
Версия class файлов — 49. Почему именно её — уже не помню. Код для работы с Java файлами писался довольно давно.
Да, весь код по работе с байт кодом и class файлами писал сам по «Java Virtual Machine Specification». Вся работа с class файлами собрана в пространстве имён CIL2Java.Java, плюс есть класс CIL2Java.JavaBytecodeWriter для упрощения генерации байткода и класс CIL2Java.StackSimulator для трассировки получившегося кода и заполнения значений max_stack и max_locals в Code_attribute.
Ваш компилятор написан на C#. Можно ли его скомпилировать вашим компилятором в Java? Какой будет провал в производительности?

Пока нельзя. Нет реализации стандартных библиотек. Для mscorlib есть только заглушки (весь код усеян throw new NotImplementedException();), а остальных библиотек нет даже заглушек. И получается ситуация что компилятор подхватывает стандартные библиотеки от .NET, которые мало того, что не подходят, так ещё и собраны так, что mscorlib от .NET даёт им доступ к internal типам, которых нет в моей реализации mscorlib. Но на то это и альфа версия. План минимум — это что бы компилятор мог скомпилировать самого себя.

Генерируете ли вы StackMapTable? Говорят, без неё на новых JVM никак. Или вы именно поэтому остановились на Java 1.6?

Нет не генерирую. Если честно раньше думал что она не обязательна и не стал заморачиваться.

Вообще, конечно, невероятный пласт работы.

Впереди работы не меньше =)

Поставил плюсики, где мог.

Спасибо

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Date of birth
Registered
Activity