63
задан 17 April 2013 в 22:34

2 ответа

Те строки выделяют новый ByteArray# на "куче" Haskell, так для понимания их сначала необходимо знать немного о том, как "кучей" GHC управляют.

  • Каждая возможность (= поток ОС, который выполняет код Haskell) имеет свое собственное специализированное детский сад , область "кучи", в которую это делает нормальные, маленькие выделения как этот. Объекты просто выделяются последовательно в эту область от низких адресов до высоких адресов, пока возможность не пытается сделать выделение, которое превышает остающееся пространство в детском саду, который инициировал сборщик "мусора".

  • Все объекты "кучи" выровненные к нескольким из размера слова, т.е. 4 байта в 32-разрядных системах и 8 байтов в 64-разрядных системах.

  • регистр Cmm-уровня Hp указывает на (начало) последнее слово, которое было выделено в детском саду. HpLim указывает на последнее слово, которое может быть выделено в детском саду. (HpLim может также быть установлен на 0 другим потоком остановить мир для GC или отправить асинхронное исключение.)

  • https://ghc.haskell.org/trac/ghc/wiki/Commentary/Rts/Storage/HeapObjects имеет информацию о расположении отдельных объектов "кучи". Особенно каждый объект "кучи" начинается информационный указатель , который (среди прочего) определяет, какая "куча" возражают, что это.

тип Haskell ByteArray# реализован с типом объекта "кучи" ARR_WORDS. Объект ARR_WORDS просто состоит из (информационный указатель, сопровождаемый) размер (в байтах) сопровождаемый произвольными данными (полезная нагрузка). Полезная нагрузка не интерпретируется GC, таким образом, это не может сохранить указатели на объекты "кучи" Haskell, но это может сохранить что-либо еще. SIZEOF_StgArrWords является размером заголовка, характерного для всех объектов "кучи" ARR_WORDS, и в этом случае полезная нагрузка является просто отдельным словом, таким образом, SIZEOF_StgArrWords + WDS (1) является суммой пространства, мы должны выделить.

ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS (1), integer_cmm_int2Integerzh, val) расширяется до чего-то как [1 114]

Hp = Hp + (SIZEOF_StgArrWords + WDS(1));
if (Hp > HpLim) {
    HpAlloc = SIZEOF_StgArrWords + WDS(1);
    goto stg_gc_prim_n(integer_cmm_int2Integerzh, val);
}

, Первая строка увеличивает Hp суммой, которая будет выделена. Вторая строка проверяет на переполнение "кучи". Третья строка записывает сумму, которую мы пытались выделить, таким образом, GC может отменить ее. Четвертая строка называет GC.

