h8 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +8 -0
- data/README.md +55 -2
- data/ext/h8/JsCatcher.cpp +24 -0
- data/ext/h8/JsCatcher.h +29 -0
- data/ext/h8/allocated_resource.h +37 -0
- data/ext/h8/chain.h +191 -0
- data/ext/h8/extconf.rb +48 -30
- data/ext/h8/h8.cpp +100 -8
- data/ext/h8/h8.h +109 -42
- data/ext/h8/js_gate.cpp +18 -0
- data/ext/h8/js_gate.h +70 -31
- data/ext/h8/main.cpp +69 -25
- data/ext/h8/object_wrap.h +1 -1
- data/ext/h8/ruby_gate.cpp +117 -0
- data/ext/h8/ruby_gate.h +118 -0
- data/hybrid8.gemspec +3 -1
- data/lib/h8.rb +61 -2
- data/lib/h8/context.rb +38 -5
- data/lib/h8/value.rb +104 -19
- data/lib/h8/version.rb +1 -1
- data/spec/context_spec.rb +42 -4
- data/spec/js_gate_spec.rb +95 -16
- data/spec/ruby_gate_spec.rb +159 -0
- data/spec/spec_helper.rb +31 -1
- metadata +15 -4
- data/ext/h8/ruby_wrap.h +0 -32
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a72940e0db998af017aa93553d91b90eefe2662c
|
4
|
+
data.tar.gz: b2d87d6c19c23c983cdc00b60bf874d921133f29
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 713eedbe21d86dcaeac35d3d3d052af41bb36fc9ff434c096fa1c15f95299194c1fce45945150ac8f8ad77fb8732fa2acbbe7e6c9a4d37aa6fca82e3cf075387
|
7
|
+
data.tar.gz: d0ff9c201ae06798b57d1c80bcb471f72a5bc29b8e4e3404b33df1ec689422472efc2e547836df50846f955d6aca441e2ab81488853d3e26af25f63ab85dec15
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# Hybrid8, aka H8
|
2
2
|
|
3
|
-
_Warning_ this gem
|
4
|
-
|
3
|
+
_Warning_ this gem functionality is almost complete but it lacks of testing and some features
|
4
|
+
(see below). This is a working (or better say, test passing) alpha. Beta suitable versions
|
5
|
+
will start from 0.1.*.
|
5
6
|
|
6
7
|
Therubyracer gem alternative to effectively work with ruby 2.1+ in multithreaded environment in an
|
7
8
|
effective and GC-safe way. Should be out of the box replacement for most scenarios.
|
@@ -16,6 +17,29 @@ javascript context
|
|
16
17
|
while there are ruby objects referencing it. It also means that once created H8::Context will not
|
17
18
|
be reclaimed as long as there is at least one active wrapped object returned from the script.
|
18
19
|
|
20
|
+
- you can pass ruby objects from ruby code called from javascript back to the ruby code intact.
|
21
|
+
Ruby objects are automatically wrapped in js code and unwrapped in ruby code (you might need to
|
22
|
+
call #to_ruby)
|
23
|
+
|
24
|
+
- Uncaught ruby exceptions are thrown as javascript exceptions in javascript code. The same,
|
25
|
+
uncaught javascript exceptions raise ruby error in ruby code.
|
26
|
+
|
27
|
+
## Main difference from therubyracer/features not ready
|
28
|
+
|
29
|
+
*This version is not (yet?) thread safe*. For the sake of effectiveness, do not access same
|
30
|
+
H8::Context and its returned values from concurrent threads. Use Mutexes!
|
31
|
+
|
32
|
+
- correct and accurate object tracking in both JS and Ruby VMs, GC aware.
|
33
|
+
|
34
|
+
- passed thru objects and exceptions in js -> ruby -> js -> ruby chains are usually kept unchanged,
|
35
|
+
e.g. wrapped in one language then unwrapped when passed to the original language
|
36
|
+
|
37
|
+
- Not Yet: source information in uncaught exception in js
|
38
|
+
|
39
|
+
- Script is executed in the calling ruby thread without unblocking it (for the sake of
|
40
|
+
effectiveness). If we would release GIL and reacquire it, it would take more time. And there is no
|
41
|
+
multithreading support yet (this one might be added soon).
|
42
|
+
|
19
43
|
## Installation
|
20
44
|
|
21
45
|
### Prerequisites
|
@@ -23,6 +47,33 @@ be reclaimed as long as there is at least one active wrapped object returned fro
|
|
23
47
|
You should have installed libv8, use latest version with v8::Isolate and v8::Locker. This version
|
24
48
|
may not find you installation, contact me if you have problems, I'll tune it up.
|
25
49
|
|
50
|
+
#### Macos (10.9 maybe+)
|
51
|
+
|
52
|
+
The working process:
|
53
|
+
|
54
|
+
install v8 from sources 3.31.77 (or try newer), then execute:
|
55
|
+
|
56
|
+
gclient update
|
57
|
+
export CXXFLAGS='-std=c++11 -stdlib=libc++ -mmacosx-version-min=10.9'
|
58
|
+
export LDFLAGS=-lc++
|
59
|
+
make native
|
60
|
+
exportexport V8_3_31_ROOT=`pwd` # or somehow else set it
|
61
|
+
|
62
|
+
Note that exporting symbols is a hack that may not be in need anymore. After that the gem should
|
63
|
+
install normally.
|
64
|
+
|
65
|
+
#### Debian and like
|
66
|
+
|
67
|
+
Install first a valid v8 version. We provide a ready package!
|
68
|
+
|
69
|
+
sudo apt-get install libv8-3.31-dev
|
70
|
+
|
71
|
+
It should install prerequisites, if not, manually install
|
72
|
+
|
73
|
+
sudo apt-get install libicu-dev
|
74
|
+
|
75
|
+
You might also need to install GMP.
|
76
|
+
|
26
77
|
### Setting up
|
27
78
|
|
28
79
|
Add this line to your application's Gemfile:
|
@@ -93,3 +144,5 @@ wheel.
|
|
93
144
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
94
145
|
4. Push to the branch (`git push origin my-new-feature`)
|
95
146
|
5. Create a new Pull Request
|
147
|
+
|
148
|
+
|
@@ -0,0 +1,24 @@
|
|
1
|
+
/*
|
2
|
+
* JsCatcher.cpp
|
3
|
+
*
|
4
|
+
* Created on: Dec 23, 2014
|
5
|
+
* Author: sergeych
|
6
|
+
*/
|
7
|
+
|
8
|
+
#include "JsCatcher.h"
|
9
|
+
|
10
|
+
namespace h8 {
|
11
|
+
|
12
|
+
|
13
|
+
JsCatcher::JsCatcher(H8* h8) : h8(h8), v8::TryCatch(h8->getIsolate()) {}
|
14
|
+
|
15
|
+
void JsCatcher::throwIfCaught() {
|
16
|
+
if( HasCaught() ) {
|
17
|
+
if( !CanContinue() && HasTerminated() ) {
|
18
|
+
throw JsTimeoutError(h8);
|
19
|
+
}
|
20
|
+
throw JsError(h8, Message(), Exception());
|
21
|
+
}
|
22
|
+
}
|
23
|
+
|
24
|
+
} /* namespace h8 */
|
data/ext/h8/JsCatcher.h
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
/*
|
2
|
+
* JsCatcher.h
|
3
|
+
*
|
4
|
+
* Created on: Dec 23, 2014
|
5
|
+
* Author: sergeych
|
6
|
+
*/
|
7
|
+
|
8
|
+
#ifndef JSCATCHER_H_
|
9
|
+
#define JSCATCHER_H_
|
10
|
+
|
11
|
+
#include <include/v8.h>
|
12
|
+
#include "h8.h"
|
13
|
+
|
14
|
+
namespace h8 {
|
15
|
+
|
16
|
+
class H8;
|
17
|
+
|
18
|
+
class JsCatcher : public v8::TryCatch {
|
19
|
+
public:
|
20
|
+
JsCatcher(H8* h8);
|
21
|
+
|
22
|
+
void throwIfCaught();
|
23
|
+
private:
|
24
|
+
H8* h8;
|
25
|
+
};
|
26
|
+
|
27
|
+
} /* namespace h8 */
|
28
|
+
|
29
|
+
#endif /* JSCATCHER_H_ */
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#ifndef __allocated_resource
|
2
|
+
#define __allocated_resource
|
3
|
+
|
4
|
+
#include "chain.h"
|
5
|
+
|
6
|
+
namespace h8 {
|
7
|
+
|
8
|
+
/**
|
9
|
+
* Resource that allocates anything that is tied to Isolate and should be
|
10
|
+
* freed _before_ isolate is destroyed.
|
11
|
+
*
|
12
|
+
* (1) derive any of such your resources from it
|
13
|
+
* (2) register them in the parent H8 (h8->add_resource())
|
14
|
+
* (3) free() resource in free(), then call unlink()/super
|
15
|
+
* (4) free all resources in the destructor if any.
|
16
|
+
*/
|
17
|
+
class AllocatedResource : public chain::link {
|
18
|
+
public:
|
19
|
+
/**
|
20
|
+
* If your resource references any ruby object, be sure to mark them
|
21
|
+
* all overriding this method!
|
22
|
+
*/
|
23
|
+
virtual void rb_mark_gc() {};
|
24
|
+
|
25
|
+
virtual void free() {
|
26
|
+
unlink();
|
27
|
+
};
|
28
|
+
|
29
|
+
/* Default implementation does nothing but call unlink throgh parent
|
30
|
+
* destructor
|
31
|
+
*/
|
32
|
+
virtual ~AllocatedResource() {};
|
33
|
+
};
|
34
|
+
|
35
|
+
}
|
36
|
+
|
37
|
+
#endif
|
data/ext/h8/chain.h
ADDED
@@ -0,0 +1,191 @@
|
|
1
|
+
#ifndef __chain_h
|
2
|
+
#define __chain_h
|
3
|
+
|
4
|
+
#include <assert.h>
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Copyright (C) by Sergey S. Chernov, iCodici S.n.C
|
8
|
+
*
|
9
|
+
* Free software under MIT license.
|
10
|
+
*
|
11
|
+
* Extremely fast minimalistic double linked list.
|
12
|
+
*
|
13
|
+
* List item derives from chain::link. List item can not be inserted in
|
14
|
+
* more than one list. Linking chain::link into other list removes it
|
15
|
+
* from any other list. Unlinked chain::link links to self.
|
16
|
+
*
|
17
|
+
* Not thread safe! Inserting and removing in any position of the list
|
18
|
+
* is O(1) operation, iterating is O(N) operation.
|
19
|
+
*
|
20
|
+
* Typical usages:
|
21
|
+
*
|
22
|
+
* minimal:
|
23
|
+
* Use any chain::link instance as a root of you list. You can do
|
24
|
+
* everything with it without creating chain instance
|
25
|
+
*
|
26
|
+
* typical:
|
27
|
+
* create chain instance and feed it with chain::instance derivatives.
|
28
|
+
* does the same as above but provide more commonly used unterface
|
29
|
+
* (actually it is a wrapped chain::link item)
|
30
|
+
*/
|
31
|
+
class chain {
|
32
|
+
public:
|
33
|
+
class link;
|
34
|
+
|
35
|
+
/**
|
36
|
+
* Iterator that can iterate over either chain or even chain::link
|
37
|
+
* item (in which case it iterates from a given link and traverses
|
38
|
+
* all the list
|
39
|
+
*/
|
40
|
+
class iterator {
|
41
|
+
public:
|
42
|
+
iterator(link *start) :
|
43
|
+
current(start) {
|
44
|
+
}
|
45
|
+
|
46
|
+
bool operator !=(const iterator& other) const {
|
47
|
+
return current != other.current;
|
48
|
+
}
|
49
|
+
|
50
|
+
const iterator& operator++() {
|
51
|
+
current = current->next;
|
52
|
+
return *this;
|
53
|
+
}
|
54
|
+
|
55
|
+
link* operator*() const {
|
56
|
+
return current;
|
57
|
+
}
|
58
|
+
|
59
|
+
private:
|
60
|
+
link *current;
|
61
|
+
};
|
62
|
+
|
63
|
+
/**
|
64
|
+
* chain list item. Can be used as a list itself: can be iterated, can insert items,
|
65
|
+
* can provide head and tail items and any of its linked items can be easily removed
|
66
|
+
*/
|
67
|
+
class link {
|
68
|
+
public:
|
69
|
+
/// Create empty list item (which is locked to itself)
|
70
|
+
link() {
|
71
|
+
next = prev = this;
|
72
|
+
}
|
73
|
+
|
74
|
+
/// Leave whatever chain it is in (or do nothing)
|
75
|
+
void unlink() {
|
76
|
+
next->prev = prev;
|
77
|
+
prev->next = next;
|
78
|
+
next = prev = this;
|
79
|
+
}
|
80
|
+
|
81
|
+
// Insert in the chain after the specified item
|
82
|
+
void link_after(link *left) {
|
83
|
+
unlink();
|
84
|
+
next = left->next;
|
85
|
+
left->next = this;
|
86
|
+
prev = left;
|
87
|
+
next->prev = this;
|
88
|
+
}
|
89
|
+
|
90
|
+
/**
|
91
|
+
* @return true if this is the only item in the list (this is not connected
|
92
|
+
* to any other item)
|
93
|
+
*/
|
94
|
+
bool is_disconnected() const {
|
95
|
+
return next == prev && next == this;
|
96
|
+
}
|
97
|
+
|
98
|
+
/**
|
99
|
+
* Get the next item in the list.
|
100
|
+
*
|
101
|
+
* @return this if the list is empty
|
102
|
+
*/
|
103
|
+
template<class T>
|
104
|
+
T* get_next() {
|
105
|
+
return (T*) (next);
|
106
|
+
}
|
107
|
+
|
108
|
+
/**
|
109
|
+
* Get the previous item in the list.
|
110
|
+
*
|
111
|
+
* @return this if the list is empty
|
112
|
+
*/
|
113
|
+
template<class T>
|
114
|
+
T* get_prev() {
|
115
|
+
return (T*) (prev);
|
116
|
+
}
|
117
|
+
|
118
|
+
~link() {
|
119
|
+
unlink();
|
120
|
+
}
|
121
|
+
|
122
|
+
chain::iterator begin() const {
|
123
|
+
return iterator(next);
|
124
|
+
}
|
125
|
+
|
126
|
+
chain::iterator end() const {
|
127
|
+
return iterator(const_cast<link*>(this));
|
128
|
+
}
|
129
|
+
|
130
|
+
private:
|
131
|
+
link *next, *prev;
|
132
|
+
friend class chain;
|
133
|
+
};
|
134
|
+
|
135
|
+
iterator begin() const {
|
136
|
+
return root.begin();
|
137
|
+
}
|
138
|
+
|
139
|
+
iterator end() const {
|
140
|
+
return root.end();
|
141
|
+
}
|
142
|
+
|
143
|
+
/**
|
144
|
+
* Add item to the tail of the list
|
145
|
+
*/
|
146
|
+
void push(link* item) {
|
147
|
+
item->link_after(root.prev);
|
148
|
+
}
|
149
|
+
|
150
|
+
void push_first(link* item) {
|
151
|
+
item->link_after(&root);
|
152
|
+
}
|
153
|
+
|
154
|
+
template<class T>
|
155
|
+
T* peek_first() {
|
156
|
+
return (T*) root.next;
|
157
|
+
}
|
158
|
+
|
159
|
+
template<class T>
|
160
|
+
T* peek_last() {
|
161
|
+
return (T*) root.prev;
|
162
|
+
}
|
163
|
+
|
164
|
+
/**
|
165
|
+
* Convenience method: removes head item (if any) and returns it.
|
166
|
+
* Actually, you can get any item from the list (using peek_head(), peek_tail() or iterating
|
167
|
+
* the list) and then remove it from the list (@see chain::link#unlink()) - it is effective and
|
168
|
+
* simple way.
|
169
|
+
*
|
170
|
+
* @return detached head item or NULL
|
171
|
+
*/
|
172
|
+
template<class T>
|
173
|
+
T* pop() {
|
174
|
+
if (root.is_disconnected())
|
175
|
+
return 0;
|
176
|
+
link *first = root.next;
|
177
|
+
first->unlink();
|
178
|
+
return (T*) first;
|
179
|
+
}
|
180
|
+
|
181
|
+
bool is_empty() const {
|
182
|
+
return root.is_disconnected();
|
183
|
+
}
|
184
|
+
|
185
|
+
private:
|
186
|
+
// Root item default constructor is enough
|
187
|
+
link root;
|
188
|
+
|
189
|
+
};
|
190
|
+
|
191
|
+
#endif
|
data/ext/h8/extconf.rb
CHANGED
@@ -16,44 +16,63 @@
|
|
16
16
|
|
17
17
|
require "mkmf"
|
18
18
|
|
19
|
+
cxx11flag = " --std=c++11"
|
20
|
+
|
21
|
+
$CXXFLAGS = CONFIG["CXXFLAGS"] unless defined?($CXXFLAGS)
|
22
|
+
$CXXFLAGS += cxx11flag unless $CXXFLAGS.include?(cxx11flag)
|
19
23
|
|
20
24
|
abort 'missing malloc()' unless have_func 'malloc'
|
21
25
|
abort 'missing free()' unless have_func 'free'
|
22
26
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
27
|
+
begin
|
28
|
+
|
29
|
+
# Give it a name
|
30
|
+
extension_name = 'h8'
|
31
|
+
|
32
|
+
chk_headers = ['include/v8.h']
|
33
|
+
chk_libs = %w(v8_base v8_libbase v8_libplatform v8_snapshot icudata icui18n icuuc)
|
34
|
+
|
35
|
+
case RbConfig::CONFIG['target_os']
|
36
|
+
when /darwin/
|
37
|
+
v8_path = ENV['V8_3_31_ROOT'] or raise "Please give me export V8_3_31_ROOT=..."
|
38
|
+
# dir_config('v8', '/Users/sergeych/dev/v8', '/Users/sergeych/dev/v8/out/native')
|
39
|
+
dir_config('v8', v8_path, v8_path+'/out/native')
|
40
|
+
CONFIG['CXXFLAGS'] += ' --std=c++11'
|
41
|
+
else
|
42
|
+
# example linux package https://github.com/porzione/v8-git-debian
|
43
|
+
dir_config('v8', '/usr/include/libv8-3.31', '/usr/lib/libv8-3.31')
|
44
|
+
# force static, but system icu
|
45
|
+
$LOCAL_LIBS = chk_libs.reject { |l| l.match /^icu/ }.map { |l| "-l#{l}" }.join(" ")
|
46
|
+
end
|
47
|
+
|
48
|
+
dir_config(extension_name)
|
49
|
+
|
50
|
+
chk_headers.each do |h|
|
51
|
+
unless have_header(h)
|
52
|
+
raise "can't find v8 header '#{h}', install libv8 3.31+ first"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
chk_libs.each do |lib|
|
57
|
+
unless have_library(lib)
|
58
|
+
raise "can't find v8 lib '#{lib}'"
|
59
|
+
end
|
60
|
+
end
|
42
61
|
|
43
62
|
# This test is actually due to a Clang 3.3 shortcoming, included in OS X 10.9,
|
44
63
|
# fixed in Clang 3.4:
|
45
64
|
# http://llvm.org/releases/3.4/tools/clang/docs/ReleaseNotes.html#new-compiler-flags
|
46
|
-
if try_compile('', '-O6')
|
47
|
-
|
48
|
-
else
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
CONFIG['CXXFLAGS'] += " --std=c++11"
|
65
|
+
# if try_compile('', '-O6')
|
66
|
+
# $CFLAGS += ' -Wall -W -O6 -g'
|
67
|
+
# else
|
68
|
+
# $CFLAGS += ' -Wall -W -O3 -g'
|
69
|
+
# end
|
53
70
|
|
54
|
-
|
71
|
+
# create_makefile('h8/h8')
|
55
72
|
create_makefile(extension_name)
|
56
|
-
|
73
|
+
rescue
|
74
|
+
$stderr.puts "*********************************************************************"
|
75
|
+
$stderr.puts "\n#{$!}\n\n"
|
57
76
|
$stderr.puts "*********************************************************************"
|
58
77
|
$stderr.puts "Your compiler was unable to link to all necessary libraries"
|
59
78
|
$stderr.puts "Please install all prerequisites first"
|
@@ -62,7 +81,7 @@ else
|
|
62
81
|
raise "Unable to build, correct above errors and rerun"
|
63
82
|
end
|
64
83
|
|
65
|
-
# LIBV8_COMPATIBILITY = '~> 3.
|
84
|
+
# LIBV8_COMPATIBILITY = '~> 3.31'
|
66
85
|
#
|
67
86
|
# begin
|
68
87
|
# require 'rubygems'
|
@@ -77,5 +96,4 @@ end
|
|
77
96
|
#
|
78
97
|
# Libv8.configure_makefile
|
79
98
|
|
80
|
-
create_makefile('h8/h8')
|
81
99
|
|