Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
So you want to design a programming language
Search
brixen
February 15, 2013
1
130
So you want to design a programming language
Talk about Rubinius as a language platform at Copious.
brixen
February 15, 2013
Tweet
Share
More Decks by brixen
See All by brixen
Stop making mud pies!
brixen
0
79
Papers We Love - Immix mark-region garbage collector
brixen
2
680
An Ensemble of Programming Languages: How to Build a Platform for Collaboration
brixen
0
190
Types As Premature Optimization
brixen
2
480
Rubinius X
brixen
3
260
Code Is What Code Does
brixen
0
400
Augmented Ruby: The Rubinius Language Platform
brixen
2
120
The Future of Ruby
brixen
1
320
Rubinius, and the Future of Ruby
brixen
2
240
Featured
See All Featured
How GitHub (no longer) Works
holman
310
140k
Typedesign – Prime Four
hannesfritz
40
2.4k
Site-Speed That Sticks
csswizardry
0
24
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
Scaling GitHub
holman
458
140k
Product Roadmaps are Hard
iamctodd
PRO
49
11k
Art, The Web, and Tiny UX
lynnandtonic
297
20k
Save Time (by Creating Custom Rails Generators)
garrettdimon
PRO
27
840
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
280
13k
A Modern Web Designer's Workflow
chriscoyier
693
190k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
38
1.8k
Evolution of real-time – Irina Nazarova, EuRuKo, 2024
irinanazarova
4
370
Transcript
So you want to design a programming language COPIOUSLabs TechTalk
15 Feb 2013
Brian Shirai Rubinius Developer
there will be a quiz
Questions?
Languages
why are languages fascinating?
practical or fanciful?
Security
28c3: The Science of Insecurity
computability
predictability
None
None
None
None
None
data vs meta-data
None
None
Virtual Machines
Interpreter
Stack vs Register
Jimple
Garbage collection
Concurrency
JIT compiler
None
None
Parsers and compilers
Parsing Expression Grammars
PEGs
github.com/evanphx/kpeg
github.com/wycats/parsejs
LPeg http://www.inf.puc-rio.br/~roberto/lpeg/
None
Rubinius
None
atomy-lang.org
None
fancy-lang.org
Primitives
class Array def [] Ruby.primitive :array_aref raise PrimitiveFailure, "Array#[] primitive
failed" end end
class Array : public Object { private: Fixnum* total_; //
slot Tuple* tuple_; // slot public: attr_accessor(total, Fixnum); attr_accessor(tuple, Tuple); }
class Array : public Object { // Ruby.primitive :array_aref Object*
aref(STATE, Fixnum* idx); }
instruction send_method(literal) [ receiver -- value ] => send flush_ip();
Object* recv = stack_top(); InlineCache* cache = reinterpret_cast<InlineCache*>(literal); Arguments args(cache->name, recv, cNil, 0, 0); Object* ret = cache->execute(state, call_frame, args); (void)stack_pop(); CHECK_AND_PUSH(ret); end
class OneArgument { public: static bool call(STATE, VMMethod* vmm, StackVariables*
scope, Arguments& args) { if(args.total() != 1) return false; scope->set_local(0, args.get_argument(0)); return true; } };
$ rbx irb(main):001:0> def hello(name) irb(main):002:1> puts "hello, #{name}" irb(main):003:1>
end => #<Rubinius::CompiledCode hello file=(irb)>
every CompiledCode object has its own interpreter
def self.compile_string(string, file="(eval)", line=1) compiler = new :string, :compiled_code parser
= compiler.parser parser.root AST::Script parser.default_transforms parser.input string, file, line compiler.run end
$ rbx compile -e 'def m(a, b=1) a + b
end' -N m -B ================== :m ================== Arguments: 1 required, 0 post, 2 total Locals: 2: a, b Stack size: 4 Lines to IP: 1: -1..14 0000: passed_arg 1 0002: goto_if_true 8 0004: meta_push_1 0005: set_local 1 # b 0007: pop 0008: push_local 0 # a 0010: push_local 1 # b 0012: meta_send_op_plus :+ 0014: ret ----------------------------------------
$ rbx compile -e 'def m(a, b=1) a + b
end' -B ============= :__script__ ============== Arguments: 0 required, 0 post, 0 total Locals: 0 Stack size: 5 Lines to IP: 1: 0..15 0000: push_rubinius 0001: push_literal :m 0003: push_literal #<Rubinius::CompiledCode m file=(snippet)> 0005: push_scope 0006: push_variables 0007: send_stack :method_visibility, 0 0010: send_stack :add_defn_method, 4 0013: pop 0014: push_true 0015: ret ----------------------------------------
Ruby
$ rbx irb(main):001:0> m = Rubinius::Executable.new => #<Rubinius::Executable:0xf3c>
irb(main):002:0> def m.call(*args) irb(main):003:1> puts "you rang? #{args.inspect}" irb(main):004:1> end
=> #<Rubinius::CompiledCode call file=(irb)>
irb(main):005:0> sc = m.singleton_class => #<Class:#<Rubinius::Executable:0xf3c>> irb(main):006:0> sc.method_table.store :hi, m,
:public => :hi
irb(main):007:0> m.hi you rang? [#<Rubinius::Executable:0xf3c>, :hi] => nil irb(main):008:0> m.hi
"hello" you rang? [#<Rubinius::Executable:0xf3c>, :hi, "hello"] => nil
Module#dynamic_method
$ rbx irb(main):001:0> class Cat irb(main):002:1> dynamic_method :meow do |g|
irb(main):003:2* g.push :self irb(main):004:2> g.push_literal "meow" irb(main):005:2> g.send :puts, 1, true irb(main):006:2> g.ret irb(main):007:2> end irb(main):008:1> end
=> #<Rubinius::CompiledCode meow file=(dynamic)> irb(main):009:0> Cat.new.meow meow => nil irb(main):010:0>
Tools
Debugger
class Cat def speak puts "woof" end end Cat.new.speak
None
None
None
None
None
github.com/rocky/rbx-trepanning
Profiler
$ rbx -Xprofile -e '10000.times { |x| x * x
+ x * 2 }' Thread 1: total running time: 0.073496367s % cumulative self self total time seconds seconds calls ms/call ms/call name ------------------------------------------------------------ 70.58 0.05 0.05 1 52.05 52.05 Rubinius::Tooling.disable 12.43 0.01 0.01 10000 0.00 0.00 Object::__script__<1> {} 7.24 0.02 0.01 1 5.34 16.74 Integer#times 3.03 0.00 0.00 20000 0.00 0.00 Fixnum#* 1.61 0.00 0.00 1 1.19 1.19 Rubinius::AST::Send#bytecode 1.38 0.00 0.00 1 1.02 2.78 Rubinius::Compiler::Parser#run 1.07 0.00 0.00 1 0.79 3.58 Rubinius::Compiler.compile_eval 0.74 0.00 0.00 4 0.14 0.44 Rubinius::Compiler::Stage#run_next 0.58 0.00 0.00 1 0.42 1.75 Rubinius::Compiler::Generator#run 0.53 0.02 0.00 1 0.39 20.97 Rubinius::Loader#evals 0.19 0.05 0.00 1 0.14 52.19 Rubinius::Profiler::Instrumenter#__stop__ 0.18 0.02 0.00 1 0.13 20.58 Kernel#eval 0.15 0.00 0.00 1 0.11 3.69 Rubinius::Compiler.construct_block 0.09 0.00 0.00 1 0.06 1.25 Rubinius::AST::EvalExpression::bytecode<906> 0.06 0.00 0.00 1 0.05 1.30 Rubinius::AST::Container#container_bytecode 0.05 0.05 0.00 1 0.04 52.25 Rubinius::Loader#epilogue 0.03 0.00 0.00 1 0.02 1.32 Rubinius::AST::EvalExpression#bytecode 0.01 0.00 0.00 1 0.01 2.79 Rubinius::Compiler#run 0.01 0.05 0.00 1 0.01 52.21 Object::__script__<4> {} 0.01 0.02 0.00 1 0.01 16.75 Object::__script__<1> {} 0.01 0.02 0.00 1 0.01 16.75 Rubinius::BlockEnvironment#call_on_instance 0.01 0.05 0.00 1 0.01 52.20 Profiler__.stop_profile 0.01 0.05 0.00 1 0.00 52.19 Rubinius::Profiler::Instrumenter#stop 0.01 0.05 0.00 1 0.00 52.20 Profiler__.print_profile 24 methods called a total of 30,025 times
Agent
$ rbx -Xagent.start irb(main):001:0>
$ rbx console VM: rbx -Xagent.start Connecting to VM on
port 56488 Connected to localhost:56488, host type: x86_64-apple-darw console>
$ console> get system var system = [ "name", "backtrace",
"threads", "gc", "memory", "pid", "jit", ]
$ console> get system.pid var system.pid = [ 69118, ]
$ console> get system.threads var system.threads = [ "count", "backtrace", ] $ console> get system.threads.count var system.threads.count = 2
Memory analysis
require "rubinius/agent" agent = Rubinius::Agent.loopback agent.request :set_config, "system.memory.dump", "before.d array
= (0..10).map { |i| "x" * rand(i) } p array agent.request :set_config, "system.memory.dump", "after.du
$ rbx -I /source/heap_dump/lib/ /source/heap_dump/bin/histo.rb before.dump 20738 Rubinius::Tuple 3763200 5820
Object 279312 5001 Rubinius::MethodTable::Bucket 280056 4388 Rubinius::CompiledMethod 877600 4388 Rubinius::InstructionSequence 140416 3269 String 209216 3166 Rubinius::CharArray 166864 1815 Rubinius::LookupTable::Bucket 87120 1130 Rubinius::LookupTable 54240 1100 Rubinius::GlobalCacheEntry 52800 1047 Rubinius::MethodTable 50256 1001 Class 100384 835 Rubinius::StaticScope 40080 676 Rubinius::AccessVariable 54080 456 Array 25536 141 Hash::Entry 7896 123 Rubinius::CompactLookupTable 15744 105 Rubinius::NativeFunction 10920 102 Rubinius::InstructionSet::OpCode 13872 46 Module 2944 46 Float 1472 46 Rubinius::IncludedModule 3312 39 Rubinius::CompiledMethod::Script 2808 22 Hash 1760
$ rbx -I /source/../lib /source/.../histo.rb before.dump after.dump 54 Object 2592
11 String 704 11 Rubinius::CharArray 440 8 Rubinius::GlobalCacheEntry 384 2 Rubinius::CompactLookupTable 256 2 Rubinius::ByteArray 2624 2 Rubinius::Tuple 184 1 Rubinius::Randomizer 48 1 Bignum 56 1 Rubinius::VariableScope 104 1 Array 56
proc FS
github.com/rubinius github.com/brixen @brixen
Thank you
the most important tech talk to watch this year is
________________.
Questions?