Slide 1

Slide 1 text

Разработка компилятора для «TypeScript»на LLVM#2 Дмитрий Пацура @ovr https://github.com/ovr

Slide 2

Slide 2 text

+2 heiakim omae wa mou shindeiru

Slide 3

Slide 3 text

+3 Дмитрий Пацура Fintier UK Пишу на много чем) https://github.com/ovr GHubber PHPSA

Slide 4

Slide 4 text

• Геометрии и число • Как устроенны Branches/Cycles • ГПСЧ/ГСЧ • С++ 11 random • Math.random and JS engines • JS engines and code structure • Array • Dynamic value Поговорим сегодня:

Slide 5

Slide 5 text

Разработка компилятора для "TypeScript" используя, LLVM в качестве backend, и TypeScript в качестве frontend, на TypeScript Часть 2

Slide 6

Slide 6 text

ВОТ ЕГО

Slide 7

Slide 7 text

В предыдущей серии

Slide 8

Slide 8 text

+8 В предыдущей серии LLVM TypeScript Backend Frontend compiler *.ts Executable

Slide 9

Slide 9 text

{ function doMath(): number { const a = 5.5; const b = 14.5; return ((a + b) * 50) / 10; } puts("hello"); puts(doMath()); }

Slide 10

Slide 10 text

Для этой серии, нам нужна программа

Slide 11

Slide 11 text

Нужно что-то сложнее чем складывать числа

Slide 12

Slide 12 text

Calculate PI number

Slide 13

Slide 13 text

Calculate PI number R C = π * d

Slide 14

Slide 14 text

Но как же считать?

Slide 15

Slide 15 text

Calculate PI number R

Slide 16

Slide 16 text

Calculate PI number R

Slide 17

Slide 17 text

Calculate PI number R Метод Монте-Карло

Slide 18

Slide 18 text

Calculate PI number R R S(circle) = S(square) = 2R 2R 4 * R2 π * R2 π * R2 4 * R2 P = = π 4 π = 4 * P

Slide 19

Slide 19 text

{ function calculatePI(cycles: number): number { let inside = 0; for (let i = 0; i < cycles; i++) { let x = Math.random(); let y = Math.random(); if ((x*x + y*y) < 1) { inside++ } } return 4.0 * inside / cycles; } console_log(calculatePI(1000000000)); }

Slide 20

Slide 20 text

Calculate PI number R

Slide 21

Slide 21 text

+21 Branches •Branches - ts.IfStatement •Cycle - ts.ForStatement •Math.random What we need to implement

Slide 22

Slide 22 text

Branches

Slide 23

Slide 23 text

+23 #include int main() { auto a = 5; auto b = 4; if (a > b) { puts("5 > 4"); } else { puts("5 < 4"); } } clang -S -emit-llvm main.cpp -O0 Branches

Slide 24

Slide 24 text

@.str = private unnamed_addr constant [6 x i8] c"5 > 4\00", align 1 @.str.1 = private unnamed_addr constant [6 x i8] c"5 < 4\00", align 1 define i32 @main() #0 { %a.0 = alloca i32, align 4 %b.0 = alloca i32, align 4 store i32 5, i32* %a.0, align 4 store i32 4, i32* %b.0, align 4 %a.1 = load i32, i32* %a.0, align 4 %b.1 = load i32, i32* %b.0, align 4 %6 = icmp sgt i32 %a.1, %b.1 br i1 %6, label %7, label %9 ; :7: ; preds = %0 %8 = call i32 @puts(i8* @.str) br label %11 ; :9: ; preds = %0 %10 = call i32 @puts(i8* @.str.1)) br label %11 ; :11: ; preds = %9, %7 ret i32 0 } if (a > b) { puts("5 > 4"); puts("5 < 4"); auto a = 5; auto b = 4;

Slide 25

Slide 25 text

