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
85
Papers We Love - Immix mark-region garbage collector
brixen
2
690
An Ensemble of Programming Languages: How to Build a Platform for Collaboration
brixen
0
200
Types As Premature Optimization
brixen
2
490
Rubinius X
brixen
3
270
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
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
jQuery: Nuts, Bolts and Bling
dougneiner
61
7.5k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
48k
A better future with KSS
kneath
238
17k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7k
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
It's Worth the Effort
3n
183
28k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
111
49k
Fontdeck: Realign not Redesign
paulrobertlloyd
82
5.3k
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
YesSQL, Process and Tooling at Scale
rocio
169
14k
Six Lessons from altMBA
skipperchong
27
3.5k
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?