Skip to content
This repository was archived by the owner on Mar 29, 2024. It is now read-only.

Commit f1519a9

Browse files
committed
Add script compiler
1 parent fa7840f commit f1519a9

13 files changed

+1267
-2
lines changed

config.m4

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ if test "$PHP_V8" != "no"; then
170170
src/php_v8_unbound_script.cc \
171171
src/php_v8_cached_data.cc \
172172
src/php_v8_compile_options.cc \
173+
src/php_v8_script_compiler.cc \
173174
src/php_v8_source.cc \
174175
src/php_v8_data.cc \
175176
src/php_v8_value.cc \

src/php_v8_callbacks.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ void php_v8_callback_call_from_bucket_with_zargs(size_t index, v8::Local<v8::Val
268268
ZVAL_ZVAL(retval, fci.retval, 1, 1);
269269
}
270270

271-
// TODO: what about exceptions? - we let user handle any case of exceptions for themself
271+
// TODO: what about exceptions? - we let user handle any case of exceptions for themselves
272272

273273
/* Clean up our mess */
274274
zend_fcall_info_args_clear(&fci, 1);

src/php_v8_exceptions.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ extern void php_v8_throw_try_catch_exception(php_v8_context_t *php_v8_context, v
108108
//#define PHP_V8_CHECK_EMPTY_HANDLER(val, message) if (NULL == (val)->php_v8_isolate || (val)->persistent->IsEmpty()) { PHP_V8_THROW_EXCEPTION(message); return; }
109109
// we check handler to be !IsEmpty() in constructors and before value creations, so unless we didn't check that by mistacke, IsEmpty() check may be skipped
110110
#define PHP_V8_CHECK_EMPTY_HANDLER(val, message) if (NULL == (val)->php_v8_isolate) { PHP_V8_THROW_EXCEPTION(message); return; }
111+
#define PHP_V8_CHECK_EMPTY_HANDLER_RET(val, message, ret) if (NULL == (val)->php_v8_isolate) { PHP_V8_THROW_EXCEPTION(message); return (ret); }
111112

112113

113114
PHP_MINIT_FUNCTION(php_v8_exceptions);

src/php_v8_script_compiler.cc

Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
/*
2+
* This file is part of the pinepain/php-v8 PHP extension.
3+
*
4+
* Copyright (c) 2015-2017 Bogdan Padalko <[email protected]>
5+
*
6+
* Licensed under the MIT license: http://opensource.org/licenses/MIT
7+
*
8+
* For the full copyright and license information, please view the
9+
* LICENSE file that was distributed with this source or visit
10+
* http://opensource.org/licenses/MIT
11+
*/
12+
13+
#ifdef HAVE_CONFIG_H
14+
#include "config.h"
15+
#endif
16+
17+
#include "php_v8_script_compiler.h"
18+
#include "php_v8_compile_options.h"
19+
#include "php_v8_cached_data.h"
20+
#include "php_v8_script.h"
21+
#include "php_v8_script_origin.h"
22+
#include "php_v8_unbound_script.h"
23+
#include "php_v8_source.h"
24+
#include "php_v8_function.h"
25+
#include "php_v8_string.h"
26+
#include "php_v8_value.h"
27+
#include "php_v8_isolate.h"
28+
#include "php_v8.h"
29+
30+
zend_class_entry* php_v8_script_compiler_class_entry;
31+
#define this_ce php_v8_script_compiler_class_entry
32+
33+
34+
static v8::ScriptCompiler::Source * php_v8_build_source(zval *source_string_zv, zval *origin_zv, zval *cached_data_zv, v8::Isolate *isolate) {
35+
PHP_V8_VALUE_FETCH_INTO(source_string_zv, php_v8_source_string);
36+
37+
v8::Local<v8::String> local_source_string = php_v8_value_get_string_local(isolate, php_v8_source_string);
38+
39+
v8::ScriptOrigin *origin = NULL;
40+
41+
if (!ZVAL_IS_NULL(origin_zv)) {
42+
origin = php_v8_create_script_origin_from_zval(origin_zv, isolate);
43+
}
44+
45+
v8::ScriptCompiler::CachedData *cached_data = NULL;
46+
47+
if (!ZVAL_IS_NULL(cached_data_zv)) {
48+
PHP_V8_FETCH_CACHED_DATA_INTO(cached_data_zv, php_v8_cached_data);
49+
cached_data = php_v8_cached_data->cached_data;
50+
}
51+
52+
v8::ScriptCompiler::Source *source;
53+
54+
if (origin) {
55+
source = new v8::ScriptCompiler::Source(local_source_string, *origin, cached_data);
56+
} else {
57+
source = new v8::ScriptCompiler::Source(local_source_string, cached_data);
58+
}
59+
60+
return source;
61+
}
62+
63+
static PHP_METHOD(V8ScriptCompiler, CachedDataVersionTag)
64+
{
65+
if (zend_parse_parameters_none() == FAILURE) {
66+
return;
67+
}
68+
69+
RETURN_LONG(static_cast<zend_long>(v8::ScriptCompiler::CachedDataVersionTag()));
70+
}
71+
72+
static PHP_METHOD(V8ScriptCompiler, CompileUnboundScript)
73+
{
74+
zval rv;
75+
76+
zval *php_v8_context_zv;
77+
zval *php_v8_source_zv;
78+
zend_long options = 0;
79+
80+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oo|l", &php_v8_context_zv, &php_v8_source_zv, &options) == FAILURE) {
81+
return;
82+
}
83+
84+
PHP_V8_CHECK_COMPILER_OPTIONS_RANGE(options, "Invalid Script compiler options given. See V8\\ScriptCompiler\\CompileOptions class constants for available options.")
85+
86+
PHP_V8_CONTEXT_FETCH_INTO(php_v8_context_zv, php_v8_context);
87+
88+
zval *source_string_zv = PHP_V8_SOURCE_READ_SOURCE_STRING(php_v8_source_zv);
89+
zval *origin_zv = PHP_V8_SOURCE_READ_ORIGIN(php_v8_source_zv);
90+
zval *cached_data_zv = PHP_V8_SOURCE_READ_CACHED_DATA(php_v8_source_zv);
91+
92+
PHP_V8_VALUE_FETCH_WITH_CHECK(source_string_zv, php_v8_source_string);
93+
PHP_V8_DATA_ISOLATES_CHECK(php_v8_source_string, php_v8_context);
94+
95+
if (!ZVAL_IS_NULL(cached_data_zv)) {
96+
PHP_V8_FETCH_CACHED_DATA_WITH_CHECK(cached_data_zv, php_v8_cached_data);
97+
}
98+
99+
PHP_V8_ENTER_STORED_ISOLATE(php_v8_context);
100+
PHP_V8_ENTER_CONTEXT(php_v8_context);
101+
102+
v8::ScriptCompiler::Source * source = php_v8_build_source(source_string_zv, origin_zv, cached_data_zv, isolate);
103+
104+
if (source->GetResourceOptions().IsModule()) {
105+
PHP_V8_THROW_EXCEPTION("Unable to compile module as unbound script")
106+
return;
107+
}
108+
109+
if (source->GetCachedData() == NULL && (options == v8::ScriptCompiler::CompileOptions::kConsumeParserCache || options == v8::ScriptCompiler::CompileOptions::kConsumeCodeCache)) {
110+
PHP_V8_THROW_EXCEPTION("Unable to consume cache when it's not set");
111+
return;
112+
}
113+
114+
PHP_V8_TRY_CATCH(isolate);
115+
PHP_V8_INIT_ISOLATE_LIMITS_ON_CONTEXT(php_v8_context);
116+
117+
v8::MaybeLocal<v8::UnboundScript> maybe_unbound_script = v8::ScriptCompiler::CompileUnboundScript(isolate, source, static_cast<v8::ScriptCompiler::CompileOptions>(options));
118+
119+
PHP_V8_MAYBE_CATCH(php_v8_context, try_catch);
120+
PHP_V8_THROW_VALUE_EXCEPTION_WHEN_EMPTY(maybe_unbound_script, "Failed to compile unbound script");
121+
122+
v8::Local<v8::UnboundScript> local_unbound_script = maybe_unbound_script.ToLocalChecked();
123+
124+
php_v8_update_source_cached_data(php_v8_source_zv, source);
125+
php_v8_create_unbound_script(return_value, php_v8_context->php_v8_isolate, local_unbound_script);
126+
}
127+
128+
static PHP_METHOD(V8ScriptCompiler, Compile)
129+
{
130+
zval rv;
131+
132+
zval *php_v8_context_zv;
133+
zval *php_v8_source_zv;
134+
zend_long options = 0;
135+
136+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oo|l", &php_v8_context_zv, &php_v8_source_zv, &options) == FAILURE) {
137+
return;
138+
}
139+
140+
PHP_V8_CHECK_COMPILER_OPTIONS_RANGE(options, "Invalid Script compiler options given. See V8\\ScriptCompiler\\CompileOptions class constants for available options.")
141+
142+
PHP_V8_CONTEXT_FETCH_INTO(php_v8_context_zv, php_v8_context);
143+
144+
zval *source_string_zv = PHP_V8_SOURCE_READ_SOURCE_STRING(php_v8_source_zv);
145+
zval *origin_zv = PHP_V8_SOURCE_READ_ORIGIN(php_v8_source_zv);
146+
zval *cached_data_zv = PHP_V8_SOURCE_READ_CACHED_DATA(php_v8_source_zv);
147+
148+
PHP_V8_VALUE_FETCH_WITH_CHECK(source_string_zv, php_v8_source_string);
149+
PHP_V8_DATA_ISOLATES_CHECK(php_v8_source_string, php_v8_context);
150+
151+
if (!ZVAL_IS_NULL(cached_data_zv)) {
152+
PHP_V8_FETCH_CACHED_DATA_WITH_CHECK(cached_data_zv, php_v8_cached_data);
153+
}
154+
155+
PHP_V8_ENTER_STORED_ISOLATE(php_v8_context);
156+
PHP_V8_ENTER_CONTEXT(php_v8_context);
157+
158+
v8::ScriptCompiler::Source * source = php_v8_build_source(source_string_zv, origin_zv, cached_data_zv, isolate);
159+
160+
if (source->GetResourceOptions().IsModule()) {
161+
PHP_V8_THROW_EXCEPTION("Unable to compile module as script")
162+
return;
163+
}
164+
165+
if (source->GetCachedData() == NULL && (options == v8::ScriptCompiler::CompileOptions::kConsumeParserCache || options == v8::ScriptCompiler::CompileOptions::kConsumeCodeCache)) {
166+
PHP_V8_THROW_EXCEPTION("Unable to consume cache when it's not set");
167+
return;
168+
}
169+
170+
PHP_V8_TRY_CATCH(isolate);
171+
PHP_V8_INIT_ISOLATE_LIMITS_ON_CONTEXT(php_v8_context);
172+
173+
v8::MaybeLocal<v8::Script> maybe_script = v8::ScriptCompiler::Compile(context, source, static_cast<v8::ScriptCompiler::CompileOptions>(options));
174+
175+
PHP_V8_MAYBE_CATCH(php_v8_context, try_catch);
176+
PHP_V8_THROW_VALUE_EXCEPTION_WHEN_EMPTY(maybe_script, "Failed to compile script");
177+
178+
v8::Local<v8::Script> local_script = maybe_script.ToLocalChecked();
179+
180+
php_v8_update_source_cached_data(php_v8_source_zv, source);
181+
php_v8_create_script(return_value, local_script, php_v8_context);
182+
}
183+
184+
static PHP_METHOD(V8ScriptCompiler, CompileFunctionInContext)
185+
{
186+
zval rv;
187+
188+
zval *php_v8_context_zv;
189+
zval *php_v8_source_zv;
190+
zval *arguments_zv = NULL;
191+
zval *context_extensions_zv = NULL;
192+
193+
int arguments_count = 0;
194+
v8::Local<v8::String> *arguments = NULL;
195+
int context_extensions_count = 0;
196+
v8::Local<v8::Object> *context_extensions = NULL;
197+
198+
if (zend_parse_parameters(ZEND_NUM_ARGS(), "oo|aa", &php_v8_context_zv, &php_v8_source_zv, &arguments_zv, &context_extensions_zv) == FAILURE) {
199+
return;
200+
}
201+
202+
PHP_V8_CONTEXT_FETCH_INTO(php_v8_context_zv, php_v8_context);
203+
204+
zval *source_string_zv = PHP_V8_SOURCE_READ_SOURCE_STRING(php_v8_source_zv);
205+
zval *origin_zv = PHP_V8_SOURCE_READ_ORIGIN(php_v8_source_zv);
206+
zval *cached_data_zv = PHP_V8_SOURCE_READ_CACHED_DATA(php_v8_source_zv);
207+
208+
PHP_V8_VALUE_FETCH_WITH_CHECK(source_string_zv, php_v8_source_string);
209+
PHP_V8_DATA_ISOLATES_CHECK(php_v8_source_string, php_v8_context);
210+
211+
if (!ZVAL_IS_NULL(cached_data_zv)) {
212+
PHP_V8_FETCH_CACHED_DATA_WITH_CHECK(cached_data_zv, php_v8_cached_data);
213+
}
214+
215+
PHP_V8_ENTER_STORED_ISOLATE(php_v8_context);
216+
PHP_V8_ENTER_CONTEXT(php_v8_context);
217+
218+
if (arguments_zv != NULL && !php_v8_function_unpack_string_args(arguments_zv, 3, isolate, &arguments_count, &arguments)) {
219+
return;
220+
}
221+
222+
if (context_extensions_zv != NULL && !php_v8_function_unpack_object_args(context_extensions_zv, 4, isolate, &context_extensions_count, &context_extensions)) {
223+
return;
224+
}
225+
226+
v8::ScriptCompiler::Source * source = php_v8_build_source(source_string_zv, origin_zv, cached_data_zv, isolate);
227+
228+
PHP_V8_TRY_CATCH(isolate);
229+
PHP_V8_INIT_ISOLATE_LIMITS_ON_CONTEXT(php_v8_context);
230+
231+
v8::MaybeLocal<v8::Function> maybe_function;
232+
maybe_function = v8::ScriptCompiler::CompileFunctionInContext(context,
233+
source,
234+
static_cast<size_t>(arguments_count),
235+
arguments,
236+
static_cast<size_t>(context_extensions_count),
237+
context_extensions);
238+
239+
PHP_V8_MAYBE_CATCH(php_v8_context, try_catch);
240+
PHP_V8_THROW_VALUE_EXCEPTION_WHEN_EMPTY(maybe_function, "Failed to compile function in context");
241+
242+
v8::Local<v8::Function> local_function = maybe_function.ToLocalChecked();
243+
244+
php_v8_get_or_create_value(return_value, local_function, isolate);
245+
}
246+
247+
248+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_v8_script_compiler_CachedDataVersionTag, ZEND_RETURN_VALUE, 0, IS_LONG, 0)
249+
ZEND_END_ARG_INFO()
250+
251+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_script_compiler_CompileUnboundScript, ZEND_RETURN_VALUE, 2, V8\\UnboundScript, 0)
252+
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
253+
ZEND_ARG_OBJ_INFO(0, source, V8\\ScriptCompiler\\Source, 0)
254+
ZEND_ARG_TYPE_INFO(0, options, IS_LONG, 0)
255+
ZEND_END_ARG_INFO()
256+
257+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_script_compiler_Compile, ZEND_RETURN_VALUE, 2, V8\\Script, 0)
258+
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
259+
ZEND_ARG_OBJ_INFO(0, source, V8\\ScriptCompiler\\Source, 0)
260+
ZEND_ARG_TYPE_INFO(0, options, IS_LONG, 0)
261+
ZEND_END_ARG_INFO()
262+
263+
PHP_V8_ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_v8_script_compiler_CompileFunctionInContext, ZEND_RETURN_VALUE, 2, V8\\FunctionObject, 0)
264+
ZEND_ARG_OBJ_INFO(0, context, V8\\Context, 0)
265+
ZEND_ARG_OBJ_INFO(0, source, V8\\ScriptCompiler\\Source, 0)
266+
ZEND_ARG_TYPE_INFO(0, arguments, IS_ARRAY, 0)
267+
ZEND_ARG_TYPE_INFO(0, context_extensions, IS_ARRAY, 0)
268+
ZEND_END_ARG_INFO()
269+
270+
271+
static const zend_function_entry php_v8_script_compiler_methods[] = {
272+
PHP_ME(V8ScriptCompiler, CachedDataVersionTag, arginfo_v8_script_compiler_CachedDataVersionTag, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
273+
PHP_ME(V8ScriptCompiler, CompileUnboundScript, arginfo_v8_script_compiler_CompileUnboundScript, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
274+
PHP_ME(V8ScriptCompiler, Compile, arginfo_v8_script_compiler_Compile, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
275+
PHP_ME(V8ScriptCompiler, CompileFunctionInContext, arginfo_v8_script_compiler_CompileFunctionInContext, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
276+
277+
PHP_FE_END
278+
};
279+
280+
281+
PHP_MINIT_FUNCTION(php_v8_script_compiler)
282+
{
283+
zend_class_entry ce;
284+
285+
INIT_NS_CLASS_ENTRY(ce, PHP_V8_NS, "ScriptCompiler", php_v8_script_compiler_methods);
286+
this_ce = zend_register_internal_class(&ce);
287+
288+
return SUCCESS;
289+
}

src/php_v8_script_compiler.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* This file is part of the pinepain/php-v8 PHP extension.
3+
*
4+
* Copyright (c) 2015-2017 Bogdan Padalko <[email protected]>
5+
*
6+
* Licensed under the MIT license: http://opensource.org/licenses/MIT
7+
*
8+
* For the full copyright and license information, please view the
9+
* LICENSE file that was distributed with this source or visit
10+
* http://opensource.org/licenses/MIT
11+
*/
12+
13+
#ifndef PHP_V8_SCRIPT_COMPILER_H
14+
#define PHP_V8_SCRIPT_COMPILER_H
15+
16+
extern "C" {
17+
#include "php.h"
18+
19+
#ifdef ZTS
20+
#include "TSRM.h"
21+
#endif
22+
}
23+
24+
extern zend_class_entry *php_v8_script_compiler_class_entry;
25+
26+
PHP_MINIT_FUNCTION(php_v8_script_compiler);
27+
28+
#endif //PHP_V8_SCRIPT_COMPILER_H

0 commit comments

Comments
 (0)