• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
using cxx::types
 

using cxx::types

on

  • 3,184 views

 

Statistics

Views

Total Views
3,184
Views on SlideShare
3,133
Embed Views
51

Actions

Likes
4
Downloads
57
Comments
1

1 Embed 51

http://www.redditmedia.com 51

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel

11 of 1 previous next

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
  • Hello dearest,

    I'm a female,Lusee by name.
    Please for a very important issue
    contact me direct in this my private box for further knowing
    (lusee1johnson@yahoo.co.uk),Thanks hoping to see your mail soon.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

    using cxx::types using cxx::types Presentation Transcript

    • using cxx::types; Jordan DeLong Software Engineer, FacebookBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 1 / 39
    • Overview • C++ and its type system • Weakly typed code • Refactoring exampleBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 2 / 39
    • Preliminaries Why does Facebook use C++?By Jordan DeLong. c 2012- Facebook. Do not redistribute. 3 / 39
    • Preliminaries Why does Facebook use C++? • Performance ◦ At scale: operational costs > engineering costs ◦ C++ gives programmers low-level controlBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 3 / 39
    • Preliminaries Why does Facebook use C++? • Performance ◦ At scale: operational costs > engineering costs ◦ C++ gives programmers low-level control • Abstraction tools ◦ Lambdas and higher-order functions ◦ Type deduction (auto, template arguments) ◦ Powerful type systemBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 3 / 39
    • C++: Powerful Type System • template<class T>By Jordan DeLong. c 2012- Facebook. Do not redistribute. 4 / 39
    • C++: Powerful Type System • template<class T> • template<int I>By Jordan DeLong. c 2012- Facebook. Do not redistribute. 4 / 39
    • C++: Powerful Type System • template<class T> • template<int I> • template<template <class> class T>By Jordan DeLong. c 2012- Facebook. Do not redistribute. 4 / 39
    • C++: Powerful Type System • template<class T> • template<int I> • template<template <class> class T> • OO-style subtyping/polymorphismBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 4 / 39
    • C++: Powerful Type System • template<class T> • template<int I> • template<template <class> class T> • OO-style subtyping/polymorphism Basics: • New statically incompatible types can be createdBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 4 / 39
    • C++: Powerful Type System • template<class T> • template<int I> • template<template <class> class T> • OO-style subtyping/polymorphism Basics: • New statically incompatible types can be created • Function and operator overloadingBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 4 / 39
    • C++: “Powerful” Type System? • Error-prone standard conversions ◦ Nearly all primitive types convert to bool ◦ unsigned to signed ◦ narrowing conversions ◦ floating-integral conversionsBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 5 / 39
    • C++: “Powerful” Type System? • Error-prone standard conversions ◦ Nearly all primitive types convert to bool ◦ unsigned to signed ◦ narrowing conversions ◦ floating-integral conversions • void*, unsigned char*, untyped memoryBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 5 / 39
    • C++: “Powerful” Type System? • Error-prone standard conversions ◦ Nearly all primitive types convert to bool ◦ unsigned to signed ◦ narrowing conversions ◦ floating-integral conversions • void*, unsigned char*, untyped memory • typedef only makes type aliases ◦ Creating real new types is more verboseBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 5 / 39
    • Strong vs. Weak Usual definition: A type system is “strong” if it disallows conversions between values of different types.By Jordan DeLong. c 2012- Facebook. Do not redistribute. 6 / 39
    • Strong vs. Weak Usual definition: A type system is “strong” if it disallows conversions between values of different types. Many? Most? Unsafe? Implicit?By Jordan DeLong. c 2012- Facebook. Do not redistribute. 6 / 39
    • Strong vs. Weak Usual definition: A type system is “strong” if it disallows conversions between values of different types. Many? Most? Unsafe? Implicit? In the context of static type systems: • Unclear as a language propertyBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 6 / 39
    • Strong vs. Weak Usual definition: A type system is “strong” if it disallows conversions between values of different types. Many? Most? Unsafe? Implicit? In the context of static type systems: • Unclear as a language property • Better: “strongly typed” is a property of codeBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 6 / 39
    • Strong vs. Weak Usual definition: A type system is “strong” if it disallows conversions between values of different types. Many? Most? Unsafe? Implicit? In the context of static type systems: • Unclear as a language property • Better: “strongly typed” is a property of code • Weakly typed code can be written in a strongly typed languageBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 6 / 39
    • What We Really Want Goal: fewer bugs, guaranteed correctness.By Jordan DeLong. c 2012- Facebook. Do not redistribute. 7 / 39
    • What We Really Want Goal: fewer bugs, guaranteed correctness. • Move runtime errors to compile time • One way to do this: strongly typed APIsBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 7 / 39
    • What We Really Want Goal: fewer bugs, guaranteed correctness. • Move runtime errors to compile time • One way to do this: strongly typed APIs What this means: • Types are a critical part of interface designBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 7 / 39
    • What We Really Want Goal: fewer bugs, guaranteed correctness. • Move runtime errors to compile time • One way to do this: strongly typed APIs What this means: • Types are a critical part of interface design • Types should encode semanticsBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 7 / 39
    • What We Really Want Goal: fewer bugs, guaranteed correctness. • Move runtime errors to compile time • One way to do this: strongly typed APIs What this means: • Types are a critical part of interface design • Types should encode semantics • Primitive types are just building blocks (especially in C++)By Jordan DeLong. c 2012- Facebook. Do not redistribute. 7 / 39
    • Weakly Typed APIsBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 8 / 39
    • Weak: High-arity Functions public void DrawRectangle( Color colorOutline, int thicknessOutline, int x, int y, int width, int height, int xCornerRadius, int yCornerRadius, Color colorGradientStart, int xGradientStart, int yGradientStart, Color colorGradientEnd, int xGradientEnd, int yGradientEnd, UInt16 opacityBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 9 / 39
    • Weak: High-arity Functions • Semantics are primarily encoded by positionBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 10 / 39
    • Weak: High-arity Functions • Semantics are primarily encoded by position • Worse when arguments have compatible typesBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 10 / 39
    • Weak: High-arity Functions • Semantics are primarily encoded by position • Worse when arguments have compatible types • Temptation to use or add defaulted arguments ◦ Hinders refactoringBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 10 / 39
    • Weak: “Types” in Identifiers void sleep(int seconds); sleep(3600 * 60 * 2 /* two hours */);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 11 / 39
    • Weak: “Types” in Identifiers void sleep(int seconds); sleep(3600 * 60 * 2 /* two hours */); • Semantics are encoded in the identifierBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 11 / 39
    • Weak: “Types” in Identifiers void sleep(int seconds); sleep(3600 * 60 * 2 /* two hours */); • Semantics are encoded in the identifier • Use types that encode units, e.g. std::chrono::duration<> using namespace std::chrono; void sleep(seconds s); sleep(duration_cast<seconds>(hours(2)));By Jordan DeLong. c 2012- Facebook. Do not redistribute. 11 / 39
    • Weak: Boolean Arguments typedef int Id; enum MetaKind { ... }; void addMeta(int pos, MetaKind kind, MetaData* mdata, bool mIsVector, Id id); Particularly bad in C++: every other argument type here implicitly converts to bool.By Jordan DeLong. c 2012- Facebook. Do not redistribute. 12 / 39
    • Refactoring: HHVM AssemblerBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 13 / 39
    • An Assembler API typedef int register_name_t; const register_name_t rax = 0; const register_name_t rbx = 1; // ... struct Asm { // ... void load_reg64_disp_reg32(int rbase, int disp, int rdest); void load_reg64_disp_reg64(int, int, int); void sub_imm32_reg32(intptr_t, int); void mov_imm64_reg(intptr_t, int); void load_reg64_index_scale_disp_reg64( int rbase, int rindex, int scale, int disp, int rdest);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 14 / 39
    • x64 Memory Operands // *rax = rbx; movq %rbx, (%rax) ; base + 0 // rax[0xc] = rbx; movq %rbx, 0xc(%rax) ; base + disp // rax[rcx*2+0xc] = 0x42; movq $0x42, 0xc(%rax,%rcx,0x2) ; base + idx*2 + disp General case: base + index * scale + displacement.By Jordan DeLong. c 2012- Facebook. Do not redistribute. 15 / 39
    • Using the API void (*g_destructors[4])(void*) = {destructString, destructArray, destructObject, destructRef}; // Dispatch to appropriate destructor function a. load_reg64_disp_reg32(rbx, TVOFF(m_type), rsi); a. sub_imm32_reg32(KindOfString, rsi); a. mov_imm64_reg(uintptr_t(&g_destructors), rax) a. load_reg64_index_scale_disp_reg64( rax, rsi, 8, 0, rax); a. call_reg(rax);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 16 / 39
    • Using the API movl 0xc(%rbx), %esi subl $0xf,%esi movq $0x6a28240,%rax movq (%rax,%rsi,8),%rax callq *%raxBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 17 / 39
    • Misusing the API void load_reg64_index_scale_disp_reg64( int rbase, int rindex, int scale, int disp, int rdest);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 18 / 39
    • Possible Errors #1 a. load_reg64_disp_reg64(rVmFp, AROFF(m_this), rax); a. store_reg64_disp_reg64(0, AROFF(m_this), rVmFp); a. shr_imm32_reg64(1, rax); a. jcc(CC_NBE, decRefThisStub);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 19 / 39
    • Possible Errors #1 a. load_reg64_disp_reg64(rVmFp, AROFF(m_this), rax); a. store_reg64_disp_reg64(0, AROFF(m_this), rVmFp); // <-- a. shr_imm32_reg64(1, rax); a. jcc(CC_NBE, decRefThisStub);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 20 / 39
    • Possible Errors #1 a. load_reg64_disp_reg64(rVmFp, AROFF(m_this), rax); a. store_imm64_disp_reg64(0, // reg -> imm AROFF(m_this), rVmFp); // <-- a. shr_imm32_reg64(1, rax); a. jcc(CC_NBE, decRefThisStub);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 21 / 39
    • Possible Errors #2 a. mov_imm32_reg32(-1, rax); a. store_reg64_disp_reg64(rax, 0, rbx);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 22 / 39
    • Possible Errors #2 a. mov_imm32_reg32(-1, rax); a. store_reg64_disp_reg64(rax, 0, rbx); // not sign-extendedBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 23 / 39
    • Possible Errors #2 a. mov_imm32_reg64(-1, rax); // 32 -> 64 a. store_reg64_disp_reg64(rax, 0, rbx); // not sign-extendedBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 24 / 39
    • Improving on this • Argument semantics we can encode in types: ◦ Registers vs. immediates ◦ How a register is used (value vs. part of memory operand) ◦ Operand sizes (eax vs. rax)By Jordan DeLong. c 2012- Facebook. Do not redistribute. 25 / 39
    • Improving on this • Argument semantics we can encode in types: ◦ Registers vs. immediates ◦ How a register is used (value vs. part of memory operand) ◦ Operand sizes (eax vs. rax) • Reduce function arityBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 25 / 39
    • Improving on this • Argument semantics we can encode in types: ◦ Registers vs. immediates ◦ How a register is used (value vs. part of memory operand) ◦ Operand sizes (eax vs. rax) • Reduce function arity • Function naming: closer to x64 opcode mnemonicsBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 25 / 39
    • Refactored API // Dispatch to appropriate destructor function a. movl (rbx[TVOFF(m_type)], esi); a. subl (KindOfString, esi); a. movq (&g_destructors, rax); a. movq (rax[rsi*8], rax); a. call (rax);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 26 / 39
    • New Register Types /// Reg64, Reg32, RegXMM, RegRIP ... constexpr Reg64 rax(0); constexpr Reg64 rcx(1); constexpr Reg32 eax(0); constexpr Reg32 ecx(1); constexpr Reg8 al(0); constexpr RegXMM xmm0(0); constexpr RegRIP rip; // etcBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 27 / 39
    • Register Type Details struct Reg64 { explicit constexpr Reg64(int); explicit constexpr operator int() const; constexpr bool operator==(Reg64) const; constexpr bool operator!=(Reg64) const; // ... }; • We’re using a struct instead of enum class because we want to define an operator[] later.By Jordan DeLong. c 2012- Facebook. Do not redistribute. 28 / 39
    • Register to Register mov void movb(Reg8, Reg8); // 8-bit operands void movl(Reg32, Reg32); // 32-bit operands void movq(Reg64, Reg64); // 64-bit operandsBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 29 / 39
    • Register to Register mov void movb(Reg8, Reg8); // 8-bit operands void movl(Reg32, Reg32); // 32-bit operands void movq(Reg64, Reg64); // 64-bit operands a. movl (rax, rbx); // compile-time errorBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 29 / 39
    • Register to Register mov void movb(Reg8, Reg8); // 8-bit operands void movl(Reg32, Reg32); // 32-bit operands void movq(Reg64, Reg64); // 64-bit operands a. movl (rax, rbx); // compile-time error a. movl (eax, ebx); // okBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 29 / 39
    • Simple Memory Operands // reg + offset struct DispReg { Reg64 rbase; intptr_t disp; }; DispReg operator+(Reg64 rbase, intptr_t disp);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 30 / 39
    • Indexed Memory Operands // reg * scale struct ScaledIndex { Reg64 rindex; int scale; }; ScaledIndex operator*(Reg64 rindex, int scale); // reg + reg*scale + disp struct IndexedDispReg { Reg64 rbase; ScaledIndex index; intptr_t disp; }; IndexedDispReg operator+(Reg64 rbase, ScaledIndex); IndexedDispReg operator+(IndexedDispReg, intptr_t);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 31 / 39
    • Dereferenced Memory Operands // *(reg + offset) struct MemoryRef { DispReg dr; }; MemoryRef operator*(DispReg); // *(reg + reg*scale + disp) struct IndexedMemoryRef { IndexedDispReg dr; }; IndexedMemoryRef operator*(IndexedDispReg);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 32 / 39
    • Loads void movq(MemoryRef, Reg64); void movl(MemoryRef, Reg32); void movq(IndexedMemoryRef, Reg64); void movl(IndexedMemoryRef, Reg32);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 33 / 39
    • Loads void movq(MemoryRef, Reg64); void movl(MemoryRef, Reg32); void movq(IndexedMemoryRef, Reg64); void movl(IndexedMemoryRef, Reg32); a. movl(*(rbx + 0xc), rax); // compile-time errorBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 33 / 39
    • Loads void movq(MemoryRef, Reg64); void movl(MemoryRef, Reg32); void movq(IndexedMemoryRef, Reg64); void movl(IndexedMemoryRef, Reg32); a. movl(*(rbx + 0xc), rax); // compile-time error a. movl(*(rbx + 0xc), eax); // okBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 33 / 39
    • Stores void movq(Reg64, MemoryRef); void movl(Reg32, MemoryRef); void movq(Reg64, IndexedMemoryRef); void movl(Reg32, IndexedMemoryRef);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 34 / 39
    • Stores void movq(Reg64, MemoryRef); void movl(Reg32, MemoryRef); void movq(Reg64, IndexedMemoryRef); void movl(Reg32, IndexedMemoryRef); a. movq(rbx, rax[0xc]); // Reg64 gets an operator[]By Jordan DeLong. c 2012- Facebook. Do not redistribute. 34 / 39
    • Stores void movq(Reg64, MemoryRef); void movl(Reg32, MemoryRef); void movq(Reg64, IndexedMemoryRef); void movl(Reg32, IndexedMemoryRef); a. movq(rbx, rax[0xc]); // Reg64 gets an operator[] a. movq(ebx, rax[0xc]); // compile-time errorBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 34 / 39
    • Other opcodes // Load effective address: void lea(IndexedDispReg, Reg64); void lea(DispReg, Reg64); // Push can take memory or registers: void pushq(IndexedMemoryRef); void pushq(MemoryRef); void pushq(Reg64);By Jordan DeLong. c 2012- Facebook. Do not redistribute. 35 / 39
    • Discussion • Registers ≡ Memory Operands ≡ Immediates ≡ RegistersBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 36 / 39
    • Discussion • Registers ≡ Memory Operands ≡ Immediates ≡ Registers • Memory Operands: encoded as an embedded expression languageBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 36 / 39
    • Discussion • Registers ≡ Memory Operands ≡ Immediates ≡ Registers • Memory Operands: encoded as an embedded expression language • Immediates: void movq(Immed, Reg64); void movl(Immed, Reg32); void movb(Immed, Reg8); ◦ Thin, runtime-checked wrapper around intptr_t ◦ Still potentially vulnerable to runtime integer-related issuesBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 36 / 39
    • Discussion • Registers ≡ Memory Operands ≡ Immediates ≡ Registers • Memory Operands: encoded as an embedded expression language • Immediates: void movq(Immed, Reg64); void movl(Immed, Reg32); void movb(Immed, Reg8); ◦ Thin, runtime-checked wrapper around intptr_t ◦ Still potentially vulnerable to runtime integer-related issues • Looks more like the assembly we’re trying to generateBy Jordan DeLong. c 2012- Facebook. Do not redistribute. 36 / 39
    • ;By Jordan DeLong. c 2012- Facebook. Do not redistribute. 37 / 39
    • Making immediates safer void movimm(Immed immed, Reg64 reg); struct Immed { template<class T> /* implicit */ Immed( T i, typename std::enable_if<...>::type* = 0 ) : m_int(/* ... */) {} // various accessors q(), l(), w() // fitsSigned(), fitsUnsigned() };By Jordan DeLong. c 2012- Facebook. Do not redistribute. 38 / 39
    • Making immediates safer void movimm(Immed imm, Reg64 dest) { if (imm.q() == 0) return xorl(r32(dest), r32(dest)); if (imm.q() > 0 && imm.fitsUnsigned(sz::dword)) { return movl(imm, r32(dest)); // zeros top bits } movq(imm, dest); }By Jordan DeLong. c 2012- Facebook. Do not redistribute. 39 / 39