JSRootingGuide: main.cpp

File main.cpp, 5.3 KB (added by Yves, 10 years ago)

Main.cpp for the heap rooting example

Line 
1#include <fstream>
2#include <iostream>
3#include <memory>
4
5#include "SpiderMonkeyInclude.h"
6
7using namespace std;
8
9class CTestClassBase
10{
11public:
12 CTestClassBase(JSRuntime* rt, JSContext* cx) : m_rt(rt), m_cx(cx) {}
13
14protected:
15
16 JSObject* InitObjectInternal()
17 {
18 //objStack.set(JS_NewObject(m_cx, nullptr, JS::NullPtr(), JS::NullPtr()));
19 JS::RootedObject obj(m_cx, JS_NewObject(m_cx, nullptr, JS::NullPtr(), JS::NullPtr()));
20 JS::RootedValue intVal(m_cx, JS::Int32Value(0));
21 JS_SetProperty(m_cx, obj, "useCounter", intVal);
22 return obj.get();
23 }
24
25 void PrintUsecountBase(JS::HandleObject objStack)
26 {
27 int32_t tmpCounter;
28 JS::RootedValue counterValStack(m_cx);
29
30 if (!JS_GetProperty(m_cx, objStack, "useCounter", &counterValStack))
31 cerr << "Error: JS_GetProperty on m_HeapValue for property useCounter failed!" << endl;
32
33 if (!JS::ToInt32(m_cx, counterValStack, &tmpCounter))
34 cerr << "Error in JS::ToInt32!" << endl;
35
36 cout << "function has alread been called " << tmpCounter++ << " times." << endl;
37
38 JS::RootedValue tmpCounterVal(m_cx, JS::Int32Value(tmpCounter));
39 JS_SetProperty(m_cx, objStack, "useCounter", tmpCounterVal);
40 }
41
42 JSRuntime* m_rt;
43 JSContext* m_cx;
44};
45
46#include "HeapRootingTest.h"
47
48JSRuntime *rt = NULL;
49std::shared_ptr<CHeapRootingTest> g_HeapRootingTest;
50
51/* The class of the global object. */
52static JSClass global_class = { "global", JSCLASS_GLOBAL_FLAGS,
53JS_PropertyStub, JS_DeletePropertyStub,
54JS_PropertyStub, JS_StrictPropertyStub,
55JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
56nullptr, nullptr, nullptr, nullptr,
57JS_GlobalObjectTraceHook };
58
59void reportError(JSContext *cx, const char *message, JSErrorReport *report) {
60 fprintf(stderr, "%s:%u:%s\n",
61 report->filename ? report->filename : "<no filename="">",
62 (unsigned int) report->lineno,
63 message);
64}
65
66const char* readFile(const char*);
67void loadScript(JSContext* cx, JS::HandleObject global);
68bool myjs_print(JSContext *cx, uint32_t argc, jsval *vp);
69bool myjs_heapExample(JSContext *cx, uint32_t argc, jsval *vp);
70
71static JSClass test_class = { "testclass", 0,
72JS_PropertyStub, JS_DeletePropertyStub,
73JS_PropertyStub, JS_StrictPropertyStub,
74JS_EnumerateStub, JS_ResolveStub,
75JS_ConvertStub,
76JSCLASS_NO_OPTIONAL_MEMBERS };
77
78JSFunctionSpec myjs_global_functions[] = {
79 JS_FS("print", &(myjs_print), 1, 0),
80 JS_FS("heapExample", &(myjs_heapExample), 0, 0),
81 JS_FS_END
82};
83
84void bar(JS::Value val)
85{
86}
87
88void foo(JSContext* cx, JS::HandleValue handleVal, JS::MutableHandleValue mutableHandleVal)
89{
90 JS::RootedValue val(cx);
91 bar(val);
92 bar(handleVal);
93 bar(mutableHandleVal);
94}
95
96int run(JSContext *cx) {
97 /* Enter a request before running anything in the context */
98 JSAutoRequest ar(cx);
99
100 /* Create the global object in a new compartment. */
101 JS::RootedObject global(cx, JS_NewGlobalObject(cx, &global_class, nullptr, JS::FireOnNewGlobalHook));
102 if (!global)
103 return 1;
104
105 /* Set the context's global */
106 JSAutoCompartment ac(cx, global);
107
108 /* Populate the global object with the standard globals, like Object and Array. */
109 if (!JS_InitStandardClasses(cx, global))
110 return 1;
111
112 /* Your application code here. This may include JSAPI calls to create your own custom JS objects and run scripts. */
113 JS_DefineFunctions(cx, global, myjs_global_functions);
114 g_HeapRootingTest.reset(new CHeapRootingTest(rt, cx));
115
116 loadScript(cx, global);
117
118 /* Application code end */
119
120 return 0;
121}
122
123int main(int argc, const char *argv[]) {
124 /* Initialize the JS engine -- new/required as of SpiderMonkey 31. */
125 if (!JS_Init())
126 return 1;
127
128 /* Create a JS runtime. */
129 rt = JS_NewRuntime(8L * 1024L * 1024L, JS_NO_HELPER_THREADS);
130 if (!rt)
131 return 1;
132
133 /* Create a context. */
134 JSContext *cx = JS_NewContext(rt, 8192);
135 if (!cx)
136 return 1;
137
138 JS_SetErrorReporter(cx, reportError);
139
140 int status = run(cx);
141
142 JS_GC(rt);
143 g_HeapRootingTest.reset();
144 JS_DestroyContext(cx);
145 JS_DestroyRuntime(rt);
146
147 /* Shut down the JS engine. */
148 JS_ShutDown();
149
150 int x=0;
151 cin >> x;
152}
153
154void loadScript(JSContext* cx, JS::HandleObject global)
155{
156 const char* script = readFile("../../test.js");
157 bool ok;
158 const char *filename = "test.js";
159 unsigned lineno = 0;
160
161 JSAutoRequest rq(cx);
162 ok = JS_EvaluateScript(cx, global, script, strlen(script), filename, lineno);
163}
164
165const char* readFile(const char* scriptFile)
166{
167 ifstream file;
168 char* content;
169 int length;
170
171 file.open(scriptFile, ifstream::in);
172
173 // get length of file:
174 file.seekg (0, ios::end);
175 length = file.tellg();
176 file.seekg (0, ios::beg);
177
178 // allocate memory (+1 for null-termination)
179 content = new char[length+1];
180 file.read(content, length);
181 file.close();
182 content[length] = '\0';
183
184 return content;
185}
186
187/**
188 * The function prints a counter how often it has been called already.
189 * This counter gets stored as a JS value on the heap.
190 * It's used to test some assumptions about rooting on the heap because the documentation lacks a bit.
191 */
192
193bool myjs_heapExample(JSContext *cx, uint32_t argc, jsval *vp)
194{
195 g_HeapRootingTest->PrintUsecount();
196 return true;
197}
198
199bool myjs_print(JSContext *cx, uint32_t argc, jsval *vp)
200{
201 JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
202 JS::CallReceiver rec = JS::CallReceiverFromVp(vp);
203
204 JS::RootedString str(cx, args[0].toString());
205 char* text = JS_EncodeString(cx, str);
206
207 cout << text << endl;
208
209 rec.rval().set(JSVAL_VOID); // return undefined
210
211 return true;
212}