forked from JavascriptNet/Javascript.Net
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathJavascriptContext.h
272 lines (209 loc) · 9.89 KB
/
JavascriptContext.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
////////////////////////////////////////////////////////////////////////////////////////////////////
// File: JavascriptContext.h
//
// Copyright 2010 Noesis Innovation Inc. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once
////////////////////////////////////////////////////////////////////////////////////////////////////
#include <v8.h>
#include <string>
#include <vector>
#include "JavascriptStackFrame.h"
////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Noesis { namespace Javascript {
////////////////////////////////////////////////////////////////////////////////////////////////////
using namespace v8;
using namespace std;
////////////////////////////////////////////////////////////////////////////////////////////////////
class JavascriptExternal;
[System::Flags]
public enum class SetParameterOptions : int
{
None = 0,
RejectUnknownProperties = 1
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// WrappedMethod
//
// Type-safely wraps a native pointer for inclusion in managed code as an IntPtr. I thought
// there would already be something for this, but I couldn't find it.
////////////////////////////////////////////////////////////////////////////////////////////////////
public value struct WrappedMethod
{
private:
System::IntPtr pointer;
internal:
WrappedMethod(Persistent<Function> *value)
{
System::IntPtr value_pointer(value);
pointer = value_pointer;
}
property Persistent<Function> *Pointer
{
Persistent<Function> *get()
{
return (Persistent<Function> *)(void *)pointer;
}
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// WrappedJavascriptExternal
//
// See comment in WrappedMethod.
////////////////////////////////////////////////////////////////////////////////////////////////////
public value struct WrappedJavascriptExternal
{
private:
System::IntPtr pointer;
internal:
WrappedJavascriptExternal(JavascriptExternal *value)
{
System::IntPtr value_pointer(value);
pointer = value_pointer;
}
property JavascriptExternal *Pointer
{
JavascriptExternal *get()
{
return (JavascriptExternal *)(void *)pointer;
}
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// JavascriptContext
//
// This is the interface provided to our C# code.
//
// Being a CLR data structure, this cannot be seen by x86 code.
////////////////////////////////////////////////////////////////////////////////////////////////////
public ref class JavascriptContext: public System::IDisposable
{
////////////////////////////////////////////////////////////
// Constructor
////////////////////////////////////////////////////////////
public:
static JavascriptContext();
JavascriptContext();
~JavascriptContext();
////////////////////////////////////////////////////////////
// Public methods
////////////////////////////////////////////////////////////
public:
void SetParameter(System::String^ iName, System::Object^ iObject);
void SetParameter(System::String^ iName, System::Object^ iObject, SetParameterOptions options);
generic <typename AssociatedType> void SetConstructor(System::String^ name, System::Delegate^ constructor);
void SetConstructor(System::String^ name, System::Type^ associatedType, System::Delegate^ constructor);
System::Object^ GetParameter(System::String^ iName);
virtual System::Object^ Run(System::String^ iSourceCode);
virtual System::Object^ Run(System::String^ iScript, System::String^ iScriptResourceName);
property static System::String^ V8Version { System::String^ get(); }
System::Collections::Generic::List<JavascriptStackFrame^>^ GetCurrentStack(int maxDepth);
void TerminateExecution();
// terminate_subsequent_runs allows you to avoid the race condition
// that occurs if you haven't yet called Run(), and you
// know your context is being constructed for a single execution.
void TerminateExecution(bool terminate_subsequent_runs);
bool IsExecutionTerminating();
void Collect();
// Fatal errors can occur when v8 runs out of memory. Your process
// will exit immediately after this handler is called, because
// that's just how v8 works.
// (http://stackoverflow.com/questions/16797423/how-to-handle-v8-engine-crash-when-process-runs-out-of-memory)
//
// Call this just once for the whole library.
delegate void FatalErrorHandler(System::String^ location, System::String^ message);
static void SetFatalErrorHandler(FatalErrorHandler^ handler);
static void SetFlags(System::String^ flags);
////////////////////////////////////////////////////////////
// Internal methods
////////////////////////////////////////////////////////////
internal:
//void SetStackLimit();
static JavascriptContext^ GetCurrent();
static v8::Isolate *GetCurrentIsolate();
Local<v8::Object> GetGlobal();
v8::Locker *Enter([System::Runtime::InteropServices::Out] JavascriptContext^% old_context);
void Exit(v8::Locker *locker, JavascriptContext^ old_context);
JavascriptExternal* WrapObject(System::Object^ iObject);
Local<FunctionTemplate> GetObjectWrapperConstructorTemplate(System::Type ^type);
static void FatalErrorCallbackMember(const char* location, const char* message);
inline bool IsDisposed() { return mContext == nullptr; }
////////////////////////////////////////////////////////////
// Data members
////////////////////////////////////////////////////////////
internal:
// Stores every JavascriptExternal we create. This saves time if the same
// objects are recreated frequently, and stops us building up a huge
// collection of JavascriptExternal objects that won't be freed until
// the context is destroyed.
System::Collections::Generic::Dictionary<System::Object^, WrappedJavascriptExternal>^ mExternals;
System::Collections::Generic::Dictionary<System::String^, WrappedMethod>^ mMethods;
protected:
// By entering an isolate before using a context, we can have multiple
// contexts used simultaneously in different threads.
v8::Isolate *isolate;
// v8 context required to be active for all v8 operations.
Persistent<Context>* mContext;
// Maps types to their constructor function templates
// The mapping will either be defined by the user calling `SetConstructor` or autogenerated if no
// mapping was provided.
// The `IntPtr` points to a `Persistent<FunctionTemplate>`.
System::Collections::Generic::Dictionary<System::Type ^, System::IntPtr> ^mTypeToConstructorMapping;
// See comment for TerminateExecution().
bool terminateRuns;
// Keeping track of recursion.
[System::ThreadStaticAttribute] static JavascriptContext ^sCurrentContext;
static FatalErrorHandler^ fatalErrorHandler;
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// JavascriptScope
//
// This must be constructed before any use of handles or calling of v8
// functions. It protects against simultaneous multithreaded use of v8.
////////////////////////////////////////////////////////////////////////////////////////////////////
ref class JavascriptScope
{
// It is OK to nest v8::Lockers in one thread.
v8::Locker *v8ThreadLock;
JavascriptContext^ oldContext;
public:
JavascriptScope(JavascriptContext^ iContext)
{
// We store the old context so that JavascriptContexts can be created and run
// recursively.
v8ThreadLock = iContext->Enter(oldContext);
}
~JavascriptScope()
{
JavascriptContext::GetCurrent()->Exit(v8ThreadLock, oldContext);
}
};
////////////////////////////////////////////////////////////////////////////////////////////////////
// Standalone functions - can be called from unmanaged code too
////////////////////////////////////////////////////////////////////////////////////////////////////
Local<Script> CompileScript(v8::Isolate *isolate, wchar_t const *source_code, wchar_t const *resource_name = NULL);
////////////////////////////////////////////////////////////////////////////////////////////////////
} } // namespace Noesis::Javascript
////////////////////////////////////////////////////////////////////////////////////////////////////