14 'phpCallsRequireSerialization' =>
false,
31 $versions = LuaSandbox::getVersionInfo();
32 $software[
'[https://www.mediawiki.org/wiki/LuaSandbox LuaSandbox]'] =
33 $versions[
'LuaSandbox'];
34 $software[
'[http://www.lua.org/ Lua]'] = str_replace(
'Lua ',
'', $versions[
'Lua'] );
35 if ( isset( $versions[
'LuaJIT'] ) ) {
36 $software[
'[http://luajit.org/ LuaJIT]'] = str_replace(
'LuaJIT ',
'', $versions[
'LuaJIT'] );
42 switch ( $resource ) {
44 return $this->interpreter->getPeakMemoryUsage();
46 return $this->interpreter->getCPUUsage();
56 $t = $this->interpreter->getCPUUsage();
57 $ret[
'scribunto-limitreport-timeusage'] = [
58 sprintf(
"%.3f",
$t ),
59 sprintf(
"%.3f", $this->options[
'cpuLimit'] )
61 $ret[
'scribunto-limitreport-memusage'] = [
62 $this->interpreter->getPeakMemoryUsage(),
63 $this->options[
'memoryLimit'],
68 $ret[
'scribunto-limitreport-logs'] = $logs;
75 $percentProfile = $this->interpreter->getProfilerFunctionReport(
78 if ( !count( $percentProfile ) ) {
81 $timeProfile = $this->interpreter->getProfilerFunctionReport(
86 $cumulativePercent = 0;
87 $num = $otherTime = $otherPercent = 0;
88 foreach ( $percentProfile as $name => $percent ) {
89 $time = $timeProfile[$name] * 1000;
91 if ( $cumulativePercent <= 99 && $num <= 10 ) {
93 if ( preg_match(
'/^<mw.lua:(\d+)>$/', $name, $m ) ) {
95 if ( preg_match(
'/^\s*(local\s+)?function ([a-zA-Z0-9_.]*)/',
$line, $m ) ) {
96 $name = $m[2] .
' ' . $name;
99 $lines[] = [ $name, sprintf(
'%.0f', $time ), sprintf(
'%.1f', $percent ) ];
102 $otherPercent += $percent;
104 $cumulativePercent += $percent;
107 $lines[] = [
'[others]', sprintf(
'%.0f', $otherTime ), sprintf(
'%.1f', $otherPercent ) ];
109 $ret[
'scribunto-limitreport-profile'] =
$lines;
115 foreach ( $data as $k => $v ) {
116 $output->setLimitReportData( $k, $v );
118 if ( isset( $data[
'scribunto-limitreport-logs'] ) ) {
119 $output->addModules(
'ext.scribunto.logs' );
127 case 'scribunto-limitreport-logs':
133 case 'scribunto-limitreport-memusage':
134 $value = array_map( [
$lang,
'formatSize' ], $value );
138 if ( $key !==
'scribunto-limitreport-profile' ) {
142 $keyMsg =
wfMessage(
'scribunto-limitreport-profile' );
143 $msMsg =
wfMessage(
'scribunto-limitreport-profile-ms' );
144 $percentMsg =
wfMessage(
'scribunto-limitreport-profile-percent' );
146 $keyMsg->inLanguage(
'en' )->useDatabase(
false );
147 $msMsg->inLanguage(
'en' )->useDatabase(
false );
148 $percentMsg->inLanguage(
'en' )->useDatabase(
false );
154 $percentMsg->exists();
157 $report .= Html::openElement(
'tr' ) .
158 Html::rawElement(
'th', [
'colspan' => 2 ], $keyMsg->parse() ) .
159 Html::closeElement(
'tr' ) .
160 Html::openElement(
'tr' ) .
161 Html::openElement(
'td', [
'colspan' => 2 ] ) .
162 Html::openElement(
'table' );
163 foreach ( $value as
$line ) {
166 if ( preg_match(
'/^(.*?) *<([^<>]+):(\d+)>$/', $name, $m ) ) {
172 $location = htmlspecialchars(
"<{$m[2]}:{$m[3]}>" );
176 $ms->params(
$line[1] );
177 $pct = clone $percentMsg;
178 $pct->params(
$line[2] );
179 $report .= Html::openElement(
'tr' ) .
180 Html::element(
'td',
null, $name ) .
181 Html::rawElement(
'td',
null, $location ) .
182 Html::rawElement(
'td', [
'align' =>
'right' ], $ms->parse() ) .
183 Html::rawElement(
'td', [
'align' =>
'right' ], $pct->parse() ) .
184 Html::closeElement(
'tr' );
186 $report .= Html::closeElement(
'table' ) .
187 Html::closeElement(
'td' ) .
188 Html::closeElement(
'tr' );
190 $report .= $keyMsg->text() .
":\n";
191 foreach ( $value as
$line ) {
193 $ms->params(
$line[1] );
194 $pct = clone $percentMsg;
195 $pct->params(
$line[2] );
196 $report .= sprintf(
" %-59s %11s %11s\n",
$line[0], $ms->text(), $pct->text() );
204 if ( !isset( $this->lineCache[
'mw.lua'] ) ) {
205 $this->lineCache[
'mw.lua'] = file( $this->
getLuaLibDir() .
'/mw.lua' );
207 return $this->lineCache[
'mw.lua'][$lineNum - 1];
241 if ( !extension_loaded(
'luasandbox' ) ) {
243 'The luasandbox extension is not present, this engine cannot be used.' );
246 if ( !is_callable(
'LuaSandbox::getVersionInfo' ) ) {
248 'The luasandbox extension is too old (version 1.6+ is required), ' .
249 'this engine cannot be used.'
258 $this->sandbox =
new LuaSandbox;
259 $this->sandbox->setMemoryLimit( $options[
'memoryLimit'] );
260 $this->sandbox->setCPULimit( $options[
'cpuLimit'] );
261 if ( !isset( $options[
'profilerPeriod'] ) ) {
262 $options[
'profilerPeriod'] = 0.02;
264 if ( $options[
'profilerPeriod'] ) {
265 $this->profilerEnabled =
true;
266 $this->sandbox->enableProfiler( $options[
'profilerPeriod'] );
272 if ( isset( $e->luaTrace ) ) {
273 $opts[
'trace'] = $e->luaTrace;
275 $message = $e->getMessage();
276 if ( preg_match(
'/^(.*?):(\d+): (.*)$/', $message, $m ) ) {
277 $opts[
'module'] = $m[1];
278 $opts[
'line'] = $m[2];
281 return $this->engine->newLuaError( $message, $opts );
292 return $this->sandbox->loadString( $text, $chunkName );
293 }
catch ( LuaSandboxError $e ) {
300 foreach ( $functions as $funcName => $callback ) {
301 $realLibrary[$funcName] = [
305 $this->sandbox->registerLibrary( $name, $realLibrary );
307 # TODO: replace this with
308 # $this->sandbox->registerVirtualLibrary(
309 # $name, [ $this, 'callback' ], $functions );
314 $ret = $func->call( ...
$args );
315 if ( $ret ===
false ) {
320 __METHOD__ .
': LuaSandboxFunction::call returned false' );
323 }
catch ( LuaSandboxTimeoutError $e ) {
324 throw $this->engine->newException(
'scribunto-common-timeout' );
325 }
catch ( LuaSandboxError $e ) {
331 return $this->sandbox->wrapPhpFunction( $callable );
335 return $object instanceof LuaSandboxFunction;
339 return $this->sandbox->getPeakMemoryUsage();
343 return $this->sandbox->getCPUUsage();
347 if ( $this->profilerEnabled ) {
351 self::SAMPLES => LuaSandbox::SAMPLES,
352 self::SECONDS => LuaSandbox::SECONDS,
353 self::PERCENT => LuaSandbox::PERCENT,
356 return $this->sandbox->getProfilerFunctionReport( $unitsMap[$units] );
363 $this->sandbox->pauseUsageTimer();
367 $this->sandbox->unpauseUsageTimer();
391 return ( $this->callback )( ...$args );