четвертая строка является самой интересной. Аргументы говорят GC, как перезапустить поток, после того как сборка "мусора" сделана: это должно повторно вызвать integer_cmm_int2Integerzh с аргументом val. "_n" в stg_gc_prim_n (и "_N" в ALLOC_PRIM_N) означает, что val является неуказательным параметром (в этом случае Int#). Если бы val были указателем на объект "кучи" Haskell, то GC должен знать, что это живо (таким образом, это не становится собранным) и повторно вызвать нашу функцию с новым адресом объекта. В этом случае мы использовали бы _p вариант. Существуют также варианты как _pp для нескольких аргументов указателя, _d для аргументов Double#, и т.д.

После строки 5, мы успешно выделили блок SIZEOF_StgArrWords + WDS (1) байты и, помним, Hp указывает на свое последнее слово. Так, p = Hp - SIZEOF_StgArrWords устанавливает p на начало этого блока. Строки 8 заполняют информационный указатель p, идентифицируя недавно созданный объект "кучи" как ARR_WORDS. CCCS является текущей стопкой центра затрат, используемой только для профилирования. Когда профилированию включают, каждый объект "кучи" содержит дополнительное поле, которое в основном определяет, кто ответственен за его выделение. В непрофилировании сборок нет никакого CCCS, и SET_HDR просто устанавливает информационный указатель. Наконец, строка 9 заполняет поле размера ByteArray#. Остальная часть функции заполняет полезную нагрузку, и возвратите значение знака и указатель объекта ByteArray#.

Так, это закончило тем, что было больше о "куче" GHC, чем о языке Cmm, но я надеюсь, что это помогает.

5
ответ дан 31 October 2019 в 13:01

enter image description here

Необходимое знание

, Чтобы сделать арифметика и логичный , операционные компьютеры имеют цифровая схема , названная (арифметико-логическое устройство) ALU в их ЦП (Центральный процессор). ALU загружает данные от [1 143] входные регистры . регистр Процессора устройство хранения данных памяти в [1 146] кэш L1 (запросы данных в 3 галочках тактовой частоты ЦП) реализован в [1 147] (статическая оперативная память) SRAM , расположенная в [1 148] микросхема ЦП . Процессор часто содержит несколько видов из регистров, обычно дифференцируемых число битов, которые они могут содержать .

Числа выражаются в [1 151], дискретные биты могут содержать конечное число значений. Обычно числа имеют следующий типы примитивов выставленный языком программирования ( в Haskell):

 8 bit numbers = 256 unique representable values
16 bit numbers = 65 536 unique representable values
32 bit numbers = 4 294 967 296 unique representable values
64 bit numbers = 18 446 744 073 709 551 616 unique representable values

арифметика Фиксированной точности для тех типов была реализована в аппаратных средствах . размер Word относится к числу битов, которые могут быть обработаны ЦП компьютера сразу. Для [1 156] архитектура x86 это 32 бита и x64, который это 64 бита .

IEEE 754 определяет стандарт чисел с плавающей точкой для [1 161] {16, 32, 64, 128} разрядные числа. , Например, число точки на 32 бита (с 4 294 967 296 уникальными значениями) может содержать приблизительный значения [-3.402823e38 к 3.402823e38] с [1 164] точность по крайней мере из [1 165] 7 плавающая точка цифры .

enter image description here

, Кроме того

Акроним средства GMP Библиотека Арифметики Многократно увеличенной точности GNU и добавляет, что поддержка программного обеспечения эмулировала арифметику произвольной точности. Глазго Компилятор Haskell Целочисленная реализация использует это.

GMP имеет целью быть быстрее, чем какая-либо другая библиотека сверхбольшого числа для всех размеров операнда. Некоторые важные факторы в выполнении этого:

  • Используя полные слова как основной арифметический тип.
  • Используя различные алгоритмы для различных размеров операнда; алгоритмы, которые быстрее для очень больших чисел, обычно медленнее для небольших чисел.
  • Высоко оптимизированный код ассемблера для самых важных внутренних циклов, специализированных для различных процессоров.

Ответу

Для некоторого Haskell, возможно, придется немного трудно постигать синтаксис, таким образом, вот версия

var integer_cmm_int2Integerzh = function(word) {
  return WORDSIZE == 32 
    ? goog.math.Integer.fromInt(word))
    : goog.math.Integer.fromBits([word.getLowBits(), word.getHighBits()]);
};

JavaScript, Где goog библиотека Google Closure , используемый класс расположен в Математика. Целое число . Вызванные функции:

goog.math.Integer.fromInt = function(value) {
  if (-128 <= value && value < 128) {
    var cachedObj = goog.math.Integer.IntCache_[value];
    if (cachedObj) {
      return cachedObj;
    }
  }

  var obj = new goog.math.Integer([value | 0], value < 0 ? -1 : 0);
  if (-128 <= value && value < 128) {
    goog.math.Integer.IntCache_[value] = obj;
  }
  return obj;
};
goog.math.Integer.fromBits = function(bits) {
  var high = bits[bits.length - 1];
  return new goog.math.Integer(bits, high & (1 << 31) ? -1 : 0);
};

, Который не полностью корректен, поскольку тип возврата должен быть return (s,p);, где

  • с является значением
  • , p является знаком

для фиксации этой обертки GMP, должен быть создан. Это было сделано в Haskell к компилятору JavaScript проект ( исходная ссылка ).

Строки 5-9

ALLOC_PRIM_N (SIZEOF_StgArrWords + WDS(1), integer_cmm_int2Integerzh, val);
p = Hp - SIZEOF_StgArrWords;
SET_HDR(p, stg_ARR_WORDS_info, CCCS);
StgArrWords_bytes(p) = SIZEOF_W;

следующим образом

  • , выделяет место, поскольку новый Word
  • создает указатель на него
  • установленное значение указателя
  • размер типа указателя набора
3
ответ дан 31 October 2019 в 13:01