import * as ts from "typescript"; import * as llvm from 'llvm-node'; import {NodeGenerateInterface} from "../node-generate.interface"; import {Context} from "../context"; class IfStatementCodeGenerator implements NodeGenerateInterface { generate(node: ts.IfStatement, ctx: Context, builder: llvm.IRBuilder): void { // @todo Будем писать код тут } }

Slide 26

Slide 26 text

generate(node: ts.IfStatement, ctx: Context, builder: llvm.IRBuilder): void { const positiveBlock = llvm.BasicBlock.create(ctx.llvmContext, "if.true"); ctx.scope.enclosureFunction.llvmFunction.addBasicBlock(positiveBlock); const negativeBlock = llvm.BasicBlock.create(ctx.llvmContext, "if.false"); ctx.scope.enclosureFunction.llvmFunction.addBasicBlock(negativeBlock); const next = llvm.BasicBlock.create(ctx.llvmContext, "if.end"); ctx.scope.enclosureFunction.llvmFunction.addBasicBlock(next); }

Slide 27

Slide 27 text

generate(node: ts.IfStatement, ctx: Context, builder: llvm.IRBuilder): void { const positiveBlock = llvm.BasicBlock.create(ctx.llvmContext, "if.true"); ctx.scope.enclosureFunction.llvmFunction.addBasicBlock(positiveBlock); const negativeBlock = llvm.BasicBlock.create(ctx.llvmContext, "if.false"); ctx.scope.enclosureFunction.llvmFunction.addBasicBlock(negativeBlock); const next = llvm.BasicBlock.create(ctx.llvmContext, "if.end"); ctx.scope.enclosureFunction.llvmFunction.addBasicBlock(next); emitCondition( node.expression, ctx, builder, positiveBlock, negativeBlock ); }

Slide 28

Slide 28 text

export function emitCondition( condition: ts.Expression, ctx: Context, builder: llvm.IRBuilder, positiveBlock: llvm.BasicBlock, negativeBlock: llvm.BasicBlock, ) { const left = buildFromExpression(condition, ctx, builder); const conditionBoolValue = left.toBoolean(ctx, builder, condition); builder.createCondBr(conditionBoolValue.getValue(), positiveBlock, negativeBlock); } if (expression) {

Slide 29

Slide 29 text

generate(node: ts.IfStatement, ctx: Context, builder: llvm.IRBuilder): void { //.. .. .. emitCondition( node.expression, ctx, builder, positiveBlock, negativeBlock ); builder.setInsertionPoint(positiveBlock); passNode(node.thenStatement, ctx, builder); builder.createBr(next); builder.setInsertionPoint(negativeBlock); passNode(node.elseStatement, ctx, builder); builder.createBr(next); builder.setInsertionPoint(next); }

Slide 30

Slide 30 text

ovr  hlvm   master ● ?  ./bin/ssc --printIR sandbox/do-simple-math.ts ✔ define i64 @main() { entry: %a = alloca double store double 5.000000e+00, double* %a %b = alloca double store double 4.000000e+00, double* %b %0 = load double, double* %a %1 = load double, double* %b %cmpGT = fcmp ogt double %0, %1 br i1 %cmpGT, label %if.true, label %if.false if.true: ; preds = %entry call void @puts(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @1, i32 0, i32 0)) br label %if.end if.end: ; preds = %if.true, %if.false ret i64 0 if.false: ; preds = %Entry call void @puts(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @0, i32 0, i32 0)) br label %if.end }

Slide 31

Slide 31 text

Cycles

Slide 32

Slide 32 text

+32 int main() { for (auto i = 0; i < 100; i++) { } } clang -S -emit-llvm main.cpp -O0 Cycles

Slide 33

Slide 33 text

define i32 @main() #0 { %1 = alloca i32, align 4 %2 = alloca i32, align 4 store i32 0, i32* %1, align 4 store i32 0, i32* %2, align 4 br label %3 ; :3: ; preds = %7, %0 %4 = load i32, i32* %2, align 4 %5 = icmp slt i32 %4, 100 br i1 %5, label %6, label %10 ; :6: ; preds = %3 br label %7 ; :7: ; preds = %6 %8 = load i32, i32* %2, align 4 %9 = add nsw i32 %8, 1 store i32 %9, i32* %2, align 4 br label %3 ; :10: ; preds = %3 %11 = load i32, i32* %1, align 4 ret i32 %11 }

Slide 34

Slide 34 text

llvm/7.0.1/bin/opt main.ll -dot-cfg-only dot -Tpng cfg.main.dot -o cfg.main.png

Slide 35

Slide 35 text

No content

Slide 36

Slide 36 text

define i64 @main() { entry: %i = alloca double store double 0.000000e+00, double* %i br label %for.condition for.body: ; preds = %for.condition br label %for.inc for.condition: ; preds = %for.inc, %entry %0 = load double, double* %i %cmpLT = fcmp olt double %0, 1.000000e+03 br i1 %cmpLT, label %for.body, label %next for.inc: ; preds = %for.body %1 = load double, double* %i %2 = fadd double %1, 1.000000e+00 store double %2, double* %i br label %for.condition next: ; preds = %for.condition ret i64 0 }

Slide 37

Slide 37 text

i condition -> i = 0 0 T for.body 1 T for.body 2 T for.body 100 F next

Slide 38

Slide 38 text

Math.Random

Slide 39

Slide 39 text

Math.Random https://www.ecma-international.org/ecma-262/5.1/#sec-15.8.2.14 15.8.2.14 random ( ) Returns a Number value with positive sign, greater than or equal to 0 but less than 1, chosen randomly or pseudo randomly with approximately uniform distribution over that range, using an implementation-dependent algorithm or strategy. This function takes no arguments. • Нет алгоритма • Распределение? • Chosen randomly or pseudo randomly

Slide 40

Slide 40 text

randomly / pseudo randomly

Slide 41

Slide 41 text

randomly / pseudo randomly Источники случайных чисел физические процессы другие явления • Дробовой шум • Радиоактивный распад • Спонтанное параметрическое рассеяние • Тепловой шум в резисторе • Атмосферный шум (random.org) • Разница в скорости хода часов • Времени между нажатиями на кнопки • Шума со встроенного микрофона • Использование сети или интернета

Slide 42

Slide 42 text

randomly / pseudo randomly Генераторы псевдослучайных чисел (ГПСЧ) f(seed) => number

Slide 43

Slide 43 text

randomly / pseudo randomly Генераторы случайных чисел (ГСЧ) ГСЧ = ГПСЧ с источником энтропии

Slide 44

Slide 44 text

randomly / pseudo randomly Энтропия /dev/random Счётчик тактов процессора, однако собирается только во время аппаратных прерываний Java SecureRandom Взаимодействие между потоками Microsoft CryptoAPI Текущее время, размер жёсткого диска, размер свободной памяти, номер процесса и NETBIOS-имя компьютера

Slide 45

Slide 45 text

+45 randomly / pseudo randomly Почему бы не добавить инструкцию в CPU вместе с бекдором от производителя?

Slide 46

Slide 46 text

+46 randomly / pseudo randomly RDRAND (Intel Ivy Bridge+, AMD 2015 +) RDSEED (Intel Broadwell+, AMD Zen +)

Slide 47

Slide 47 text

https://www.amd.com/system/files/TechDocs/24594.pdf Loads the destination register with a hardware-generated random value. The size of the returned value in bits is determined by the size of the destination register.

Slide 48

Slide 48 text

randomly / pseudo randomly ГСЧ = ГПСЧ с источником энтропии энтропия -> (initial value, seed) -> random

Slide 49

Slide 49 text

Простейший ГСЧ с источником энтропии ovr@MacBook-Pro-Dmitry  ~/projects/ovr/hlvm   logo-introduce ● ?  node -i  ✔ > function random_piterjs(max) { return new Date().getTime() % max; } undefined > random_piterjs(100); 18 > random_piterjs(100); 13 > random_piterjs(100); 48 > random_piterjs(100); 69 > random_piterjs(100); 73 > random_piterjs(100); 32 > random_piterjs(100); 67

Slide 50

Slide 50 text

Math.Random C++ 11 Random engine distribution random_device

Slide 51

Slide 51 text

Math.Random Engine

Slide 52

Slide 52 text

Math.Random Distribution

Slide 53

Slide 53 text

Math.Random

Slide 54

Slide 54 text

Math.Random random_device std::random_device генератор равномерно распределенных целых случайных чисел. Производит истинно случайные числа если недетерминированный источник (например, аппаратное устройство) доступен для реализации.

Slide 55

Slide 55 text

Math.Random random_device engine(seed) result distribution

Slide 56

Slide 56 text

Math.Random static std::mt19937 mt(1729); static std::uniform_real_distribution dist(0, 1.0); LIBRARY_EXPORT double Math__random() { return dist(mt); } ГПСЧ

Slide 57

Slide 57 text

Math.Random static std::random_device rd; static std::mt19937 mt(rd()); static std::uniform_real_distribution dist(0, 1.0); LIBRARY_EXPORT double Math__random() { return dist(mt); } ГСЧ = ГПСЧ с источником энтропии

Slide 58

Slide 58 text

Math.random and JS Engines

Slide 59

Slide 59 text

Math.random and JS Engines/V8 Modern JS engine parser ast wasm compiler runtime Builtins Base •Platform •Utils •HasMap •CPU •Stdlib

Slide 60

Slide 60 text

V8-точенный

Slide 61

Slide 61 text

Math.random and JS Engines/V8 Зачем https://github.com/v8/v8 •Git clone •Install depot •Glient •Build V8 with GN (before was GYN)

Slide 62

Slide 62 text

Math.random and JS Engines/V8 Ты 2 недели я собирал V8 и не собрал

Slide 63

Slide 63 text

// ES6 #sec-math.random TF_BUILTIN(MathRandom, CodeStubAssembler) { Node* context = Parameter(Descriptor::kContext); Node* native_context = LoadNativeContext(context); // Load cache index. TVARIABLE(Smi, smi_index); smi_index = CAST( LoadContextElement(native_context, Context::MATH_RANDOM_INDEX_INDEX)); // Cached random numbers are exhausted if index is 0. Go to slow path. Label if_cached(this); GotoIf(SmiAbove(smi_index.value(), SmiConstant(0)), &if_cached); // Cache exhausted, populate the cache. Return value is the new index. Node* const refill_math_random = ExternalConstant(ExternalReference::refill_math_random()); //… } https://v8.dev/docs/csa-builtins https://github.com/v8/v8/blob/master/src/builtins/builtins-math-gen.h

Slide 64

Slide 64 text

https://v8.dev/docs/torque V8 Torque is a language that allows developers contributing to the V8 project to express changes in the VM by focusing on their intent of their changes to the VM, rather than preoccupying themselves with unrelated implementation details.

Slide 65

Slide 65 text

Math.random and JS Engines Смотришь refill_math_random FixedDoubleArray cache = FixedDoubleArray::cast(native_context->math_random_cache()); // Create random numbers. for (int i = 0; i < kCacheSize; i++) { // Generate random numbers using xorshift128+. base::RandomNumberGenerator::XorShift128(&state.s0, &state.s1); cache->set(i, base::RandomNumberGenerator::ToDouble(state.s0)); } pod->set(0, state); Smi new_index = Smi::FromInt(kCacheSize); native_context->set_math_random_index(new_index);

Slide 66

Slide 66 text

base/utils/random-number-generator RandomNumberGenerator::RandomNumberGenerator() { #if V8_OS_CYGWIN || V8_OS_WIN // Use rand_s() to gather entropy on Windows. See: // https://code.google.com/p/v8/issues/detail?id=2905 unsigned first_half, second_half; errno_t result = rand_s(&first_half); DCHECK_EQ(0, result); result = rand_s(&second_half); DCHECK_EQ(0, result); SetSeed((static_cast(first_half) << 32) + second_half); #else // Gather entropy from /dev/urandom if available. FILE* fp = fopen("/dev/urandom", "rb"); if (fp != nullptr) { int64_t seed; size_t n = fread(&seed, sizeof(seed), 1, fp); fclose(fp); if (n == 1) { SetSeed(seed); return; }

Slide 67

Slide 67 text

base/utils/random-number-generator // We cannot assume that random() or rand() were seeded // properly, so instead of relying on random() or rand(), // we just seed our PRNG using timing data as fallback. // This is weak entropy, but it's sufficient, because // it is the responsibility of the embedder to install // an entropy source using v8::V8::SetEntropySource(), // which provides reasonable entropy, see: // https://code.google.com/p/v8/issues/detail?id=2905 int64_t seed = Time::NowFromSystemTime().ToInternalValue() << 24; seed ^= TimeTicks::HighResolutionNow().ToInternalValue() << 16; seed ^= TimeTicks::Now().ToInternalValue() << 8; SetSeed(seed);

Slide 68

Slide 68 text

Math.random and JS Engines В void RandomNumberGenerator::SetSeed(int64_t seed) { initial_seed_ = seed; state0_ = MurmurHash3(bit_cast(seed)); state1_ = MurmurHash3(~state0_); CHECK(state0_ != 0 || state1_ != 0); } uint64_t RandomNumberGenerator::MurmurHash3(uint64_t h) { h ^= h >> 33; h *= uint64_t{0xFF51AFD7ED558CCD}; h ^= h >> 33; h *= uint64_t{0xC4CEB9FE1A85EC53}; h ^= h >> 33; return h; } https://github.com/aappleby/smhasher

Slide 69

Slide 69 text

Math.random and JS Engines Левый // Static and exposed for external use. static inline double ToDouble(uint64_t state0) { // Exponent for double values for [1.0 .. 2.0) static const uint64_t kExponentBits = uint64_t{0x3FF0000000000000}; uint64_t random = (state0 >> 12) | kExponentBits; return bit_cast(random) - 1; } // Static and exposed for external use. static inline void XorShift128(uint64_t* state0, uint64_t* state1) { uint64_t s1 = *state0; uint64_t s0 = *state1; *state0 = s0; s1 ^= s1 << 23; s1 ^= s1 >> 17; s1 ^= s0; s1 ^= s0 >> 26; *state1 = s1; }

Slide 70

Slide 70 text

Math.random and JS Engines Угол XorShift128 Xorshift random number generators are a class of pseudorandom number generators that were discovered by George Marsaglia • Marsaglia's theorem • Multiply-with-carry • Subtract-with-borrow • Kiss • Mother methods for random • Ziggurat algorithm

Slide 71

Slide 71 text

ChakraCore- мертвеченный

Slide 72

Slide 72 text

ChakraCore-мертвеченный https://github.com/Microsoft/ChakraCore •Git clone •./build.sh

Slide 73

Slide 73 text

ChakraCore-мертвеченный https://github.com/Microsoft/ChakraCore/blob/master/lib/Runtime/Library/MathLibrary.cpp ///---------------------------------------------------------------------------- /// Random() returns a random number 0 <= n < 1.0, as described in /// (ES5.0: S15.8.2.14). ///---------------------------------------------------------------------------- Var Math::Random(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); AssertMsg(callInfo.Count > 0, "Should always have implicit 'this'"); ScriptContext* scriptContext = function->GetScriptContext(); Assert(!(callInfo.Flags & CallFlags_New)); double res = JavascriptMath::Random(scriptContext); return JavascriptNumber::ToVarNoCheck(res, scriptContext); }

Slide 74

Slide 74 text

ChakraCore-мертвеченный https://github.com/Microsoft/ChakraCore/blob/master/lib/Runtime/Math/JavascriptMath.cpp void InitializeRandomSeeds(uint64 *seed0, uint64 *seed1, ScriptContext *sc) { LARGE_INTEGER s0; LARGE_INTEGER s1; if (!rand_s(reinterpret_cast(&s0.LowPart)) && !rand_s(reinterpret_cast(&s0.HighPart)) && !rand_s(reinterpret_cast(&s1.LowPart)) && !rand_s(reinterpret_cast(&s1.HighPart))) { *seed0 = s0.QuadPart; *seed1 = s1.QuadPart; } }

Slide 75

Slide 75 text

double ConvertRandomSeedsToDouble(const uint64 seed0, const uint64 seed1) { const uint64 mExp = 0x3FF0000000000000; const uint64 mMant = 0x000FFFFFFFFFFFFF; // Take lower 52 bits of the sum of two seeds to make a double // Subtract 1.0 to negate the implicit integer bit of 1. Final range: [0.0, 1.0) // See IEEE754 Double-precision floating-point format for details // https://en.wikipedia.org/wiki/Double-precision_floating-point_format uint64 resplusone_ui64 = ((seed0 + seed1) & mMant) | mExp; double res = *(reinterpret_cast(&resplusone_ui64)) - 1.0; return res; } void Xorshift128plus(uint64 *seed0, uint64 *seed1) { uint64 s1 = *seed0; uint64 s0 = *seed1; *seed0 = s0; s1 ^= s1 << 23; s1 ^= s1 >> 17; s1 ^= s0; s1 ^= s0 >> 26; *seed1 = s1; }

Slide 76

Slide 76 text

Use V8 for Math.random

Slide 77

Slide 77 text

LIBRARY_EXPORT double Math__random() { v8::base::RandomNumberGenerator ng; return ng.NextDouble(); }

Slide 78

Slide 78 text

ovr@MacBook-Pro-Dmitry  hlvm   master ● ?  ./output/main ✔ Стартуем

Slide 79

Slide 79 text

Что произойдет? Тихо упадет Seg Fault 3.14 Infinity loop

Slide 80

Slide 80 text

ovr@MacBook-Pro-Dmitry  hlvm   master ● ?  ./output/main  ✔ Monte Carlo simulation [1] 63302 segmentation fault ./output/main ovr@MacBook-Pro-Dmitry  hlvm   master ● ?   SIGSEGV(11) ↵

Slide 81

Slide 81 text

ovr@  hlvm   master ● ?  lldb ./output/main ✔ Monte Carlo simulation Process 64172 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0x7ffeef3ffff8) frame #0: 0x000000010000a6b3 main`v8::base::RandomNumberGenerator::XorShift128(state0=0x000000010030006 8, state1=0x0000000100300070) at random-number-generator.h:120 117 118 // Static and exposed for external use. 119 static inline void XorShift128(uint64_t* state0, uint64_t* state1) { -> 120 uint64_t s1 = *state0; 121 uint64_t s0 = *state1; 122 *state0 = s0; 123 s1 ^= s1 << 23; Target 0: (main) stopped.

Slide 82

Slide 82 text

Оптимизация

Slide 83

Slide 83 text

Оптимизация R SSC IR llvm-llc C++ executable

Slide 84

Slide 84 text

Оптимизация R SSC IR llvm-llc C++ executable llvm-opt

Slide 85

Slide 85 text

define double @calculatePI(double %cycles, double %r) local_unnamed_addr { Entry: %cmpLT3 = fcmp ogt double %cycles, 0.000000e+00 br i1 %cmpLT3, label %for.body.lr.ph, label %for.condition1._crit_edge for.body.lr.ph: ; preds = %Entry %0 = fmul double %r, %r br label %for.body for.body: ; preds = %for.body.lr.ph, %for.body %i.05 = phi double [ 0.000000e+00, %for.body.lr.ph ], [ %9, %for.body ] %inside.04 = phi double [ 0.000000e+00, %for.body.lr.ph ], [ %inside.1, %for.body ] %1 = tail call double @_Z12Math__randomv() %2 = fmul double %1, %r %3 = tail call double @_Z12Math__randomv() %4 = fmul double %3, %r %5 = fmul double %2, %2 %6 = fmul double %4, %4 %7 = fadd double %5, %6 %cmpLT2 = fcmp olt double %7, %0 %8 = fadd double %inside.04, 1.000000e+00 %inside.1 = select i1 %cmpLT2, double %8, double %inside.04 %9 = fadd double %i.05, 1.000000e+00 %cmpLT = fcmp olt double %9, %cycles br i1 %cmpLT, label %for.body, label %for.condition1._crit_edge.loopexit for.condition1._crit_edge.loopexit: ; preds = %for.body %phitmp = fmul double %inside.1, 4.000000e+00 br label %for.condition1._crit_edge for.condition1._crit_edge: ; preds = %for.condition1._crit_edge.loopexit, %Entry %inside.0.lcssa = phi double [ 0.000000e+00, %Entry ], [ %phitmp, %for.condition1._crit_edge.loopexit ] %10 = fdiv double %inside.0.lcssa, %cycles ret double %10 }

Slide 86

Slide 86 text

define i64 @main() local_unnamed_addr { Entry: tail call void @_Z11console_logPKc(i8* getelementptr inbounds ([23 x i8], [23 x i8]* @0, i64 0, i64 0)) br label %for.body.i for.body.i: ; preds = %for.body.i, %Entry %i.05.i.int = phi i32 [ 0, %Entry ], [ %.int, %for.body.i ] %inside.04.i = phi double [ 0.000000e+00, %Entry ], [ %inside.1.i, %for.body.i ] %0 = tail call double @_Z12Math__randomv() %1 = fmul double %0, 6.553600e+04 %2 = tail call double @_Z12Math__randomv() %3 = fmul double %2, 6.553600e+04 %4 = fmul double %1, %1 %5 = fmul double %3, %3 %6 = fadd double %4, %5 %cmpLT2.i = fcmp olt double %6, 0x41F0000000000000 %7 = fadd double %inside.04.i, 1.000000e+00 %inside.1.i = select i1 %cmpLT2.i, double %7, double %inside.04.i %.int = add nuw nsw i32 %i.05.i.int, 1 %cmpLT.i = icmp ult i32 %.int, 100000000 br i1 %cmpLT.i, label %for.body.i, label %calculatePI.exit calculatePI.exit: ; preds = %for.body.i %phitmp.i = fmul double %inside.1.i, 4.000000e+00 %8 = fdiv double %phitmp.i, 1.000000e+08 tail call void @_Z11console_logd(double %8) ret i64 0 }

Slide 87

Slide 87 text

ovr@MacBook-Pro-Dmitry  hlvm   master ● ?  ./output/main  ✔ Monte Carlo simulation 30 seconds….. 1 minute…. 2 minute….

Slide 88

Slide 88 text

sudo dtruss ./output/main open_nocancel("/dev/urandom\0", 0x0, 0x1B6) = 3 0 fstat64(0x3, 0x7FFEE6AC1878, 0x0) = 0 0 ioctl(0x3, 0x4004667A, 0x7FFEE6AC18C4) = 0 0 dtrace: error on enabled probe ID 2175 (ID 945: syscall::read_nocancel:return): invalid kernel access in action #12 at DIF offset 68 close_nocancel(0x3) = 0 0 open_nocancel("/dev/urandom\0", 0x0, 0x1B6) = 3 0 fstat64(0x3, 0x7FFEE6AC1878, 0x0) = 0 0 ioctl(0x3, 0x4004667A, 0x7FFEE6AC18C4) = 0 0 ……

Slide 89

Slide 89 text

class Machine { protected: v8::base::RandomNumberGenerator* randomNumberGenerator = nullptr; public: static Machine& Instance() { static Machine s; return s; } v8::base::RandomNumberGenerator* getRandomNumberGenerator() { if (this->randomNumberGenerator) { return this->randomNumberGenerator; } return this->randomNumberGenerator = new v8::base::RandomNumberGenerator(); } };

Slide 90

Slide 90 text

LIBRARY_EXPORT double Math__random() { auto rd = Machine::Instance().getRandomNumberGenerator(); return rd->NextDouble(); }

Slide 91

Slide 91 text

Array

Slide 92

Slide 92 text

Typed Arrays

Slide 93

Slide 93 text

Typed Array(s)

Slide 94

Slide 94 text

interface Int16Array { readonly buffer: ArrayBuffer; }

Slide 95

Slide 95 text

const elements = 10; const buffer = new ArrayBuffer(elements * 16); const view = new DataView(buffer); view.setInt16(16 * 0, 120); view.setInt16(16 * 1, 120); console.log(view.getInt8(0));

Slide 96

Slide 96 text

interface Array {} declare type Int8Array = Array; declare type Uint8Array = Array; { const values: Int8Array = [1, 2, 3, 4, 5]; }

Slide 97

Slide 97 text

interface Int8ArrayConstructor { new(length: number): Int8Array; } declare const Int8Array: Int8ArrayConstructor; { let int8Array = new Int8Array(5); }

Slide 98

Slide 98 text

Typed Array(s) C/C++ Arrays H E L L O \0 char* str = *str *(str+1) *(str+2) *(str+3) *(str+4) *(str+5) •Fixed-size sequential collection •No size information

Slide 99

Slide 99 text

struct DynamicArray { void* elements; int32_t size; int32_t capacity; };

Slide 100

Slide 100 text

Dynamic value

Slide 101

Slide 101 text

{ let a; if (Math.random() > 0.5) { a = 5; } else { a = false; } console_log(a); }

Slide 102

Slide 102 text

{ let values = [true, null, "piterjs", []]; }

Slide 103

Slide 103 text

Строго типизированное

Slide 104

Slide 104 text

Строго типизированное struct User { char* name; int age; int weight; }; int getWeight(User *ptr) { return ptr->weight; } getWeight(User*): # @getWeight(User*) pushq %rbp movq %rsp, %rbp movq %rdi, -8(%rbp) movq -8(%rbp), %rdi movl 12(%rdi), %eax popq %rbp retq

Slide 105

Slide 105 text

Строго типизированное getWeight(User*): # @getWeight(User*) pushq %rbp movq %rsp, %rbp movq %rdi, -8(%rbp) movq -8(%rbp), %rdi movl 12(%rdi), %eax popq %rbp retq MEMORY char* name int age; int weight;

Slide 106

Slide 106 text

{ let values = [true, null, "piterjs", []]; } * * * *

Slide 107

Slide 107 text

Dynamic value class Dynamic { public: Dynamic(double value) { this->d = value; this->type = DynamicType::DOUBLE_TYPE; } Dynamic(bool value) { this->b = value; this->type = DynamicType::BOOLEAN_TYPE; } Dynamic(int64_t value) { this->i = value; this->type = DynamicType::INT64_TYPE; } private: DynamicType type; double d; bool b; int64_t i; }; enum DynamicType: int8_t { BOOLEAN_TYPE = 1, DOUBLE_TYPE = 2, INT64_TYPE = 3, };

Slide 108

Slide 108 text

Dynamic value enum DynamicType: int8_t { BOOLEAN_TYPE = 1, DOUBLE_TYPE = 2, INT64_TYPE = 3, }; class Dynamic { private: DynamicType type; double d; bool b; int64_t i; }; 1 byte 1 byte 8 byte 8 byte 1 + 8 + 1 + 8 = 18 byte sizeof(Dynamic) = 32

Slide 109

Slide 109 text

Dynamic value enum DynamicType: int8_t { BOOLEAN_TYPE = 1, DOUBLE_TYPE = 2, INT64_TYPE = 3, }; class Dynamic { private: DynamicType type; double d; bool b; int64_t i; }; MEMORY 1 8 1 8 ….14 sizeof(Dynamic) = 32

Slide 110

Slide 110 text

Dynamic value enum DynamicType: int8_t { BOOLEAN_TYPE = 1, DOUBLE_TYPE = 2, INT64_TYPE = 3, }; class Dynamic { private: DynamicType type; union { double d; bool b; int64_t i; }; }; MEMORY 1 8 ….7 sizeof(Dynamic) = 16

Slide 111

Slide 111 text

Стоп, но почему значения не указателями? union { double d; bool b; int64_t i; };

Slide 112

Slide 112 text

Dynamic value sizeof(bool) vs sizeof(bool*) 1 byte 8 byte

Slide 113

Slide 113 text

Dynamic value union { double d; bool b; int64_t i; }; 8 byte

Slide 114

Slide 114 text

{ function summ(a: any, b: number) { return a + b; } } • a0 = load a* • a1 = load a0 (number)

Slide 115

Slide 115 text

+115 Выводы…

Slide 116

Slide 116 text

+116 Дмитрий Пацура https://github.com/ovr [email protected] https://telegram.me/ovrweb Спасибо за внимание! https://github.com/ovr/StaticScript