Pol  Revision:cb584c9
executor.cpp
Go to the documentation of this file.
1 
16 #include "executor.h"
17 
18 #include "../clib/clib.h"
19 #include "../clib/compilerspecifics.h"
20 #include "../clib/logfacility.h"
21 #include "../clib/passert.h"
22 #include "../clib/strutil.h"
23 #include "berror.h"
24 #include "config.h"
25 #include "contiter.h"
26 #include "dict.h"
27 #include "eprog.h"
28 #include "escriptv.h"
29 #include "execmodl.h"
30 #include "fmodule.h"
31 #include "impstr.h"
32 #include "token.h"
33 #include "tokens.h"
34 #ifdef MEMORYLEAK
35 #include "../clib/mlog.h"
36 #endif
37 
38 #include <cstdlib>
39 #include <cstring>
40 #include <exception>
41 
42 #ifdef ESCRIPT_PROFILE
43 #ifdef _WIN32
44 #define WIN32_LEAN_AND_MEAN
45 #include <windows.h>
46 #else
47 #include <sys/time.h>
48 #endif
49 #endif
50 
51 namespace Pol
52 {
53 namespace Bscript
54 {
55 std::set<Executor*> executor_instances;
56 
57 #ifdef ESCRIPT_PROFILE
58 escript_profile_map EscriptProfileMap;
59 #endif
60 
62 {
63  for ( const auto& ex : executor_instances )
64  {
65  // Fix for crashes due to orphaned script instances.
66  if ( !ex->empty_scriptname() )
67  INFO_PRINT << ex->scriptname() << "\n";
68  }
69 }
70 
71 extern int executor_count;
74  : done( 0 ),
75  error_( false ),
76  halt_( false ),
77  run_ok_( false ),
78  debug_level( NONE ),
79  PC( 0 ),
80  Locals2( new BObjectRefVec ),
81  nLines( 0 ),
82  current_module_function( NULL ),
83  prog_ok_( false ),
84  viewmode_( false ),
85  runs_to_completion_( false ),
86  debugging_( false ),
87  debug_state_( DEBUG_STATE_NONE ),
88  breakpoints_(),
89  bp_skip_( ~0u ),
90  func_result_( NULL )
91 {
94  executor_instances.insert( this );
95 
97  {
100  }
101 }
102 
104 {
105  {
107  --executor_count;
108  executor_instances.erase( this );
109  }
110  delete Locals2;
111  Locals2 = NULL;
112 
113  while ( !upperLocals2.empty() )
114  {
115  delete upperLocals2.back();
116  upperLocals2.pop_back();
117  }
118 
119  execmodules.clear();
121 }
122 
124 {
125  for ( auto& fm : prog_->modules )
126  {
127  // if no function in the module is actually called, don't go searching for it.
128  if ( fm->functions.empty() )
129  {
130  execmodules.push_back( NULL );
131  continue;
132  }
133 
134  ExecutorModule* em = findModule( fm->modulename );
135  execmodules.push_back( em );
136  if ( em == NULL )
137  {
138  ERROR_PRINT << "WARNING: " << scriptname() << ": Unable to find module "
139  << fm->modulename.get() << "\n";
140  return false;
141  }
142 
143  if ( !fm->have_indexes )
144  {
145  /*
146  FIXE: Possible optimization: store these function indexes in the
147  EScriptProgram object, since those are cached. Then, we only
148  have to find the module index.
149  */
150  for ( unsigned fidx = 0; fidx < fm->functions.size(); fidx++ )
151  {
152  ModuleFunction* func = fm->functions[fidx];
153  // FIXME: should check number of params, blah.
154  if ( !func->name.get().empty() )
155  {
156  func->funcidx = em->functionIndex( func->name.get() );
157  if ( func->funcidx == -1 )
158  {
159  ERROR_PRINT << "Unable to find " << fm->modulename.get() << "::" << func->name.get()
160  << "\n";
161  return false;
162  }
163  }
164  }
165  fm->have_indexes = true;
166  }
167  }
168  return true;
169 }
170 
171 int Executor::getParams( unsigned howMany )
172 {
173  if ( howMany )
174  {
175  fparams.resize( howMany );
176  for ( int i = howMany - 1; i >= 0; --i )
177  {
178  if ( ValueStack.empty() )
179  {
180  POLLOG_ERROR.Format( "Fatal error: Value Stack Empty! ({},PC={})\n" ) << prog_->name << PC;
181  seterror( true );
182  return -1;
183  }
184  fparams[i] = ValueStack.back();
185  ValueStack.pop_back();
186  }
187  }
188  return 0;
189 }
190 
192 {
193  fparams.clear();
194 }
195 
196 int Executor::makeString( unsigned param )
197 {
198  BObject* obj = getParam( param );
199  if ( !obj )
200  return -1;
201  if ( obj->isa( BObjectImp::OTString ) )
202  return 0;
203 
204  fparams[param].set( new BObject( new String( obj->impref() ) ) );
205 
206  return 0;
207 }
208 
209 const char* Executor::paramAsString( unsigned param )
210 {
211  makeString( param );
212  BObjectImp* objimp = fparams[param]->impptr();
213 
214  String* str = (String*)objimp;
215  return str ? str->data() : "";
216 }
217 
218 int Executor::makeDouble( unsigned param )
219 {
220  BObject* obj = getParam( param );
221  if ( !obj )
222  return -1;
223  if ( obj->isa( BObjectImp::OTDouble ) )
224  return 0;
225 
226  fparams[param].set( new BObject( new Double( static_cast<Double&>( obj->impref() ) ) ) );
227 
228  return 0;
229 }
230 
231 double Executor::paramAsDouble( unsigned param )
232 {
233  makeDouble( param );
234  BObjectImp* objimp = getParam( param )->impptr();
235 
236  Double* dbl = (Double*)objimp;
237  return dbl ? dbl->value() : 0.0;
238 }
239 
240 int Executor::paramAsLong( unsigned param )
241 {
242  BObjectImp* objimp = getParam( param )->impptr();
243  if ( objimp->isa( BObjectImp::OTLong ) )
244  {
245  return ( (BLong*)objimp )->value();
246  }
247  else if ( objimp->isa( BObjectImp::OTDouble ) )
248  {
249  return static_cast<int>( ( (Double*)objimp )->value() );
250  }
251  else
252  {
253  return 0;
254  }
255 }
256 BObject* Executor::getParam( unsigned param )
257 {
258  passert_r( param < fparams.size(), "Script Error in '" + scriptname() +
259  ": Less Parameter than expected. " +
260  "You should use *.em-files shipped with this Core and "
261  "recompile ALL of your Scripts _now_! RTFM" );
262 
263  return fparams[param].get();
264 }
265 
267 {
268  passert_r( param < fparams.size(), "Script Error in '" + scriptname() +
269  ": Less Parameter than expected. " +
270  "You should use *.em-files shipped with this Core and "
271  "recompile ALL of your Scripts _now_! RTFM" );
272 
273  return fparams[param].get()->impptr();
274 }
275 
276 BObject* Executor::getParamObj( unsigned param )
277 {
278  if ( fparams.size() > param )
279  {
280  return fparams[param].get();
281  }
282  else
283  {
284  return NULL;
285  }
286 }
287 
289 {
290  passert_r( param < fparams.size(), "Script Error in '" + scriptname() +
291  ": Less Parameter than expected. " +
292  "You should use *.em-files shipped with this Core and "
293  "recompile ALL of your Scripts _now_! RTFM" );
294 
295  BObjectImp* imp = fparams[param].get()->impptr();
296 
297  passert( imp != NULL );
298 
299  if ( imp->isa( type ) )
300  {
301  return imp;
302  }
303  else
304  {
305  if ( !IS_DEBUGLOG_DISABLED )
306  {
307  fmt::Writer tmp;
308  tmp << "Script Error in '" << scriptname() << "' PC=" << PC << ": \n";
310  tmp << "\tCall to function " << current_module_function->name.get() << ":\n";
311  else
312  tmp << "\tCall to an object method.\n";
313  tmp << "\tParameter " << param << ": Expected datatype " << BObjectImp::typestr( type )
314  << ", got datatype " << BObjectImp::typestr( imp->type() ) << "\n";
315  DEBUGLOG << tmp.str();
316  }
317  return NULL;
318  }
319 }
320 
322 {
323  passert_r( param < fparams.size(), "Script Error in '" + scriptname() +
324  ": Less Parameter than expected. " +
325  "You should use *.em-files shipped with this Core and "
326  "recompile ALL of your Scripts _now_! RTFM" );
327 
328  BObjectImp* imp = fparams[param].get()->impptr();
329 
330  passert( imp != NULL );
331 
332  if ( imp->isa( type ) )
333  {
334  return imp;
335  }
336  else
337  {
338  std::string report = "Invalid parameter type. Expected param " + Clib::decint( param ) +
339  " as " + BObjectImp::typestr( type ) + ", got " +
340  BObjectImp::typestr( imp->type() );
341  func_result_ = new BError( report );
342  return NULL;
343  }
344 }
345 
346 
347 const String* Executor::getStringParam( unsigned param )
348 {
350 }
351 
352 const BLong* Executor::getLongParam( unsigned param )
353 {
355 }
356 
357 bool Executor::getStringParam( unsigned param, const String*& pstr )
358 {
359  pstr = getStringParam( param );
360  return ( pstr != NULL );
361 }
362 
363 bool Executor::getParam( unsigned param, int& value )
364 {
365  BLong* plong =
367  if ( plong == NULL )
368  return false;
369 
370  value = plong->value();
371  return true;
372 }
373 
375 {
376  func_result_ = imp;
377 }
378 
379 bool Executor::getParam( unsigned param, int& value, int maxval )
380 {
381  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
382  if ( imp )
383  {
384  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
385 
386  value = plong->value();
387  if ( value >= 0 && value <= maxval )
388  {
389  return true;
390  }
391  else
392  {
393  std::string report = "Parameter " + Clib::decint( param ) + " value " +
394  Clib::decint( value ) + " out of expected range of [0.." +
395  Clib::decint( maxval ) + "]";
396  func_result_ = new BError( report );
397  return false;
398  }
399  }
400  else
401  {
402  return false;
403  }
404 }
405 
406 bool Executor::getParam( unsigned param, int& value, int minval, int maxval )
407 {
408  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
409  if ( imp )
410  {
411  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
412 
413  value = plong->value();
414  if ( value >= minval && value <= maxval )
415  {
416  return true;
417  }
418  else
419  {
420  std::string report = "Parameter " + Clib::decint( param ) + " value " +
421  Clib::decint( value ) + " out of expected range of [" +
422  Clib::decint( minval ) + ".." + Clib::decint( maxval ) + "]";
423  func_result_ = new BError( report );
424  return false;
425  }
426  }
427  else
428  {
429  return false;
430  }
431 }
432 
433 bool Executor::getRealParam( unsigned param, double& value )
434 {
435  BObjectImp* imp = getParamImp( param );
436  if ( imp->isa( BObjectImp::OTDouble ) )
437  {
438  value = static_cast<Double*>( imp )->value();
439  return true;
440  }
441  else if ( imp->isa( BObjectImp::OTLong ) )
442  {
443  value = static_cast<BLong*>( imp )->value();
444  return true;
445  }
446  else
447  {
448  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << PC << ": \n"
449  << "\tCall to function " << current_module_function->name.get() << ":\n"
450  << "\tParameter " << param << ": Expected Integer or Real"
451  << ", got datatype " << BObjectImp::typestr( imp->type() ) << "\n";
452 
453  return false;
454  }
455 }
456 
457 bool Executor::getObjArrayParam( unsigned param, ObjArray*& pobjarr )
458 {
459  pobjarr =
461  return ( pobjarr != NULL );
462 }
463 
464 void* Executor::getApplicPtrParam( unsigned param, const BApplicObjType* pointer_type )
465 {
466  BApplicPtr* ap =
468  if ( ap == NULL )
469  return NULL;
470 
471  if ( ap->pointer_type() == pointer_type )
472  {
473  return ap->ptr();
474  }
475  else
476  {
477  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << PC << ": \n"
478  << "\tCall to function " << current_module_function->name.get() << ":\n"
479  << "\tParameter " << param
480  << ": Expected datatype " /*<< pointer_type TODO this is totally useless since its a
481  pointer address*/
482  << ", got datatype " << BObjectImp::typestr( ap->type() ) << "\n";
483 
484  return NULL;
485  }
486 }
487 
488 BApplicObjBase* Executor::getApplicObjParam( unsigned param, const BApplicObjType* object_type )
489 {
492  if ( aob == NULL )
493  return NULL;
494 
495  if ( aob->object_type() == object_type )
496  {
497  return aob;
498  }
499  else
500  {
501  DEBUGLOG << "Script Error in '" << scriptname() << "' PC=" << PC << ": \n"
502  << "\tCall to function " << current_module_function->name.get() << ":\n"
503  << "\tParameter " << param
504  << ": Expected datatype " /*<< object_type TODO this is totally useless since its a
505  pointer address*/
506  << ", got datatype " << aob->getStringRep() << "\n";
507 
508  return NULL;
509  }
510 }
511 
512 bool Executor::getParam( unsigned param, unsigned short& value, unsigned short maxval )
513 {
514  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
515  if ( imp )
516  {
517  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
518 
519  int longvalue = plong->value();
520  if ( longvalue >= 0 && longvalue <= maxval )
521  {
522  value = static_cast<unsigned short>( longvalue );
523  return true;
524  }
525  else
526  {
527  std::string report = "Parameter " + Clib::decint( param ) + " value " +
528  Clib::decint( longvalue ) + " out of expected range of [0.." +
529  Clib::decint( maxval ) + "]";
530  func_result_ = new BError( report );
531  return false;
532  }
533  }
534  else
535  {
536  return false;
537  }
538 }
539 
540 bool Executor::getParam( unsigned param, unsigned short& value, unsigned short minval,
541  unsigned short maxval )
542 {
543  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
544  if ( imp )
545  {
546  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
547 
548  int longvalue = plong->value();
549  if ( longvalue >= minval && longvalue <= maxval )
550  {
551  value = static_cast<unsigned short>( longvalue );
552  return true;
553  }
554  else
555  {
556  std::string report = "Parameter " + Clib::decint( param ) + " value " +
557  Clib::decint( longvalue ) + " out of expected range of [" +
558  Clib::decint( minval ) + ".." + Clib::decint( maxval ) + "]";
559  func_result_ = new BError( report );
560  return false;
561  }
562  }
563  else
564  {
565  return false;
566  }
567 }
568 bool Executor::getParam( unsigned param, unsigned short& value )
569 {
570  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
571  if ( imp )
572  {
573  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
574 
575  int longvalue = plong->value();
576  if ( longvalue >= 0 && longvalue <= USHRT_MAX )
577  {
578  value = static_cast<unsigned short>( longvalue );
579  return true;
580  }
581  else
582  {
583  std::string report = "Parameter " + Clib::decint( param ) + " value " +
584  Clib::decint( longvalue ) + " out of expected range of [0.." +
585  Clib::decint( USHRT_MAX ) + "]";
586  func_result_ = new BError( report );
587  return false;
588  }
589  }
590  else
591  {
592  return false;
593  }
594 }
595 bool Executor::getParam( unsigned param, unsigned& value )
596 {
597  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
598  if ( imp )
599  {
600  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
601 
602  int longvalue = plong->value();
603  if ( longvalue >= 0 ) // && longvalue <= (int)INT_MAX )
604  {
605  value = static_cast<unsigned>( longvalue );
606  return true;
607  }
608  else
609  {
610  std::string report = "Parameter " + Clib::decint( param ) + " value " +
611  Clib::decint( longvalue ) + " out of expected range of [0.." +
612  Clib::decint( INT_MAX ) + "]";
613  func_result_ = new BError( report );
614  return false;
615  }
616  }
617  else
618  {
619  return false;
620  }
621 }
622 
623 bool Executor::getParam( unsigned param, short& value )
624 {
625  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
626  if ( imp )
627  {
628  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
629 
630  int longvalue = plong->value();
631  if ( longvalue >= (int)SHRT_MIN && longvalue <= (int)SHRT_MAX )
632  {
633  value = static_cast<short>( longvalue );
634  return true;
635  }
636  else
637  {
638  std::string report = "Parameter " + Clib::decint( param ) + " value " +
639  Clib::decint( longvalue ) + " out of expected range of [" +
640  Clib::decint( SHRT_MIN ) + ".." + Clib::decint( SHRT_MAX ) + "]";
641  func_result_ = new BError( report );
642  return false;
643  }
644  }
645  else
646  {
647  return false;
648  }
649 }
650 
651 bool Executor::getParam( unsigned param, short& value, short maxval )
652 {
653  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
654  if ( imp )
655  {
656  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
657 
658  int longvalue = plong->value();
659  if ( longvalue >= (int)SHRT_MIN && longvalue <= maxval )
660  {
661  value = static_cast<short>( longvalue );
662  return true;
663  }
664  else
665  {
666  std::string report = "Parameter " + Clib::decint( param ) + " value " +
667  Clib::decint( longvalue ) + " out of expected range of [" +
668  Clib::decint( SHRT_MIN ) + ".." + Clib::decint( maxval ) + "]";
669  func_result_ = new BError( report );
670  return false;
671  }
672  }
673  else
674  {
675  return false;
676  }
677 }
678 
679 bool Executor::getParam( unsigned param, short& value, short minval, short maxval )
680 {
681  BObjectImp* imp = getParamImp2( param, BObjectImp::OTLong );
682  if ( imp )
683  {
684  BLong* plong = Clib::explicit_cast<BLong*, BObjectImp*>( imp );
685 
686  int longvalue = plong->value();
687  if ( longvalue >= minval && longvalue <= maxval )
688  {
689  value = static_cast<short>( longvalue );
690  return true;
691  }
692  else
693  {
694  std::string report = "Parameter " + Clib::decint( param ) + " value " +
695  Clib::decint( longvalue ) + " out of expected range of [" +
696  Clib::decint( minval ) + ".." + Clib::decint( maxval ) + "]";
697  func_result_ = new BError( report );
698  return false;
699  }
700  }
701  else
702  {
703  return false;
704  }
705 }
706 
707 
708 BObjectRef& Executor::LocalVar( unsigned int varnum )
709 {
710  passert( Locals2 );
711  passert( varnum < Locals2->size() );
712 
713  return ( *Locals2 )[varnum];
714 }
715 
716 BObjectRef& Executor::GlobalVar( unsigned int varnum )
717 {
718  passert( varnum < Globals2.size() );
719  return Globals2[varnum];
720 }
721 
722 int Executor::getToken( Token& token, unsigned position )
723 {
724  if ( position >= nLines )
725  return -1;
726  token = prog_->instr[position].token;
727  return 0;
728 }
729 
730 
732 {
733  prog_.set( i_prog );
734  prog_ok_ = false;
735  seterror( true );
736  if ( !viewmode_ )
737  {
739  return false;
740  }
741 
742  nLines = static_cast<unsigned int>( prog_->instr.size() );
743 
744  Globals2.clear();
745  for ( unsigned i = 0; i < prog_->nglobals; ++i )
746  {
747  Globals2.push_back( BObjectRef() );
748  Globals2.back().set( new BObject( UninitObject::create() ) );
749  }
750 
751  prog_ok_ = true;
752  seterror( false );
753  ++prog_->invocations;
754  return true;
755 }
756 
758 {
759  switch ( token.id )
760  {
761  case TOK_IDENT:
762  return new BObject( new BError( "Please recompile this script!" ) );
763  case TOK_LOCALVAR:
764  return LocalVar( token.lval ).get();
765  case TOK_GLOBALVAR:
766  return GlobalVar( token.lval ).get();
767  case TOK_STRING:
768  return new BObject( new String( token.tokval() ) );
769  case TOK_LONG:
770  return new BObject( new BLong( token.lval ) );
771  case TOK_DOUBLE:
772  return new BObject( new Double( token.dval ) );
773  case TOK_ERROR:
774  return new BObject( new BError( "unknown" ) );
775  default:
776  passert( 0 );
777  break;
778  }
779  return NULL;
780 }
781 
783 {
784  if ( ValueStack.empty() )
785  {
786  POLLOG_ERROR.Format( "Fatal error: Value Stack Empty! ({},PC={})\n" ) << prog_->name << PC;
787  seterror( true );
788  return BObjectRef( UninitObject::create() );
789  }
790 
791  BObjectRef ref = ValueStack.back();
792  ValueStack.pop_back();
793  return ref;
794 }
795 
796 
797 void Executor::execFunc( const Token& token )
798 {
799  FunctionalityModule* fm = prog_->modules[token.module];
800  ModuleFunction* modfunc = fm->functions[token.lval];
801  current_module_function = modfunc;
802  if ( modfunc->funcidx == -1 )
803  {
804  DEBUGLOG << "Error in script '" << prog_->name.get() << "':\n"
805  << "\tModule Function " << modfunc->name.get() << " was not found.\n";
806 
807  throw std::runtime_error( "No implementation for function found." );
808  }
809 
810  ExecutorModule* em = execmodules[token.module];
811 
812  func_result_ = NULL;
813 #ifdef ESCRIPT_PROFILE
814  std::stringstream strm;
815  strm << em->functionName( modfunc->funcidx );
816  if ( !fparams.empty() )
817  strm << " [" << fparams[0].get()->impptr()->typeOf() << "]";
818  std::string name( strm.str() );
819  unsigned long profile_start = GetTimeUs();
820 #endif
821  BObjectImp* resimp = em->execFunc( modfunc->funcidx );
822 #ifdef ESCRIPT_PROFILE
823  profile_escript( name, profile_start );
824 #endif
825 
826  if ( func_result_ )
827  {
828  if ( resimp )
829  {
830  BObject obj( resimp );
831  }
832  ValueStack.push_back( BObjectRef( new BObject( func_result_ ) ) );
833  func_result_ = NULL;
834  }
835  else if ( resimp )
836  {
837  ValueStack.push_back( BObjectRef( new BObject( resimp ) ) );
838  }
839  else
840  {
841  ValueStack.push_back( BObjectRef( new BObject( UninitObject::create() ) ) );
842  }
843 
845  return;
846 }
847 
848 // RSV_LOCAL
849 void Executor::ins_makeLocal( const Instruction& /*ins*/ )
850 {
851  passert( Locals2 != NULL );
852 
853  Locals2->push_back( BObjectRef() );
854  Locals2->back().set( new BObject( UninitObject::create() ) );
855 
856  ValueStack.push_back( BObjectRef( Locals2->back().get() ) );
857 }
858 
859 // RSV_DECLARE_ARRAY
861 {
862  BObjectRef objref = getObjRef();
863 
864  if ( !objref->isa( BObjectImp::OTUninit ) )
865  {
866  // FIXME: weak error message
867  ERROR_PRINT << "variable is already initialized..\n";
868  seterror( true );
869  return;
870  }
871  auto arr = new ObjArray;
872 
873  objref->setimp( arr );
874 
875  ValueStack.push_back( BObjectRef( objref ) );
876 }
877 
878 void Executor::popParam( const Token& /*token*/ )
879 {
880  BObjectRef objref = getObjRef();
881 
882  Locals2->push_back( BObjectRef() );
883  Locals2->back().set( new BObject( objref->impptr()->copy() ) );
884 }
885 
886 void Executor::popParamByRef( const Token& /*token*/ )
887 {
888  BObjectRef objref = getObjRef();
889 
890  Locals2->push_back( BObjectRef( objref ) );
891 }
892 
893 void Executor::getArg( const Token& /*token*/ )
894 {
895  if ( ValueStack.empty() )
896  {
897  Locals2->push_back( BObjectRef() );
898  Locals2->back().set( new BObject( UninitObject::create() ) );
899  }
900  else
901  {
902  BObjectRef objref = getObjRef();
903  Locals2->push_back( BObjectRef() );
904  Locals2->back().set( new BObject( objref->impptr()->copy() ) );
905  }
906 }
907 
908 
910 {
911  if ( !right.isa( BObjectImp::OTString ) )
912  {
913  return BObjectRef( left.clone() );
914  }
915 
916  const String& varname = static_cast<const String&>( right.impref() );
917 
918  return left.impref().operDotPlus( varname.data() );
919 }
920 
922 {
923  if ( !right.isa( BObjectImp::OTString ) )
924  {
925  return BObjectRef( left.clone() );
926  }
927 
928  const String& varname = static_cast<const String&>( right.impref() );
929 
930  return left.impref().operDotMinus( varname.data() );
931 }
932 
934 {
935  if ( !right.isa( BObjectImp::OTString ) )
936  {
937  return BObjectRef( left.clone() );
938  }
939 
940  const String& varname = static_cast<const String&>( right.impref() );
941 
942  return left.impref().operDotQMark( varname.data() );
943 }
944 
945 
948 {
949  return NULL;
950 }
952 {
953  return NULL;
954 }
956 {
957  return sizeof( ContIterator );
958 }
959 std::string ContIterator::getStringRep() const
960 {
961  return "<iterator>";
962 }
963 
965 {
966 public:
967  ArrayIterator( ObjArray* pArr, BObject* pIterVal );
968  virtual BObject* step() POL_OVERRIDE;
969 
970 private:
971  size_t m_Index;
976 };
978  : ContIterator(),
979  m_Index( 0 ),
980  m_Array( pArr ),
981  m_pArray( pArr ),
982  m_IterVal( pIterVal ),
983  m_pIterVal( new BLong( 0 ) )
984 {
985  m_IterVal.get()->setimp( m_pIterVal );
986 }
988 {
990  if ( ++m_Index > m_pArray->ref_arr.size() )
991  return NULL;
992 
993  BObjectRef& objref = m_pArray->ref_arr[m_Index - 1];
994  BObject* elem = objref.get();
995  if ( elem == NULL )
996  {
997  elem = new BObject( UninitObject::create() );
998  objref.set( elem );
999  }
1000  return elem;
1001 }
1002 
1004 {
1005  return new ContIterator();
1006 }
1008 {
1009  auto pItr = new ArrayIterator( this, pIterVal );
1010  return pItr;
1011 }
1012 
1013 /* Coming into initforeach, the expr to be iterated through is on the value stack.
1014  Initforeach must create three local variables:
1015  0. the iterator
1016  1. the expression
1017  2. the counter
1018  and remove the expression from the value stack.
1019  It then jumps to the STEPFOREACH instruction.
1020  */
1022 {
1023  Locals2->push_back( BObjectRef() ); // the iterator
1024 
1025  // this is almost like popParam, only we don't want a copy.
1026  BObjectRef objref = getObjRef();
1027  Locals2->push_back( BObjectRef() );
1028  Locals2->back().set( objref.get() );
1029 
1030  Locals2->push_back( BObjectRef() );
1031  Locals2->back().set( new BObject( new BLong( 0 ) ) );
1032 
1033  PC = ins.token.lval;
1034 }
1035 
1036 
1038 {
1039  unsigned locsize = static_cast<unsigned int>( Locals2->size() );
1040  ObjArray* arr = static_cast<ObjArray*>( ( *Locals2 )[locsize - 2]->impptr() );
1041  if ( !arr->isa( BObjectImp::OTArray ) )
1042  return;
1043  BLong* blong = static_cast<BLong*>( ( *Locals2 )[locsize - 1]->impptr() );
1044 
1045  if ( blong->increment() > int( arr->ref_arr.size() ) )
1046  return;
1047 
1048  BObjectRef& objref = arr->ref_arr[blong->value() - 1];
1049  BObject* elem = objref.get();
1050  if ( elem == NULL )
1051  {
1052  elem = new BObject( UninitObject::create() );
1053  objref.set( elem );
1054  }
1055  ( *Locals2 )[locsize - 3].set( elem );
1056  PC = ins.token.lval;
1057 }
1058 
1060 {
1061  Locals2->push_back( BObjectRef() ); // the iterator
1062 
1063 
1064  auto pIterVal = new BObject( UninitObject::create() );
1065 
1066  // this is almost like popParam, only we don't want a copy.
1067  BObjectRef objref = getObjRef();
1068  Locals2->push_back( BObjectRef() );
1069  ContIterator* pIter = objref->impptr()->createIterator( pIterVal );
1070  Locals2->back().set( new BObject( pIter ) );
1071 
1072  Locals2->push_back( BObjectRef() );
1073  Locals2->back().set( pIterVal );
1074 
1075  PC = ins.token.lval;
1076 }
1077 
1078 
1080 {
1081  size_t locsize = Locals2->size();
1082  ContIterator* pIter = static_cast<ContIterator*>( ( *Locals2 )[locsize - 2]->impptr() );
1083 
1084  BObject* next = pIter->step();
1085  if ( next != NULL )
1086  {
1087  ( *Locals2 )[locsize - 3].set( next );
1088  PC = ins.token.lval;
1089  }
1090 }
1091 
1092 /*
1093  Coming into the INITFOR, there will be two values on the value stack:
1094  START VALUE
1095  END VALUE
1096 
1097  If START VALUE > END VALUE, we skip the whole for loop.
1098  (the INITFOR's lval has the instr to jump to)
1099  */
1100 
1102 {
1103  BObjectRef endref = getObjRef();
1104  BObjectRef startref = getObjRef();
1105  if ( *startref.get() > *endref.get() )
1106  {
1107  PC = ins.token.lval;
1108  return;
1109  }
1110 
1111  Locals2->push_back( BObjectRef( startref->clone() ) ); // the iterator
1112  Locals2->push_back( BObjectRef( endref->clone() ) );
1113 }
1114 
1116 {
1117  size_t locsize = Locals2->size();
1118 
1119 
1120  BObjectImp* itr = ( *Locals2 )[locsize - 2]->impptr();
1121  BObjectImp* end = ( *Locals2 )[locsize - 1]->impptr();
1122 
1123  if ( itr->isa( BObjectImp::OTLong ) )
1124  {
1125  BLong* blong = static_cast<BLong*>( itr );
1126  blong->increment();
1127  }
1128  else if ( itr->isa( BObjectImp::OTDouble ) )
1129  {
1130  Double* dbl = static_cast<Double*>( itr );
1131  dbl->increment();
1132  }
1133 
1134  if ( *end >= *itr )
1135  {
1136  PC = ins.token.lval;
1137  }
1138 }
1139 
1140 
1141 int Executor::ins_casejmp_findlong( const Token& token, BLong* blong )
1142 {
1143  const unsigned char* dataptr = token.dataptr;
1144  for ( ;; )
1145  {
1146  unsigned short offset;
1147  std::memcpy( &offset, dataptr, sizeof( unsigned short ) );
1148  dataptr += 2;
1149  unsigned char type = *dataptr;
1150  dataptr += 1;
1151  if ( type == CASE_TYPE_LONG )
1152  {
1153  int v = blong->value();
1154  if ( std::memcmp( &v, dataptr, sizeof( int ) ) == 0 )
1155  return offset;
1156  dataptr += 4;
1157  }
1158  else if ( type == CASE_TYPE_DEFAULT )
1159  {
1160  return offset;
1161  }
1162  else
1163  {
1164  dataptr += type;
1165  }
1166  }
1167 }
1168 
1169 int Executor::ins_casejmp_findstring( const Token& token, String* bstringimp )
1170 {
1171  const std::string& bstring = bstringimp->value();
1172  const unsigned char* dataptr = token.dataptr;
1173  for ( ;; )
1174  {
1175  unsigned short offset;
1176  std::memcpy( &offset, dataptr, sizeof( unsigned short ) );
1177  dataptr += 2;
1178  unsigned char type = *dataptr;
1179  dataptr += 1;
1180  if ( type == CASE_TYPE_LONG )
1181  {
1182  dataptr += 4;
1183  }
1184  else if ( type == CASE_TYPE_DEFAULT )
1185  {
1186  return offset;
1187  }
1188  else
1189  {
1190  if ( bstring.size() == type && memcmp( bstring.data(), dataptr, type ) == 0 )
1191  {
1192  return offset;
1193  }
1194  dataptr += type;
1195  }
1196  }
1197 }
1198 
1200 {
1201  const unsigned char* dataptr = token.dataptr;
1202  for ( ;; )
1203  {
1204  unsigned short offset;
1205  std::memcpy( &offset, dataptr, sizeof( unsigned short ) );
1206  dataptr += 2;
1207  unsigned char type = *dataptr;
1208  dataptr += 1;
1209  if ( type == CASE_TYPE_LONG )
1210  {
1211  dataptr += 4;
1212  }
1213  else if ( type == CASE_TYPE_DEFAULT )
1214  {
1215  return offset;
1216  }
1217  else
1218  {
1219  dataptr += type;
1220  }
1221  }
1222 }
1223 
1225 {
1226  BObjectRef& objref = ValueStack.back();
1227  BObjectImp* objimp = objref->impptr();
1228  if ( objimp->isa( BObjectImp::OTLong ) )
1229  {
1230  PC = ins_casejmp_findlong( ins.token, static_cast<BLong*>( objimp ) );
1231  }
1232  else if ( objimp->isa( BObjectImp::OTString ) )
1233  {
1234  PC = ins_casejmp_findstring( ins.token, static_cast<String*>( objimp ) );
1235  }
1236  else
1237  {
1238  PC = ins_casejmp_finddefault( ins.token );
1239  }
1240  ValueStack.pop_back();
1241 }
1242 
1243 
1245 {
1246  BObjectRef& objref = ValueStack.back();
1247 
1248  if ( objref->impptr()->isTrue() )
1249  PC = (unsigned)ins.token.lval;
1250 
1251  ValueStack.pop_back();
1252 }
1253 
1255 {
1256  BObjectRef& objref = ValueStack.back();
1257 
1258  if ( !objref->impptr()->isTrue() )
1259  PC = (unsigned)ins.token.lval;
1260 
1261  ValueStack.pop_back();
1262 }
1263 
1264 
1265 // case TOK_LOCALVAR:
1267 {
1268  ValueStack.push_back( ( *Locals2 )[ins.token.lval] );
1269 }
1270 
1271 // case RSV_GLOBAL:
1272 // case TOK_GLOBALVAR:
1274 {
1275  ValueStack.push_back( Globals2[ins.token.lval] );
1276 }
1277 
1278 // case TOK_LONG:
1280 {
1281  ValueStack.push_back( BObjectRef( new BObject( new BLong( ins.token.lval ) ) ) );
1282 }
1283 
1284 // case TOK_CONSUMER:
1285 void Executor::ins_consume( const Instruction& /*ins*/ )
1286 {
1287  ValueStack.pop_back();
1288 }
1289 
1291 {
1292  BObjectRef rightref = ValueStack.back();
1293  ValueStack.pop_back();
1294  BObjectRef& leftref = ValueStack.back();
1295 
1296  BObject& right = *rightref;
1297  BObject& left = *leftref;
1298 
1299  BObjectImp& rightimpref = right.impref();
1300  left.impref().set_member( ins.token.tokval(), &rightimpref,
1301  !( right.count() == 1 && rightimpref.count() == 1 ) );
1302 }
1303 
1305 {
1306  BObjectRef rightref = ValueStack.back();
1307  ValueStack.pop_back();
1308  BObjectRef& leftref = ValueStack.back();
1309 
1310  BObject& right = *rightref;
1311  BObject& left = *leftref;
1312 
1313  BObjectImp& rightimpref = right.impref();
1314  left.impref().set_member_id( ins.token.lval, &rightimpref,
1315  !( right.count() == 1 && rightimpref.count() == 1 ) );
1316 }
1317 
1319 {
1320  BObjectRef rightref = ValueStack.back();
1321  ValueStack.pop_back();
1322  BObjectRef& leftref = ValueStack.back();
1323 
1324  BObject& right = *rightref;
1325  BObject& left = *leftref;
1326 
1327  BObjectImp& rightimpref = right.impref();
1328  left.impref().set_member( ins.token.tokval(), &rightimpref,
1329  !( right.count() == 1 && rightimpref.count() == 1 ) );
1330  ValueStack.pop_back();
1331 }
1332 
1334 {
1335  BObjectRef rightref = ValueStack.back();
1336  ValueStack.pop_back();
1337  BObjectRef& leftref = ValueStack.back();
1338 
1339  BObject& right = *rightref;
1340  BObject& left = *leftref;
1341 
1342  BObjectImp& rightimpref = right.impref();
1343 
1344  left.impref().set_member_id( ins.token.lval, &rightimpref,
1345  !( right.count() == 1 && rightimpref.count() == 1 ) );
1346  ValueStack.pop_back();
1347 }
1348 
1350 {
1351  BObjectRef rightref = ValueStack.back();
1352  ValueStack.pop_back();
1353  BObjectRef& leftref = ValueStack.back();
1354 
1355  BObject& right = *rightref;
1356  BObject& left = *leftref;
1357 
1358  BObjectImp& leftimpref = left.impref();
1359 
1360  BObjectRef tmp = leftimpref.get_member_id( ins.token.lval );
1361  BObject obj( *tmp );
1362 
1363  if ( !obj.isa( BObjectImp::OTUninit ) &&
1364  !obj.isa( BObjectImp::OTError ) ) // do nothing if curval is uninit or error
1365  {
1366  tmp->impref().operPlusEqual( obj, right.impref() );
1367  leftimpref.set_member_id( ins.token.lval, &tmp->impref(), false );
1368  }
1369  ValueStack.pop_back();
1370 }
1371 
1373 {
1374  BObjectRef rightref = ValueStack.back();
1375  ValueStack.pop_back();
1376  BObjectRef& leftref = ValueStack.back();
1377 
1378  BObject& right = *rightref;
1379  BObject& left = *leftref;
1380 
1381  BObjectImp& leftimpref = left.impref();
1382 
1383  BObjectRef tmp = leftimpref.get_member_id( ins.token.lval );
1384  BObject obj( *tmp );
1385 
1386  if ( !obj.isa( BObjectImp::OTUninit ) &&
1387  !obj.isa( BObjectImp::OTError ) ) // do nothing if curval is uninit or error
1388  {
1389  tmp->impref().operMinusEqual( obj, right.impref() );
1390  leftimpref.set_member_id( ins.token.lval, &tmp->impref(), false );
1391  }
1392  ValueStack.pop_back();
1393 }
1394 
1396 {
1397  BObjectRef rightref = ValueStack.back();
1398  ValueStack.pop_back();
1399  BObjectRef& leftref = ValueStack.back();
1400 
1401  BObject& right = *rightref;
1402  BObject& left = *leftref;
1403 
1404  BObjectImp& leftimpref = left.impref();
1405 
1406  BObjectRef tmp = leftimpref.get_member_id( ins.token.lval );
1407  BObject obj( *tmp );
1408 
1409  if ( !obj.isa( BObjectImp::OTUninit ) &&
1410  !obj.isa( BObjectImp::OTError ) ) // do nothing if curval is uninit or error
1411  {
1412  tmp->impref().operTimesEqual( obj, right.impref() );
1413  leftimpref.set_member_id( ins.token.lval, &tmp->impref(), false );
1414  }
1415  ValueStack.pop_back();
1416 }
1417 
1419 {
1420  BObjectRef rightref = ValueStack.back();
1421  ValueStack.pop_back();
1422  BObjectRef& leftref = ValueStack.back();
1423 
1424  BObject& right = *rightref;
1425  BObject& left = *leftref;
1426 
1427  BObjectImp& leftimpref = left.impref();
1428 
1429  BObjectRef tmp = leftimpref.get_member_id( ins.token.lval );
1430  BObject obj( *tmp );
1431 
1432  if ( !obj.isa( BObjectImp::OTUninit ) &&
1433  !obj.isa( BObjectImp::OTError ) ) // do nothing if curval is uninit or error
1434  {
1435  tmp->impref().operDivideEqual( obj, right.impref() );
1436  leftimpref.set_member_id( ins.token.lval, &tmp->impref(), false );
1437  }
1438  ValueStack.pop_back();
1439 }
1440 
1442 {
1443  BObjectRef rightref = ValueStack.back();
1444  ValueStack.pop_back();
1445  BObjectRef& leftref = ValueStack.back();
1446 
1447  BObject& right = *rightref;
1448  BObject& left = *leftref;
1449 
1450  BObjectImp& leftimpref = left.impref();
1451 
1452  BObjectRef tmp = leftimpref.get_member_id( ins.token.lval );
1453  BObject obj( *tmp );
1454 
1455  if ( !obj.isa( BObjectImp::OTUninit ) &&
1456  !obj.isa( BObjectImp::OTError ) ) // do nothing if curval is uninit or error
1457  {
1458  tmp->impref().operModulusEqual( obj, right.impref() );
1459  leftimpref.set_member_id( ins.token.lval, &tmp->impref(), false );
1460  }
1461  ValueStack.pop_back();
1462 }
1463 
1465 {
1466  BObjectRef& leftref = ValueStack.back();
1467 
1468  BObject& left = *leftref;
1469 
1470 #ifdef ESCRIPT_PROFILE
1471  std::stringstream strm;
1472  strm << "MBR_" << leftref->impptr()->typeOf() << " ." << ins.token.tokval();
1473  if ( !fparams.empty() )
1474  strm << " [" << fparams[0].get()->impptr()->typeOf() << "]";
1475  std::string name( strm.str() );
1476  unsigned long profile_start = GetTimeUs();
1477 #endif
1478  leftref = left->get_member( ins.token.tokval() );
1479 #ifdef ESCRIPT_PROFILE
1480  profile_escript( name, profile_start );
1481 #endif
1482 }
1483 
1485 {
1486  BObjectRef& leftref = ValueStack.back();
1487 
1488  BObject& left = *leftref;
1489 
1490 #ifdef ESCRIPT_PROFILE
1491  std::stringstream strm;
1492  strm << "MBR_" << leftref->impptr()->typeOf() << " ." << ins.token.lval;
1493  if ( !fparams.empty() )
1494  strm << " [" << fparams[0].get()->impptr()->typeOf() << "]";
1495  std::string name( strm.str() );
1496  unsigned long profile_start = GetTimeUs();
1497 #endif
1498  leftref = left->get_member_id( ins.token.lval );
1499 #ifdef ESCRIPT_PROFILE
1500  profile_escript( name, profile_start );
1501 #endif
1502 }
1503 
1505 {
1506  BObjectRef& lvar = ( *Locals2 )[ins.token.lval];
1507 
1508  BObjectRef& rightref = ValueStack.back();
1509 
1510  BObject& right = *rightref;
1511 
1512  BObjectImp& rightimpref = right.impref();
1513 
1514  if ( right.count() == 1 && rightimpref.count() == 1 )
1515  {
1516  lvar->setimp( &rightimpref );
1517  }
1518  else
1519  {
1520  lvar->setimp( rightimpref.copy() );
1521  }
1522  ValueStack.pop_back();
1523 }
1525 {
1526  BObjectRef& gvar = Globals2[ins.token.lval];
1527 
1528  BObjectRef& rightref = ValueStack.back();
1529 
1530  BObject& right = *rightref;
1531 
1532  BObjectImp& rightimpref = right.impref();
1533 
1534  if ( right.count() == 1 && rightimpref.count() == 1 )
1535  {
1536  gvar->setimp( &rightimpref );
1537  }
1538  else
1539  {
1540  gvar->setimp( rightimpref.copy() );
1541  }
1542  ValueStack.pop_back();
1543 }
1544 
1545 // case INS_ASSIGN_CONSUME:
1547 {
1548  BObjectRef rightref = ValueStack.back();
1549  ValueStack.pop_back();
1550  BObjectRef& leftref = ValueStack.back();
1551 
1552  BObject& right = *rightref;
1553  BObject& left = *leftref;
1554 
1555  BObjectImp& rightimpref = right.impref();
1556 
1557  if ( right.count() == 1 && rightimpref.count() == 1 )
1558  {
1559  left.setimp( &rightimpref );
1560  }
1561  else
1562  {
1563  left.setimp( rightimpref.copy() );
1564  }
1565  ValueStack.pop_back();
1566 }
1567 
1568 void Executor::ins_assign( const Instruction& /*ins*/ )
1569 {
1570  /*
1571  These each take two operands, and replace them with one.
1572  We'll leave the second one on the value stack, and
1573  just replace its object with the result
1574  */
1575  BObjectRef rightref = ValueStack.back();
1576  ValueStack.pop_back();
1577  BObjectRef& leftref = ValueStack.back();
1578 
1579  BObject& right = *rightref;
1580  BObject& left = *leftref;
1581 
1582  BObjectImp& rightimpref = right.impref();
1583 
1584  if ( right.count() == 1 && rightimpref.count() == 1 )
1585  {
1586  left.setimp( &rightimpref );
1587  }
1588  else
1589  {
1590  left.setimp( rightimpref.copy() );
1591  }
1592 }
1593 
1595 {
1596  /*
1597  on the value stack:
1598  x[i] := y;
1599  (top)
1600  y
1601  i
1602  x
1603  upon exit:
1604  (x[i])
1605  */
1606  BObjectRef y_ref = ValueStack.back();
1607  ValueStack.pop_back();
1608  BObjectRef i_ref = ValueStack.back();
1609  ValueStack.pop_back();
1610  BObjectRef& x_ref = ValueStack.back();
1611 
1612  BObject& y = *y_ref;
1613  BObject& i = *i_ref;
1614  BObject& x = *x_ref;
1615 
1616  BObjectImp* result;
1617  result = x->array_assign( i.impptr(), y.impptr(), ( y.count() != 1 ) );
1618 
1619  x_ref.set( new BObject( result ) );
1620 }
1622 {
1623  /*
1624  on the value stack:
1625  x[i] := y;
1626  (top)
1627  y
1628  i
1629  x
1630  upon exit:
1631  (x[i])
1632  */
1633  BObjectRef y_ref = ValueStack.back();
1634  ValueStack.pop_back();
1635  BObjectRef i_ref = ValueStack.back();
1636  ValueStack.pop_back();
1637  BObjectRef& x_ref = ValueStack.back();
1638 
1639  BObject& y = *y_ref;
1640  BObject& i = *i_ref;
1641  BObject& x = *x_ref;
1642 
1643  BObjectImp* result;
1644  result = x->array_assign( i.impptr(), y.impptr(), ( y.count() != 1 ) );
1645 
1646  BObject obj( result );
1647  ValueStack.pop_back();
1648 }
1649 
1650 // TOK_ADD:
1651 void Executor::ins_add( const Instruction& /*ins*/ )
1652 {
1653  /*
1654  These each take two operands, and replace them with one.
1655  We'll leave the second one on the value stack, and
1656  just replace its object with the result
1657  */
1658  BObjectRef rightref = ValueStack.back();
1659  ValueStack.pop_back();
1660  BObjectRef& leftref = ValueStack.back();
1661 
1662  BObject& right = *rightref;
1663  BObject& left = *leftref;
1664 
1665  leftref.set( new BObject( right.impref().selfPlusObjImp( left.impref() ) ) );
1666 }
1667 
1668 // TOK_SUBTRACT
1669 void Executor::ins_subtract( const Instruction& /*ins*/ )
1670 {
1671  /*
1672  These each take two operands, and replace them with one.
1673  We'll leave the second one on the value stack, and
1674  just replace its object with the result
1675  */
1676  BObjectRef rightref = ValueStack.back();
1677  ValueStack.pop_back();
1678  BObjectRef& leftref = ValueStack.back();
1679 
1680  BObject& right = *rightref;
1681  BObject& left = *leftref;
1682 
1683  leftref.set( new BObject( right.impref().selfMinusObjImp( left.impref() ) ) );
1684 }
1685 
1686 // TOK_MULT:
1687 void Executor::ins_mult( const Instruction& /*ins*/ )
1688 {
1689  /*
1690  These each take two operands, and replace them with one.
1691  We'll leave the second one on the value stack, and
1692  just replace its object with the result
1693  */
1694  BObjectRef rightref = ValueStack.back();
1695  ValueStack.pop_back();
1696  BObjectRef& leftref = ValueStack.back();
1697 
1698  BObject& right = *rightref;
1699  BObject& left = *leftref;
1700 
1701  leftref.set( new BObject( right.impref().selfTimesObjImp( left.impref() ) ) );
1702 }
1703 // TOK_DIV:
1704 void Executor::ins_div( const Instruction& /*ins*/ )
1705 {
1706  /*
1707  These each take two operands, and replace them with one.
1708  We'll leave the second one on the value stack, and
1709  just replace its object with the result
1710  */
1711  BObjectRef rightref = ValueStack.back();
1712  ValueStack.pop_back();
1713  BObjectRef& leftref = ValueStack.back();
1714 
1715  BObject& right = *rightref;
1716  BObject& left = *leftref;
1717 
1718  leftref.set( new BObject( right.impref().selfDividedByObjImp( left.impref() ) ) );
1719 }
1720 // TOK_MODULUS:
1721 void Executor::ins_modulus( const Instruction& /*ins*/ )
1722 {
1723  /*
1724  These each take two operands, and replace them with one.
1725  We'll leave the second one on the value stack, and
1726  just replace its object with the result
1727  */
1728  BObjectRef rightref = ValueStack.back();
1729  ValueStack.pop_back();
1730  BObjectRef& leftref = ValueStack.back();
1731 
1732  BObject& right = *rightref;
1733  BObject& left = *leftref;
1734 
1735  leftref.set( new BObject( right.impref().selfModulusObjImp( left.impref() ) ) );
1736 }
1737 // TOK_BSRIGHT:
1739 {
1740  /*
1741  These each take two operands, and replace them with one.
1742  We'll leave the second one on the value stack, and
1743  just replace its object with the result
1744  */
1745  BObjectRef rightref = ValueStack.back();
1746  ValueStack.pop_back();
1747  BObjectRef& leftref = ValueStack.back();
1748 
1749  BObject& right = *rightref;
1750  BObject& left = *leftref;
1751 
1752  leftref.set( new BObject( right.impref().selfBitShiftRightObjImp( left.impref() ) ) );
1753 }
1754 // TOK_BSLEFT:
1756 {
1757  /*
1758  These each take two operands, and replace them with one.
1759  We'll leave the second one on the value stack, and
1760  just replace its object with the result
1761  */
1762  BObjectRef rightref = ValueStack.back();
1763  ValueStack.pop_back();
1764  BObjectRef& leftref = ValueStack.back();
1765 
1766  BObject& right = *rightref;
1767  BObject& left = *leftref;
1768 
1769  leftref.set( new BObject( right.impref().selfBitShiftLeftObjImp( left.impref() ) ) );
1770 }
1771 // TOK_BITAND:
1773 {
1774  /*
1775  These each take two operands, and replace them with one.
1776  We'll leave the second one on the value stack, and
1777  just replace its object with the result
1778  */
1779  BObjectRef rightref = ValueStack.back();
1780  ValueStack.pop_back();
1781  BObjectRef& leftref = ValueStack.back();
1782 
1783  BObject& right = *rightref;
1784  BObject& left = *leftref;
1785 
1786  leftref.set( new BObject( right.impref().selfBitAndObjImp( left.impref() ) ) );
1787 }
1788 // TOK_BITXOR:
1790 {
1791  /*
1792  These each take two operands, and replace them with one.
1793  We'll leave the second one on the value stack, and
1794  just replace its object with the result
1795  */
1796  BObjectRef rightref = ValueStack.back();
1797  ValueStack.pop_back();
1798  BObjectRef& leftref = ValueStack.back();
1799 
1800  BObject& right = *rightref;
1801  BObject& left = *leftref;
1802 
1803  leftref.set( new BObject( right.impref().selfBitXorObjImp( left.impref() ) ) );
1804 }
1805 // TOK_BITOR:
1807 {
1808  /*
1809  These each take two operands, and replace them with one.
1810  We'll leave the second one on the value stack, and
1811  just replace its object with the result
1812  */
1813  BObjectRef rightref = ValueStack.back();
1814  ValueStack.pop_back();
1815  BObjectRef& leftref = ValueStack.back();
1816 
1817  BObject& right = *rightref;
1818  BObject& left = *leftref;
1819 
1820  leftref.set( new BObject( right.impref().selfBitOrObjImp( left.impref() ) ) );
1821 }
1822 
1824 {
1825  /*
1826  These each take two operands, and replace them with one.
1827  We'll leave the second one on the value stack, and
1828  just replace its object with the result
1829  */
1830  BObjectRef rightref = ValueStack.back();
1831  ValueStack.pop_back();
1832  BObjectRef& leftref = ValueStack.back();
1833 
1834  BObject& right = *rightref;
1835  BObject& left = *leftref;
1836 
1837  int _true = ( left.isTrue() && right.isTrue() );
1838  leftref.set( new BObject( new BLong( _true ) ) );
1839 }
1841 {
1842  /*
1843  These each take two operands, and replace them with one.
1844  We'll leave the second one on the value stack, and
1845  just replace its object with the result
1846  */
1847  BObjectRef rightref = ValueStack.back();
1848  ValueStack.pop_back();
1849  BObjectRef& leftref = ValueStack.back();
1850 
1851  BObject& right = *rightref;
1852  BObject& left = *leftref;
1853 
1854  int _true = ( left.isTrue() || right.isTrue() );
1855  leftref.set( new BObject( new BLong( _true ) ) );
1856 }
1857 
1858 void Executor::ins_notequal( const Instruction& /*ins*/ )
1859 {
1860  /*
1861  These each take two operands, and replace them with one.
1862  We'll leave the second one on the value stack, and
1863  just replace its object with the result
1864  */
1865  BObjectRef rightref = ValueStack.back();
1866  ValueStack.pop_back();
1867  BObjectRef& leftref = ValueStack.back();
1868 
1869  BObject& right = *rightref;
1870  BObject& left = *leftref;
1871 
1872  int _true = ( left != right );
1873  leftref.set( new BObject( new BLong( _true ) ) );
1874 }
1875 
1876 void Executor::ins_equal( const Instruction& /*ins*/ )
1877 {
1878  /*
1879  These each take two operands, and replace them with one.
1880  We'll leave the second one on the value stack, and
1881  just replace its object with the result
1882  */
1883  BObjectRef rightref = ValueStack.back();
1884  ValueStack.pop_back();
1885  BObjectRef& leftref = ValueStack.back();
1886 
1887  BObject& right = *rightref;
1888  BObject& left = *leftref;
1889 
1890  int _true = ( left == right );
1891  leftref.set( new BObject( new BLong( _true ) ) );
1892 }
1893 
1894 void Executor::ins_lessthan( const Instruction& /*ins*/ )
1895 {
1896  /*
1897  These each take two operands, and replace them with one.
1898  We'll leave the second one on the value stack, and
1899  just replace its object with the result
1900  */
1901  BObjectRef rightref = ValueStack.back();
1902  ValueStack.pop_back();
1903  BObjectRef& leftref = ValueStack.back();
1904 
1905  BObject& right = *rightref;
1906  BObject& left = *leftref;
1907 
1908  int _true = ( left < right );
1909  leftref.set( new BObject( new BLong( _true ) ) );
1910 }
1911 
1912 void Executor::ins_lessequal( const Instruction& /*ins*/ )
1913 {
1914  /*
1915  These each take two operands, and replace them with one.
1916  We'll leave the second one on the value stack, and
1917  just replace its object with the result
1918  */
1919  BObjectRef rightref = ValueStack.back();
1920  ValueStack.pop_back();
1921  BObjectRef& leftref = ValueStack.back();
1922 
1923  BObject& right = *rightref;
1924  BObject& left = *leftref;
1925  int _true = ( left <= right );
1926  leftref.set( new BObject( new BLong( _true ) ) );
1927 }
1929 {
1930  /*
1931  These each take two operands, and replace them with one.
1932  We'll leave the second one on the value stack, and
1933  just replace its object with the result
1934  */
1935  BObjectRef rightref = ValueStack.back();
1936  ValueStack.pop_back();
1937  BObjectRef& leftref = ValueStack.back();
1938 
1939  BObject& right = *rightref;
1940  BObject& left = *leftref;
1941 
1942  int _true = ( left > right );
1943  leftref.set( new BObject( new BLong( _true ) ) );
1944 }
1946 {
1947  /*
1948  These each take two operands, and replace them with one.
1949  We'll leave the second one on the value stack, and
1950  just replace its object with the result
1951  */
1952  BObjectRef rightref = ValueStack.back();
1953  ValueStack.pop_back();
1954  BObjectRef& leftref = ValueStack.back();
1955 
1956  BObject& right = *rightref;
1957  BObject& left = *leftref;
1958 
1959  int _true = ( left >= right );
1960  leftref.set( new BObject( new BLong( _true ) ) );
1961 }
1962 
1963 // case TOK_ARRAY_SUBSCRIPT:
1965 {
1966  /*
1967  These each take two operands, and replace them with one.
1968  We'll leave the second one on the value stack, and
1969  just replace its object with the result
1970  */
1971  BObjectRef rightref = ValueStack.back();
1972  ValueStack.pop_back();
1973  BObjectRef& leftref = ValueStack.back();
1974 
1975  leftref = ( *leftref )->OperSubscript( *rightref );
1976 }
1977 
1979 {
1980  // the subscripts are on the value stack in right-to-left order, followed by the array itself
1981  std::stack<BObjectRef> indices;
1982  for ( int i = 0; i < ins.token.lval; ++i )
1983  {
1984  indices.push( ValueStack.back() );
1985  ValueStack.pop_back();
1986  }
1987 
1988  BObjectRef& leftref = ValueStack.back();
1989  leftref = ( *leftref )->OperMultiSubscript( indices );
1990 }
1992 {
1993  BObjectRef target_ref = ValueStack.back();
1994  ValueStack.pop_back();
1995  // the subscripts are on the value stack in right-to-left order, followed by the array itself
1996  std::stack<BObjectRef> indices;
1997  for ( int i = 0; i < ins.token.lval; ++i )
1998  {
1999  indices.push( ValueStack.back() );
2000  ValueStack.pop_back();
2001  }
2002 
2003  BObjectRef& leftref = ValueStack.back();
2004  leftref = ( *leftref )->OperMultiSubscriptAssign( indices, target_ref->impptr() );
2005 }
2006 
2007 void Executor::ins_addmember( const Instruction& /*ins*/ )
2008 {
2009  /*
2010  These each take two operands, and replace them with one.
2011  We'll leave the second one on the value stack, and
2012  just replace its object with the result
2013  */
2014  BObjectRef rightref = ValueStack.back();
2015  ValueStack.pop_back();
2016  BObjectRef& leftref = ValueStack.back();
2017 
2018  BObject& right = *rightref;
2019  BObject& left = *leftref;
2020 
2021  leftref = addmember( left, right );
2022 }
2023 
2025 {
2026  /*
2027  These each take two operands, and replace them with one.
2028  We'll leave the second one on the value stack, and
2029  just replace its object with the result
2030  */
2031  BObjectRef rightref = ValueStack.back();
2032  ValueStack.pop_back();
2033  BObjectRef& leftref = ValueStack.back();
2034 
2035  BObject& right = *rightref;
2036  BObject& left = *leftref;
2037 
2038  leftref = removemember( left, right );
2039 }
2040 
2042 {
2043  /*
2044  These each take two operands, and replace them with one.
2045  We'll leave the second one on the value stack, and
2046  just replace its object with the result
2047  */
2048  BObjectRef rightref = ValueStack.back();
2049  ValueStack.pop_back();
2050  BObjectRef& leftref = ValueStack.back();
2051 
2052  BObject& right = *rightref;
2053  BObject& left = *leftref;
2054 
2055  leftref = checkmember( left, right );
2056 }
2057 
2059 {
2060  BObjectRef obref = ValueStack.back();
2061 
2062  BObject& ob = *obref;
2063 
2064  ob.impref().operDotPlus( ins.token.tokval() );
2065 }
2066 
2068 {
2069  BObjectRef valref = ValueStack.back();
2070  BObject& valob = *valref;
2071  BObjectImp* valimp = valref->impptr();
2072 
2073  ValueStack.pop_back();
2074 
2075  BObjectRef obref = ValueStack.back();
2076  BObject& ob = *obref;
2077 
2078  BObjectRef memref = ob.impref().operDotPlus( ins.token.tokval() );
2079  BObject& mem = *memref;
2080 
2081  if ( valob.count() == 1 && valimp->count() == 1 )
2082  {
2083  mem.setimp( valimp );
2084  }
2085  else
2086  {
2087  mem.setimp( valimp->copy() );
2088  }
2089  // the struct is at the top of the stack
2090 }
2091 
2093 {
2094  /*
2095  ENTRANCE: value stack:
2096  dictionary
2097  key
2098  value
2099  EXIT: value stack:
2100  dictionary
2101  FUNCTION:
2102  adds the (key, value) pair to the dictionary
2103  */
2104 
2105  BObjectRef valref = ValueStack.back();
2106  ValueStack.pop_back();
2107  BObject& valob = *valref;
2108  BObjectImp* valimp = valob.impptr();
2109 
2110  BObjectRef keyref = ValueStack.back();
2111  ValueStack.pop_back();
2112  BObject& keyob = *keyref;
2113  BObjectImp* keyimp = keyob.impptr();
2114 
2115  BObjectRef dictref = ValueStack.back();
2116  BObject& dictob = *dictref;
2117  BDictionary* dict = static_cast<BDictionary*>( dictob.impptr() );
2118 
2119  if ( keyob.count() != 1 || keyimp->count() != 1 )
2120  {
2121  keyimp = keyimp->copy();
2122  }
2123  if ( valob.count() != 1 || valimp->count() != 1 )
2124  {
2125  valimp = valimp->copy();
2126  }
2127 
2128  dict->addMember( keyimp, valimp );
2129  // the dictionary remains at the top of the stack.
2130 }
2131 
2132 void Executor::ins_in( const Instruction& /*ins*/ )
2133 {
2134  /*
2135  These each take two operands, and replace them with one.
2136  We'll leave the second one on the value stack, and
2137  just replace its object with the result
2138  */
2139  BObjectRef rightref = ValueStack.back();
2140  ValueStack.pop_back();
2141  BObjectRef& leftref = ValueStack.back();
2142 
2143  BObject& right = *rightref;
2144  BObject& left = *leftref;
2145 
2146  leftref.set( new BObject( new BLong( right.impref().contains( left.impref() ) ) ) );
2147 }
2148 
2150 {
2151  BObjectRef rightref = ValueStack.back();
2152  ValueStack.pop_back();
2153  BObjectRef& leftref = ValueStack.back();
2154 
2155  BObject& right = *rightref;
2156  BObject& left = *leftref;
2157 
2158  left.impref().operInsertInto( left, right.impref() );
2159 }
2160 
2161 void Executor::ins_plusequal( const Instruction& /*ins*/ )
2162 {
2163  /*
2164  These each take two operands, and replace them with one.
2165  We'll leave the second one on the value stack, and
2166  just replace its object with the result
2167  */
2168  BObjectRef rightref = ValueStack.back();
2169  ValueStack.pop_back();
2170  BObjectRef& leftref = ValueStack.back();
2171 
2172  BObject& right = *rightref;
2173  BObject& left = *leftref;
2174 
2175  left.impref().operPlusEqual( left, right.impref() );
2176 }
2177 
2179 {
2180  /*
2181  These each take two operands, and replace them with one.
2182  We'll leave the second one on the value stack, and
2183  just replace its object with the result
2184  */
2185  BObjectRef rightref = ValueStack.back();
2186  ValueStack.pop_back();
2187  BObjectRef& leftref = ValueStack.back();
2188 
2189  BObject& right = *rightref;
2190  BObject& left = *leftref;
2191 
2192  left.impref().operMinusEqual( left, right.impref() );
2193 }
2194 
2196 {
2197  /*
2198  These each take two operands, and replace them with one.
2199  We'll leave the second one on the value stack, and
2200  just replace its object with the result
2201  */
2202  BObjectRef rightref = ValueStack.back();
2203  ValueStack.pop_back();
2204  BObjectRef& leftref = ValueStack.back();
2205 
2206  BObject& right = *rightref;
2207  BObject& left = *leftref;
2208 
2209  left.impref().operTimesEqual( left, right.impref() );
2210 }
2211 
2213 {
2214  /*
2215  These each take two operands, and replace them with one.
2216  We'll leave the second one on the value stack, and
2217  just replace its object with the result
2218  */
2219  BObjectRef rightref = ValueStack.back();
2220  ValueStack.pop_back();
2221  BObjectRef& leftref = ValueStack.back();
2222 
2223  BObject& right = *rightref;
2224  BObject& left = *leftref;
2225 
2226  left.impref().operDivideEqual( left, right.impref() );
2227 }
2228 
2230 {
2231  /*
2232  These each take two operands, and replace them with one.
2233  We'll leave the second one on the value stack, and
2234  just replace its object with the result
2235  */
2236  BObjectRef rightref = ValueStack.back();
2237  ValueStack.pop_back();
2238  BObjectRef& leftref = ValueStack.back();
2239 
2240  BObject& right = *rightref;
2241  BObject& left = *leftref;
2242 
2243  left.impref().operModulusEqual( left, right.impref() );
2244 }
2245 
2246 // case RSV_GOTO:
2248 {
2249  PC = (unsigned)ins.token.lval;
2250 }
2251 
2252 // TOK_FUNC:
2254 {
2255  unsigned nparams = prog_->modules[ins.token.module]->functions[ins.token.lval]->nargs;
2256  getParams( nparams );
2257  execFunc( ins.token );
2258  cleanParams();
2259  return;
2260 }
2261 
2263 {
2264  unsigned nparams = ins.token.type;
2265  getParams( nparams );
2266 
2267  if ( ValueStack.back()->isa( BObjectImp::OTFuncRef ) )
2268  {
2269  BObjectRef objref = ValueStack.back();
2270  auto funcr = static_cast<BFunctionRef*>( objref->impptr() );
2271  Instruction jmp;
2272  if ( funcr->validCall( ins.token.lval, *this, &jmp ) )
2273  {
2274  // params need to be on the stack, without current objectref
2275  ValueStack.pop_back();
2276  for ( auto& p : fparams )
2277  ValueStack.push_back( p );
2278  // jump to function
2279  ins_jsr_userfunc( jmp );
2280  fparams.clear();
2281  // switch to new block
2282  ins_makelocal( jmp );
2283  return;
2284  }
2285  }
2286  BObjectRef& objref = ValueStack.back();
2287 #ifdef ESCRIPT_PROFILE
2288  std::stringstream strm;
2289  strm << "MTHID_" << objref->impptr()->typeOf() << " ." << ins.token.lval;
2290  if ( !fparams.empty() )
2291  strm << " [" << fparams[0].get()->impptr()->typeOf() << "]";
2292  std::string name( strm.str() );
2293  unsigned long profile_start = GetTimeUs();
2294 #endif
2295  BObjectImp* imp = objref->impptr()->call_method_id( ins.token.lval, *this );
2296 #ifdef ESCRIPT_PROFILE
2297  profile_escript( name, profile_start );
2298 #endif
2299  if ( func_result_ )
2300  {
2301  if ( imp )
2302  {
2303  BObject obj( imp );
2304  }
2305 
2306  objref.set( new BObject( func_result_ ) );
2307  func_result_ = NULL;
2308  }
2309  else if ( imp )
2310  {
2311  objref.set( new BObject( imp ) );
2312  }
2313  else
2314  {
2315  objref.set( new BObject( UninitObject::create() ) );
2316  }
2317 
2318  cleanParams();
2319  return;
2320 }
2321 
2323 {
2324  unsigned nparams = ins.token.lval;
2325  getParams( nparams );
2326 
2327  if ( ValueStack.back()->isa( BObjectImp::OTFuncRef ) )
2328  {
2329  BObjectRef objref = ValueStack.back();
2330  auto funcr = static_cast<BFunctionRef*>( objref->impptr() );
2331  Instruction jmp;
2332  if ( funcr->validCall( ins.token.tokval(), *this, &jmp ) )
2333  {
2334  // params need to be on the stack, without current objectref
2335  ValueStack.pop_back();
2336  for ( auto& p : fparams )
2337  ValueStack.push_back( p );
2338  // jump to function
2339  ins_jsr_userfunc( jmp );
2340  fparams.clear();
2341  // switch to new block
2342  ins_makelocal( jmp );
2343  return;
2344  }
2345  }
2346 
2347  BObjectRef& objref = ValueStack.back();
2348 #ifdef ESCRIPT_PROFILE
2349  std::stringstream strm;
2350  strm << "MTH_" << objref->impptr()->typeOf() << " ." << ins.token.tokval();
2351  if ( !fparams.empty() )
2352  strm << " [" << fparams[0].get()->impptr()->typeOf() << "]";
2353  std::string name( strm.str() );
2354  unsigned long profile_start = GetTimeUs();
2355 #endif
2356  BObjectImp* imp = objref->impptr()->call_method( ins.token.tokval(), *this );
2357 #ifdef ESCRIPT_PROFILE
2358  profile_escript( name, profile_start );
2359 #endif
2360 
2361  if ( func_result_ )
2362  {
2363  if ( imp )
2364  {
2365  BObject obj( imp );
2366  }
2367 
2368  objref.set( new BObject( func_result_ ) );
2369  func_result_ = NULL;
2370  }
2371  else if ( imp )
2372  {
2373  objref.set( new BObject( imp ) );
2374  }
2375  else
2376  {
2377  objref.set( new BObject( UninitObject::create() ) );
2378  }
2379 
2380  cleanParams();
2381  return;
2382 }
2383 
2384 // CTRL_STATEMENTBEGIN:
2386 {
2387  if ( debug_level >= SOURCELINES && ins.token.tokval() )
2388  INFO_PRINT << ins.token.tokval() << "\n";
2389 }
2390 
2391 // case CTRL_PROGEND:
2392 void Executor::ins_progend( const Instruction& /*ins*/ )
2393 {
2394  done = 1;
2395  run_ok_ = false;
2396  PC = 0;
2397 }
2398 
2399 
2400 // case CTRL_MAKELOCAL:
2401 void Executor::ins_makelocal( const Instruction& /*ins*/ )
2402 {
2403  if ( Locals2 )
2404  upperLocals2.push_back( Locals2 );
2405  Locals2 = new BObjectRefVec;
2406 }
2407 
2408 // CTRL_JSR_USERFUNC:
2410 {
2411  ReturnContext rc;
2412  rc.PC = PC;
2413  rc.ValueStackDepth = static_cast<unsigned int>( ValueStack.size() );
2414  ControlStack.push_back( rc );
2415 
2416  PC = (unsigned)ins.token.lval;
2417  if ( ControlStack.size() >= escript_config.max_call_depth )
2418  {
2419  fmt::Writer tmp;
2420  tmp << "Script " << scriptname() << " exceeded maximum call depth\n"
2421  << "Return path PCs: ";
2422  while ( !ControlStack.empty() )
2423  {
2424  rc = ControlStack.back();
2425  ControlStack.pop_back();
2426  tmp << rc.PC << " ";
2427  }
2428  POLLOG << tmp.str() << "\n";
2429  seterror( true );
2430  }
2431 }
2432 
2434 {
2435  popParam( ins.token );
2436 }
2437 
2439 {
2440  popParamByRef( ins.token );
2441 }
2442 
2444 {
2445  getArg( ins.token );
2446 }
2447 
2448 // CTRL_LEAVE_BLOCK:
2450 {
2451  if ( Locals2 )
2452  {
2453  for ( int i = 0; i < ins.token.lval; i++ )
2454  Locals2->pop_back();
2455  }
2456  else // at global level. ick.
2457  {
2458  for ( int i = 0; i < ins.token.lval; i++ )
2459  Globals2.pop_back();
2460  }
2461 }
2462 
2464 {
2465  ReturnContext rc;
2466  rc.PC = PC;
2467  rc.ValueStackDepth = static_cast<unsigned int>( ValueStack.size() );
2468  ControlStack.push_back( rc );
2469  if ( Locals2 )
2470  upperLocals2.push_back( Locals2 );
2471  Locals2 = new BObjectRefVec;
2472 
2473  PC = (unsigned)ins.token.lval;
2474 }
2475 
2476 // case RSV_RETURN
2477 void Executor::ins_return( const Instruction& /*ins*/ )
2478 {
2479  if ( ControlStack.empty() )
2480  {
2481  ERROR_PRINT << "Return without GOSUB!\n";
2482 
2483  seterror( true );
2484  return;
2485  }
2486  ReturnContext& rc = ControlStack.back();
2487  PC = rc.PC;
2488  // FIXME do something with rc.ValueStackDepth
2489  ControlStack.pop_back();
2490 
2491  if ( Locals2 )
2492  {
2493  delete Locals2;
2494  Locals2 = NULL;
2495  }
2496  if ( !upperLocals2.empty() )
2497  {
2498  Locals2 = upperLocals2.back();
2499  upperLocals2.pop_back();
2500  }
2501 }
2502 
2503 void Executor::ins_exit( const Instruction& /*ins*/ )
2504 {
2505  done = 1;
2506  run_ok_ = false;
2507 }
2508 
2510 {
2511  ValueStack.push_back( BObjectRef( new BObject( new Double( ins.token.dval ) ) ) );
2512 }
2514 {
2515  ValueStack.push_back( BObjectRef( new BObject( new String( ins.token.tokval() ) ) ) );
2516 }
2517 void Executor::ins_error( const Instruction& /*ins*/ )
2518 {
2519  ValueStack.push_back( BObjectRef( new BObject( new BError() ) ) );
2520 }
2521 void Executor::ins_struct( const Instruction& /*ins*/ )
2522 {
2523  ValueStack.push_back( BObjectRef( new BObject( new BStruct ) ) );
2524 }
2525 void Executor::ins_array( const Instruction& /*ins*/ )
2526 {
2527  ValueStack.push_back( BObjectRef( new BObject( new ObjArray ) ) );
2528 }
2530 {
2531  ValueStack.push_back( BObjectRef( new BObject( new BDictionary ) ) );
2532 }
2533 void Executor::ins_uninit( const Instruction& /*ins*/ )
2534 {
2535  ValueStack.push_back( BObjectRef( new BObject( UninitObject::create() ) ) );
2536 }
2537 void Executor::ins_ident( const Instruction& /*ins*/ )
2538 {
2539  ValueStack.push_back( BObjectRef( new BObject( new BError( "Please recompile this script" ) ) ) );
2540 }
2541 
2542 // case TOK_UNMINUS:
2543 void Executor::ins_unminus( const Instruction& /*ins*/ )
2544 {
2545  BObjectRef ref = getObjRef();
2546  BObjectImp* newobj;
2547  newobj = ref->impref().inverse();
2548 
2549  ValueStack.push_back( BObjectRef( new BObject( newobj ) ) );
2550 }
2551 
2552 // case TOK_LOG_NOT:
2554 {
2555  BObjectRef ref = getObjRef();
2556  ValueStack.push_back( BObjectRef( new BObject( new BLong( (int)!ref->impptr()->isTrue() ) ) ) );
2557  return;
2558 }
2559 
2560 // case TOK_BITWISE_NOT:
2562 {
2563  BObjectRef ref = getObjRef();
2564  ValueStack.push_back( BObjectRef( new BObject( ref->impptr()->bitnot() ) ) );
2565  return;
2566 }
2567 
2569 {
2570  ValueStack.push_back( BObjectRef(
2571  new BObject( new BFunctionRef( ins.token.lval, ins.token.type, scriptname() ) ) ) );
2572 }
2573 
2574 void Executor::ins_nop( const Instruction& /*ins*/ ) {}
2575 
2577 {
2578  switch ( token.id )
2579  {
2580  case INS_INITFOREACH:
2582  case INS_STEPFOREACH:
2584  case INS_INITFOR:
2585  return &Executor::ins_initfor;
2586  case INS_NEXTFOR:
2587  return &Executor::ins_nextfor;
2588  case INS_CASEJMP:
2589  return &Executor::ins_casejmp;
2590  case RSV_JMPIFTRUE:
2591  return &Executor::ins_jmpiftrue;
2592  case RSV_JMPIFFALSE:
2593  return &Executor::ins_jmpiffalse;
2594  case RSV_LOCAL:
2595  return &Executor::ins_makeLocal;
2596  case RSV_GLOBAL:
2597  case TOK_GLOBALVAR:
2598  return &Executor::ins_globalvar;
2599  case TOK_LOCALVAR:
2600  return &Executor::ins_localvar;
2601  case TOK_LONG:
2602  return &Executor::ins_long;
2603  case TOK_DOUBLE:
2604  return &Executor::ins_double;
2605  case TOK_STRING:
2606  return &Executor::ins_string;
2607  case TOK_ERROR:
2608  return &Executor::ins_error;
2609  case TOK_STRUCT:
2610  return &Executor::ins_struct;
2611  case TOK_ARRAY:
2612  return &Executor::ins_array;
2613  case TOK_DICTIONARY:
2614  return &Executor::ins_dictionary;
2615  case TOK_FUNCREF:
2616  return &Executor::ins_funcref;
2617  case INS_UNINIT:
2618  return &Executor::ins_uninit;
2619  case TOK_IDENT:
2620  return &Executor::ins_ident;
2621  case INS_ASSIGN_GLOBALVAR:
2623  case INS_ASSIGN_LOCALVAR:
2625  case INS_ASSIGN_CONSUME:
2627  case TOK_CONSUMER:
2628  return &Executor::ins_consume;
2629  case TOK_ASSIGN:
2630  return &Executor::ins_assign;
2631  case INS_SUBSCRIPT_ASSIGN:
2635  case INS_MULTISUBSCRIPT:
2639  case INS_GET_MEMBER:
2640  return &Executor::ins_get_member;
2641  case INS_SET_MEMBER:
2642  return &Executor::ins_set_member;
2645 
2646  case INS_GET_MEMBER_ID:
2647  return &Executor::ins_get_member_id; // test id
2648  case INS_SET_MEMBER_ID:
2649  return &Executor::ins_set_member_id; // test id
2651  return &Executor::ins_set_member_id_consume; // test id
2652 
2663 
2664  case TOK_ADD:
2665  return &Executor::ins_add;
2666  case TOK_SUBTRACT:
2667  return &Executor::ins_subtract;
2668  case TOK_DIV:
2669  return &Executor::ins_div;
2670  case TOK_MULT:
2671  return &Executor::ins_mult;
2672  case TOK_MODULUS:
2673  return &Executor::ins_modulus;
2674 
2675  case TOK_INSERTINTO:
2676  return &Executor::ins_insert_into;
2677 
2678  case TOK_PLUSEQUAL:
2679  return &Executor::ins_plusequal;
2680  case TOK_MINUSEQUAL:
2681  return &Executor::ins_minusequal;
2682  case TOK_TIMESEQUAL:
2683  return &Executor::ins_timesequal;
2684  case TOK_DIVIDEEQUAL:
2685  return &Executor::ins_divideequal;
2686  case TOK_MODULUSEQUAL:
2688 
2689  case TOK_LESSTHAN:
2690  return &Executor::ins_lessthan;
2691  case TOK_LESSEQ:
2692  return &Executor::ins_lessequal;
2693  case RSV_GOTO:
2694  return &Executor::ins_goto;
2695  case TOK_ARRAY_SUBSCRIPT:
2697  case TOK_EQUAL:
2698  return &Executor::ins_equal;
2699  case TOK_FUNC:
2700  return &Executor::ins_func;
2701  case INS_CALL_METHOD:
2702  return &Executor::ins_call_method;
2703  case INS_CALL_METHOD_ID:
2705  case CTRL_STATEMENTBEGIN:
2707  case CTRL_MAKELOCAL:
2708  return &Executor::ins_makelocal;
2709  case CTRL_JSR_USERFUNC:
2711  case INS_POP_PARAM:
2712  return &Executor::ins_pop_param;
2713  case INS_POP_PARAM_BYREF:
2715  case INS_GET_ARG:
2716  return &Executor::ins_get_arg;
2717  case CTRL_LEAVE_BLOCK:
2718  return &Executor::ins_leave_block;
2719  case RSV_GOSUB:
2720  return &Executor::ins_gosub;
2721  case RSV_RETURN:
2722  return &Executor::ins_return;
2723  case RSV_EXIT:
2724  return &Executor::ins_exit;
2725  case INS_DECLARE_ARRAY:
2727  case TOK_UNMINUS:
2728  return &Executor::ins_unminus;
2729  case TOK_UNPLUS:
2730  return &Executor::ins_nop;
2731  case TOK_LOG_NOT:
2732  return &Executor::ins_logical_not;
2733  case TOK_BITWISE_NOT:
2734  return &Executor::ins_bitwise_not;
2735  case TOK_BSRIGHT:
2737  case TOK_BSLEFT:
2739  case TOK_BITAND:
2740  return &Executor::ins_bitwise_and;
2741  case TOK_BITXOR:
2742  return &Executor::ins_bitwise_xor;
2743  case TOK_BITOR:
2744  return &Executor::ins_bitwise_or;
2745 
2746  case TOK_NEQ:
2747  return &Executor::ins_notequal;
2748  case TOK_GRTHAN:
2749  return &Executor::ins_greaterthan;
2750  case TOK_GREQ:
2752  case TOK_AND:
2753  return &Executor::ins_logical_and;
2754  case TOK_OR:
2755  return &Executor::ins_logical_or;
2756 
2757  case TOK_ADDMEMBER:
2758  return &Executor::ins_addmember;
2759  case TOK_DELMEMBER:
2761  case TOK_CHKMEMBER:
2762  return &Executor::ins_checkmember;
2765  case TOK_IN:
2766  return &Executor::ins_in;
2767  case INS_ADDMEMBER2:
2768  return &Executor::ins_addmember2;
2769  case INS_ADDMEMBER_ASSIGN:
2771  case CTRL_PROGEND:
2772  return &Executor::ins_progend;
2773 
2774  default:
2775  throw std::runtime_error( "Undefined execution token " + Clib::tostring( token.id ) );
2776  }
2777 }
2778 
2780 {
2781  unsigned onPC = PC;
2782  try
2783  { // this is really more of a class invariant.
2784  passert( run_ok_ );
2785  passert( PC < nLines );
2786  passert( !error_ );
2787  passert( !done );
2788 
2789 #ifdef NDEBUG
2790  const Instruction& ins = prog_->instr[PC];
2791 #else
2792  const Instruction& ins = prog_->instr.at( PC );
2793 #endif
2794  if ( debug_level >= INSTRUCTIONS )
2795  INFO_PRINT << PC << ": " << ins.token << "\n";
2796 
2797  if ( debugging_ )
2798  {
2799  if ( debug_state_ == DEBUG_STATE_ATTACHING )
2800  {
2801  debug_state_ = DEBUG_STATE_ATTACHED;
2802  sethalt( true );
2803  return;
2804  }
2805  else if ( debug_state_ == DEBUG_STATE_INS_TRACE )
2806  {
2807  // let this instruction through.
2808  debug_state_ = DEBUG_STATE_ATTACHED;
2809  sethalt( true );
2810  // but let this instruction execute.
2811  }
2812  else if ( debug_state_ == DEBUG_STATE_STEP_INTO )
2813  {
2814  debug_state_ = DEBUG_STATE_STEPPING_INTO;
2815  // let this instruction execute.
2816  }
2817  else if ( debug_state_ == DEBUG_STATE_STEPPING_INTO )
2818  {
2819  if ( prog_->dbg_ins_statementbegin.size() > PC && prog_->dbg_ins_statementbegin[PC] )
2820  {
2821  tmpbreakpoints_.insert( PC );
2822  // and let breakpoint processing catch it below.
2823  }
2824  }
2825  else if ( debug_state_ == DEBUG_STATE_STEP_OVER )
2826  {
2827  unsigned breakPC = PC + 1;
2828  while ( prog_->dbg_ins_statementbegin.size() > breakPC )
2829  {
2830  if ( prog_->dbg_ins_statementbegin[breakPC] )
2831  {
2832  tmpbreakpoints_.insert( breakPC );
2833  debug_state_ = DEBUG_STATE_RUN;
2834  break;
2835  }
2836  else
2837  {
2838  ++breakPC;
2839  }
2840  }
2841  }
2842  else if ( debug_state_ == DEBUG_STATE_RUN )
2843  {
2844  // do nothing
2845  }
2846  else if ( debug_state_ == DEBUG_STATE_BREAK_INTO )
2847  {
2848  debug_state_ = DEBUG_STATE_ATTACHED;
2849  sethalt( true );
2850  return;
2851  }
2852 
2853  // check for breakpoints on this instruction
2854  if ( ( breakpoints_.count( PC ) || tmpbreakpoints_.count( PC ) ) && bp_skip_ != PC &&
2855  !halt() )
2856  {
2857  tmpbreakpoints_.erase( PC );
2858  bp_skip_ = PC;
2859  debug_state_ = DEBUG_STATE_ATTACHED;
2860  sethalt( true );
2861  return;
2862  }
2863  bp_skip_ = ~0u;
2864  }
2865 
2866  ++ins.cycles;
2867  ++prog_->instr_cycles;
2869 
2870  ++PC;
2871 
2872  ( this->*( ins.func ) )( ins );
2873  }
2874  catch ( std::exception& ex )
2875  {
2876  fmt::Writer tmp;
2877  tmp << "Exception in: " << prog_->name.get() << " PC=" << onPC << ": " << ex.what() << "\n";
2878  if ( !run_ok_ )
2879  tmp << "run_ok_ = false\n";
2880  if ( PC < nLines )
2881  {
2882  tmp << " PC < nLines: (" << PC << " < " << nLines << ") \n";
2883  }
2884  if ( error_ )
2885  tmp << "error_ = true\n";
2886  if ( done )
2887  tmp << "done = true\n";
2888 
2889  seterror( true );
2890  POLLOG_ERROR << tmp.str();
2891 
2892  show_context( onPC );
2893  }
2894 #ifdef __unix__
2895  catch ( ... )
2896  {
2897  seterror( true );
2898  POLLOG_ERROR << "Exception in " << prog_->name.get() << ", PC=" << onPC << ": unclassified\n";
2899 
2900  show_context( onPC );
2901  }
2902 #endif
2903 }
2904 
2905 std::string Executor::dbg_get_instruction( size_t atPC ) const
2906 {
2907  fmt::Writer os;
2908  os << ( ( atPC == PC ) ? ">" : " " ) << atPC
2909  << ( breakpoints_.count( static_cast<unsigned>( atPC ) ) ? "*" : ":" ) << " "
2910  << prog_->instr[atPC].token;
2911  return os.str();
2912 }
2913 
2914 void Executor::show_context( unsigned atPC )
2915 {
2916  unsigned start, end;
2917  if ( atPC >= 5 )
2918  start = atPC - 5;
2919  else
2920  start = 0;
2921 
2922  end = atPC + 5;
2923 
2924  if ( end >= nLines )
2925  end = nLines - 1;
2926 
2927  for ( unsigned i = start; i <= end; ++i )
2928  {
2929  POLLOG.Format( "{}: {}\n" ) << i << dbg_get_instruction( i );
2930  }
2931 }
2932 void Executor::show_context( fmt::Writer& os, unsigned atPC )
2933 {
2934  unsigned start, end;
2935  if ( atPC >= 5 )
2936  start = atPC - 5;
2937  else
2938  start = 0;
2939 
2940  end = atPC + 5;
2941 
2942  if ( end >= nLines )
2943  end = nLines - 1;
2944 
2945  for ( unsigned i = start; i <= end; ++i )
2946  {
2947  os << dbg_get_instruction( i ) << '\n';
2948  }
2949 }
2950 
2952 {
2953  passert( prog_ok_ );
2954  passert( !error_ );
2955 
2956  Clib::scripts_thread_script = scriptname();
2957 
2958  set_running_to_completion( true );
2959  while ( runnable() )
2960  {
2962  execInstr();
2963  }
2964 
2965  return !error_;
2966 }
2967 
2969 {
2970  PC = 0;
2971  done = 0;
2972  seterror( false );
2973 
2974  while ( !ValueStack.empty() )
2975  ValueStack.pop_back();
2976 
2977  delete Locals2;
2978  Locals2 = new BObjectRefVec;
2979 
2980  if ( !prog_ok_ )
2981  {
2982  seterror( true );
2983  }
2984 }
2985 
2986 void Executor::initForFnCall( unsigned in_PC )
2987 {
2988 #ifdef MEMORYLEAK
2989  bool data_shown = false;
2990 #endif
2991 
2992  PC = in_PC;
2993  done = 0;
2994  seterror( false );
2995 
2996 #ifdef MEMORYLEAK
2997  while ( !ValueStack.empty() )
2998  {
2999  if ( Clib::memoryleak_debug )
3000  {
3001  if ( !data_shown )
3002  {
3003  LEAKLOG << "ValueStack... ";
3004  data_shown = true;
3005  }
3006 
3007  LEAKLOG << ValueStack.back()->impptr()->pack();
3008  LEAKLOG << " [" << ValueStack.back()->impptr()->sizeEstimate() << "] ";
3009  }
3010  ValueStack.pop_back();
3011  }
3012  if ( Clib::memoryleak_debug )
3013  if ( data_shown )
3014  LEAKLOG << " ...deleted\n";
3015 #endif
3016 
3017  ValueStack.clear();
3018  Locals2->clear();
3019 }
3020 
3022 {
3023  passert_always( arg );
3024  ValueStack.push_back( BObjectRef( arg ) );
3025 }
3026 
3027 void Executor::pushArg( const BObjectRef& arg )
3028 {
3029  ValueStack.push_back( arg );
3030 }
3031 
3033 {
3034  availmodules.push_back( module );
3035 }
3036 
3037 
3039 {
3040  unsigned idx;
3041  for ( idx = 0; idx < availmodules.size(); idx++ )
3042  {
3043  ExecutorModule* module = availmodules[idx];
3044  if ( stricmp( module->moduleName.get().c_str(), name.c_str() ) == 0 )
3045  return module;
3046  }
3047  return NULL;
3048 }
3049 
3051 {
3052  setdebugging( true );
3053  debug_state_ = DEBUG_STATE_ATTACHING;
3054 }
3056 {
3057  setdebugging( false );
3058  debug_state_ = DEBUG_STATE_NONE;
3059  sethalt( false );
3060 }
3062 {
3063  debug_state_ = DEBUG_STATE_INS_TRACE;
3064  sethalt( false );
3065 }
3067 {
3068  debug_state_ = DEBUG_STATE_STEP_INTO;
3069  sethalt( false );
3070 }
3072 {
3073  debug_state_ = DEBUG_STATE_STEP_OVER;
3074  sethalt( false );
3075 }
3077 {
3078  debug_state_ = DEBUG_STATE_RUN;
3079  sethalt( false );
3080 }
3082 {
3083  debug_state_ = DEBUG_STATE_BREAK_INTO;
3084 }
3085 
3086 void Executor::dbg_setbp( unsigned atPC )
3087 {
3088  breakpoints_.insert( atPC );
3089 }
3090 void Executor::dbg_clrbp( unsigned atPC )
3091 {
3092  breakpoints_.erase( atPC );
3093 }
3095 {
3096  breakpoints_.clear();
3097 }
3098 
3100 {
3101  size_t size = sizeof( *this );
3102  size += 3 * sizeof( BObjectRefVec** ) + upperLocals2.size() * sizeof( BObjectRefVec* );
3103  for ( const auto& bojectrefvec : upperLocals2 )
3104  {
3105  size += 3 * sizeof( BObjectRef* ) + bojectrefvec->capacity() * sizeof( BObjectRef );
3106  for ( const auto& bojectref : *bojectrefvec )
3107  {
3108  if ( bojectref != nullptr )
3109  size += bojectref->sizeEstimate();
3110  }
3111  }
3112  size += 3 * sizeof( ReturnContext* ) + ControlStack.size() * sizeof( ReturnContext );
3113 
3114  size += 3 * sizeof( BObjectRef* ) + Locals2->size() * sizeof( BObjectRef );
3115  for ( const auto& bojectref : *Locals2 )
3116  {
3117  if ( bojectref != nullptr )
3118  size += bojectref->sizeEstimate();
3119  }
3120  size += 3 * sizeof( BObjectRef* ) + Globals2.size() * sizeof( BObjectRef );
3121  for ( const auto& bojectref : Globals2 )
3122  {
3123  if ( bojectref != nullptr )
3124  size += bojectref->sizeEstimate();
3125  }
3126  size += 3 * sizeof( BObjectRef* ) + ValueStack.size() * sizeof( BObjectRef );
3127  for ( const auto& bojectref : ValueStack )
3128  {
3129  if ( bojectref != nullptr )
3130  size += bojectref->sizeEstimate();
3131  }
3132  size += 3 * sizeof( BObjectRef* ) + fparams.capacity() * sizeof( BObjectRef );
3133  for ( const auto& bojectref : fparams )
3134  {
3135  if ( bojectref != nullptr )
3136  size += bojectref->sizeEstimate();
3137  }
3138  size += 3 * sizeof( ExecutorModule** ) + execmodules.capacity() * sizeof( ExecutorModule* );
3139  size += 3 * sizeof( ExecutorModule** ) + availmodules.capacity() * sizeof( ExecutorModule* );
3140  size += 3 * sizeof( unsigned* ) + breakpoints_.size() * sizeof( unsigned );
3141  size += 3 * sizeof( unsigned* ) + tmpbreakpoints_.size() * sizeof( unsigned );
3142  size += func_result_ != nullptr ? func_result_->sizeEstimate() : 0;
3143  return size;
3144 }
3145 
3146 
3147 #ifdef ESCRIPT_PROFILE
3148 void Executor::profile_escript( std::string name, unsigned long profile_start )
3149 {
3150  unsigned long profile_end = GetTimeUs() - profile_start;
3151  escript_profile_map::iterator itr = EscriptProfileMap.find( name );
3152  if ( itr != EscriptProfileMap.end() )
3153  {
3154  itr->second.count++;
3155  itr->second.sum += profile_end;
3156  if ( itr->second.max < profile_end )
3157  itr->second.max = profile_end;
3158  else if ( itr->second.min > profile_end )
3159  itr->second.min = profile_end;
3160  }
3161  else
3162  {
3163  profile_instr profInstr;
3164  profInstr.count = 1;
3165  profInstr.max = profile_end;
3166  profInstr.min = profile_end;
3167  profInstr.sum = profile_end;
3168  EscriptProfileMap[name] = profInstr;
3169  }
3170 }
3171 #ifdef _WIN32
3172 
3173 unsigned long Executor::GetTimeUs()
3174 {
3175  static bool bInitialized = false;
3176  static LARGE_INTEGER lFreq, lStart;
3177  static LARGE_INTEGER lDivisor;
3178  if ( !bInitialized )
3179  {
3180  bInitialized = true;
3181  QueryPerformanceFrequency( &lFreq );
3182  QueryPerformanceCounter( &lStart );
3183  lDivisor.QuadPart = lFreq.QuadPart / 1000000;
3184  }
3185 
3186  LARGE_INTEGER lEnd;
3187  QueryPerformanceCounter( &lEnd );
3188  double duration = double( lEnd.QuadPart - lStart.QuadPart ) / lFreq.QuadPart;
3189  duration *= 1000000;
3190  LONGLONG llDuration = static_cast<LONGLONG>( duration );
3191  return llDuration & 0xffffffff;
3192 }
3193 #else
3194 unsigned long Executor::GetTimeUs()
3195 {
3196  static bool bInitialized = false;
3197  static timeval t1;
3198  if ( !bInitialized )
3199  {
3200  bInitialized = true;
3201  gettimeofday( &t1, NULL );
3202  }
3203 
3204  timeval t2;
3205  gettimeofday( &t2, NULL );
3206 
3207  double elapsedTime;
3208  elapsedTime = ( t2.tv_sec - t1.tv_sec ) * 1000000.0;
3209  elapsedTime += ( t2.tv_usec - t1.tv_usec );
3210 
3211  long long llDuration = static_cast<long long>( elapsedTime );
3212  return llDuration & 0xffffffff;
3213 }
3214 #endif
3215 #endif
3216 }
3217 }
virtual BObjectImp * selfBitShiftRightObjImp(const BObjectImp &objimp) const
Definition: object.cpp:606
double increment()
Definition: bobject.h:715
BObjectRef getObjRef(void)
Definition: executor.cpp:782
void ins_modulusequal(const Instruction &ins)
Definition: executor.cpp:2229
void ins_exit(const Instruction &ins)
Definition: executor.cpp:2503
void setFunctionResult(BObjectImp *imp)
Definition: executor.cpp:374
void ins_globalvar(const Instruction &ins)
Definition: executor.cpp:1273
void ins_in(const Instruction &ins)
Definition: executor.cpp:2132
virtual BObjectRef get_member(const char *membername)
Definition: object.cpp:930
void ins_set_member(const Instruction &ins)
Definition: executor.cpp:1290
void ins_error(const Instruction &ins)
Definition: executor.cpp:2517
void ins_logical_not(const Instruction &ins)
Definition: executor.cpp:2553
void ins_dictionary(const Instruction &ins)
Definition: executor.cpp:2529
int makeDouble(unsigned param)
Definition: executor.cpp:218
#define POL_OVERRIDE
BObjectImp * func_result_
Definition: executor.h:402
const std::string & value() const
Definition: impstr.h:67
void ins_multisubscript_assign(const Instruction &ins)
Definition: executor.cpp:1991
BObject * clone() const
Definition: object.cpp:129
virtual ContIterator * createIterator(BObject *pIterVal) POL_OVERRIDE
Definition: executor.cpp:1007
void ins_string(const Instruction &ins)
Definition: executor.cpp:2513
BObjectType type() const
Definition: bobject.h:358
int value() const
Definition: bobject.h:592
void ins_unminus(const Instruction &ins)
Definition: executor.cpp:2543
BObjectImp * copy(void) const
Definition: executor.cpp:951
void ins_jsr_userfunc(const Instruction &ins)
Definition: executor.cpp:2409
void ins_set_member_id_consume_modulusequal(const Instruction &ins)
Definition: executor.cpp:1441
void delete_all(T &coll)
Definition: stlutil.h:24
void ins_divideequal(const Instruction &ins)
Definition: executor.cpp:2212
ValueStackCont ValueStack
Definition: executor.h:120
void set(BObject *obj)
Definition: bobject.h:456
BTokenType type
Definition: token.h:40
virtual BObjectImp * selfBitAndObjImp(const BObjectImp &objimp) const
Definition: object.cpp:704
BObjectImp * getParamImp2(unsigned param, BObjectImp::BObjectType type)
Definition: executor.cpp:321
void ins_progend(const Instruction &ins)
Definition: executor.cpp:2392
size_t sizeEstimate() const
Definition: executor.cpp:955
void ins_uninit(const Instruction &ins)
Definition: executor.cpp:2533
std::string scripts_thread_script
Definition: passert.cpp:36
bool isa(BObjectType type) const
Definition: bobject.h:353
virtual BObjectImp * selfBitOrObjImp(const BObjectImp &objimp) const
Definition: object.cpp:753
void ins_nop(const Instruction &ins)
Definition: executor.cpp:2574
void ins_get_member(const Instruction &ins)
Definition: executor.cpp:1464
void ins_array_assign_consume(const Instruction &ins)
Definition: executor.cpp:1621
void ins_initforeach(const Instruction &ins)
Definition: executor.cpp:1021
void seterror(bool err)
Definition: executor.h:437
int getToken(Token &token, unsigned position)
Definition: executor.cpp:722
void ins_jmpiffalse(const Instruction &ins)
Definition: executor.cpp:1254
const char * tokval() const
Definition: token.h:71
virtual long contains(const BObjectImp &objimp) const
Definition: object.cpp:946
void ins_equal(const Instruction &ins)
Definition: executor.cpp:1876
void addModule(ExecutorModule *module)
Definition: executor.cpp:3032
void ins_notequal(const Instruction &ins)
Definition: executor.cpp:1858
void ins_set_member_id_consume_timesequal(const Instruction &ins)
Definition: executor.cpp:1395
virtual int functionIndex(const std::string &funcname)=0
void execFunc(const Token &token)
Definition: executor.cpp:797
T * get() const
Definition: refptr.h:176
BTokenId id
Definition: token.h:39
void ins_modulus(const Instruction &ins)
Definition: executor.cpp:1721
void ins_lessequal(const Instruction &ins)
Definition: executor.cpp:1912
std::string decint(unsigned short v)
Definition: strutil.cpp:64
#define IS_DEBUGLOG_DISABLED
Definition: logfacility.h:259
void ins_add(const Instruction &ins)
Definition: executor.cpp:1651
std::vector< BObjectRef > BObjectRefVec
Definition: exectype.h:21
void ins_set_member_id_consume_divideequal(const Instruction &ins)
Definition: executor.cpp:1418
void ins_pop_param(const Instruction &ins)
Definition: executor.cpp:2433
void ins_addmember_assign(const Instruction &ins)
Definition: executor.cpp:2067
static int ins_casejmp_finddefault(const Token &token)
Definition: executor.cpp:1199
EScriptConfig escript_config
int makeString(unsigned param)
Definition: executor.cpp:196
void ins_bitshift_right(const Instruction &ins)
Definition: executor.cpp:1738
void ins_func(const Instruction &ins)
Definition: executor.cpp:2253
void ins_set_member_id_consume_minusequal(const Instruction &ins)
Definition: executor.cpp:1372
void ins_div(const Instruction &ins)
Definition: executor.cpp:1704
virtual BObjectImp * copy() const =0
BObjectRef & GlobalVar(unsigned int varnum)
Definition: executor.cpp:716
void ins_return(const Instruction &ins)
Definition: executor.cpp:2477
virtual void operInsertInto(BObject &obj, const BObjectImp &objimp)
Definition: object.cpp:856
const BLong * getLongParam(unsigned param)
Definition: executor.cpp:352
#define POLLOG_ERROR
Definition: logfacility.h:207
bool isa(BObjectImp::BObjectType type) const
Definition: bobject.h:423
std::vector< ExecutorModule * > execmodules
Definition: executor.h:208
ArrayIterator(ObjArray *pArr, BObject *pIterVal)
Definition: executor.cpp:977
void ins_logical_and(const Instruction &ins)
Definition: executor.cpp:1823
int paramAsLong(unsigned param)
Definition: executor.cpp:240
void ins_lessthan(const Instruction &ins)
Definition: executor.cpp:1894
virtual void operModulusEqual(BObject &obj, BObjectImp &objimp)
Definition: object.cpp:886
void ins_initfor(const Instruction &ins)
Definition: executor.cpp:1101
const char * paramAsString(unsigned param)
Definition: executor.cpp:209
void(Executor::* ExecInstrFunc)(const Instruction &)
Definition: executortype.h:16
static int ins_casejmp_findlong(const Token &token, BLong *blong)
Definition: executor.cpp:1141
#define EXPLICIT_CAST(totype, fromtype)
Definition: clib.h:24
std::string getStringRep() const
Definition: executor.cpp:959
virtual BObjectRef operDotPlus(const char *name)
Definition: object.cpp:951
void ins_checkmember(const Instruction &ins)
Definition: executor.cpp:2041
void ins_call_method(const Instruction &ins)
Definition: executor.cpp:2322
#define passert_r(exp, reason)
Definition: passert.h:66
void ins_goto(const Instruction &ins)
Definition: executor.cpp:2247
void ins_initforeach2(const Instruction &ins)
Definition: executor.cpp:1059
void ins_assign_localvar(const Instruction &ins)
Definition: executor.cpp:1504
const BApplicObjType * object_type() const
Definition: bobject.h:897
virtual void operDivideEqual(BObject &obj, BObjectImp &objimp)
Definition: object.cpp:880
BObject * getParamObj(unsigned param)
Definition: executor.cpp:276
boost_utils::function_name_flystring name
Definition: fmodule.h:27
void ins_ident(const Instruction &ins)
Definition: executor.cpp:2537
std::string dbg_get_instruction(size_t atPC) const
Definition: executor.cpp:2905
void ins_funcref(const Instruction &ins)
Definition: executor.cpp:2568
virtual BObjectImp * selfBitShiftLeftObjImp(const BObjectImp &objimp) const
Definition: object.cpp:655
void pushArg(BObjectImp *arg)
Definition: executor.cpp:3021
void * ptr() const
Definition: object.cpp:1854
virtual BObject * step() POL_OVERRIDE
Definition: executor.cpp:987
#define LEAKLOG
Definition: logfacility.h:241
void ins_dictionary_addmember(const Instruction &ins)
Definition: executor.cpp:2092
void ins_bitwise_xor(const Instruction &ins)
Definition: executor.cpp:1789
static BObjectRef addmember(BObject &left, const BObject &right)
Definition: executor.cpp:909
void setimp(BObjectImp *imp)
Definition: bobject.h:446
BObjectRefVec Globals2
Definition: executor.h:109
void ins_greaterthan(const Instruction &ins)
Definition: executor.cpp:1928
#define DEBUGLOG
Definition: logfacility.h:237
void ins_arraysubscript(const Instruction &ins)
Definition: executor.cpp:1964
void ins_pop_param_byref(const Instruction &ins)
Definition: executor.cpp:2438
virtual BObjectRef get_member_id(const int id)
Definition: object.cpp:934
virtual BObjectRef set_member(const char *membername, BObjectImp *valueimp, bool copy)
Definition: object.cpp:926
u64 escript_instr_cycles
Definition: escriptv.cpp:22
virtual BObjectImp * execFunc(unsigned idx)=0
static BObjectRef checkmember(BObject &left, const BObject &right)
Definition: executor.cpp:933
const BApplicObjType * pointer_type() const
Definition: object.cpp:1849
void ins_get_arg(const Instruction &ins)
Definition: executor.cpp:2443
void ins_bitshift_left(const Instruction &ins)
Definition: executor.cpp:1755
virtual void operPlusEqual(BObject &obj, BObjectImp &objimp)
Definition: object.cpp:862
ExecutorModule * findModule(const std::string &name)
Definition: executor.cpp:3038
std::vector< BObjectRef > fparams
Definition: executor.h:133
std::vector< BObjectRefVec * > upperLocals2
Definition: executor.h:111
virtual ContIterator * createIterator(BObject *pIterVal)
Definition: executor.cpp:1003
std::string tostring(const Bscript::BTokenType &v)
Definition: tokens.cpp:19
bool AttachFunctionalityModules()
Definition: executor.cpp:123
static BObjectRef removemember(BObject &left, const BObject &right)
Definition: executor.cpp:921
bool setProgram(EScriptProgram *prog)
Definition: executor.cpp:731
static UninitObject * create()
Definition: bobject.h:482
void ins_minusequal(const Instruction &ins)
Definition: executor.cpp:2178
void ins_bitwise_and(const Instruction &ins)
Definition: executor.cpp:1772
void ins_set_member_id(const Instruction &ins)
Definition: executor.cpp:1304
void ins_logical_or(const Instruction &ins)
Definition: executor.cpp:1840
#define passert(exp)
Definition: passert.h:62
virtual void operMinusEqual(BObject &obj, BObjectImp &objimp)
Definition: object.cpp:868
boost_utils::function_name_flystring moduleName
Definition: execmodl.h:78
virtual BObject * step()
Definition: executor.cpp:947
bool getRealParam(unsigned param, double &value)
Definition: executor.cpp:433
#define POLLOG
Definition: logfacility.h:219
void ins_timesequal(const Instruction &ins)
Definition: executor.cpp:2195
void ins_stepforeach(const Instruction &ins)
Definition: executor.cpp:1037
virtual BObjectRef set_member_id(const int id, BObjectImp *valueimp, bool copy)
Definition: object.cpp:940
int getParams(unsigned howMany)
Definition: executor.cpp:171
ref_ptr< EScriptProgram > prog_
Definition: executor.h:376
void addMember(const char *name, BObjectRef val)
Definition: dict.cpp:232
void popParamByRef(const Token &token)
Definition: executor.cpp:886
void ins_localvar(const Instruction &ins)
Definition: executor.cpp:1266
void ins_addmember(const Instruction &ins)
Definition: executor.cpp:2007
void ins_array(const Instruction &ins)
Definition: executor.cpp:2525
static int ins_casejmp_findstring(const Token &token, String *bstringimp)
Definition: executor.cpp:1169
BObjectImp * impptr()
Definition: bobject.h:428
void ins_struct(const Instruction &ins)
Definition: executor.cpp:2521
void ins_subtract(const Instruction &ins)
Definition: executor.cpp:1669
std::vector< ModuleFunction * > functions
Definition: fmodule.h:43
unsigned int max_call_depth
Definition: config.h:15
virtual std::string functionName(unsigned idx)=0
void ins_stepforeach2(const Instruction &ins)
Definition: executor.cpp:1079
void ins_mult(const Instruction &ins)
Definition: executor.cpp:1687
void ins_declareArray(const Instruction &ins)
Definition: executor.cpp:860
void ins_double(const Instruction &ins)
Definition: executor.cpp:2509
unsigned int count() const
Definition: refptr.h:130
const unsigned char * dataptr
Definition: token.h:50
std::set< Executor * > executor_instances
Definition: executor.cpp:55
void ins_leave_block(const Instruction &ins)
Definition: executor.cpp:2449
virtual BObjectImp * selfMinusObjImp(const BObjectImp &objimp) const
Definition: object.cpp:410
void dbg_setbp(unsigned atPC)
Definition: executor.cpp:3086
virtual BObjectRef operDotQMark(const char *name)
Definition: object.cpp:961
void ins_nextfor(const Instruction &ins)
Definition: executor.cpp:1115
BObjectImp & impref()
Definition: bobject.h:438
void * getApplicPtrParam(unsigned param, const BApplicObjType *pointer_type)
Definition: executor.cpp:464
void ins_assign(const Instruction &ins)
Definition: executor.cpp:1568
void popParam(const Token &token)
Definition: executor.cpp:878
BApplicObjBase * getApplicObjParam(unsigned param, const BApplicObjType *object_type)
Definition: executor.cpp:488
const std::string & scriptname() const
Definition: executor.h:413
const String * getStringParam(unsigned param)
Definition: executor.cpp:347
virtual BObjectImp * selfTimesObjImp(const BObjectImp &objimp) const
Definition: object.cpp:459
void dbg_clrbp(unsigned atPC)
Definition: executor.cpp:3090
bool isTrue() const
Definition: bobject.h:384
D explicit_cast(const S &s)
Definition: stlutil.h:40
void ins_assign_globalvar(const Instruction &ins)
Definition: executor.cpp:1524
void ins_set_member_id_consume(const Instruction &ins)
Definition: executor.cpp:1333
void ins_bitwise_or(const Instruction &ins)
Definition: executor.cpp:1806
void ins_makelocal(const Instruction &ins)
Definition: executor.cpp:2401
std::string name
Definition: osmod.cpp:943
void ins_removemember(const Instruction &ins)
Definition: executor.cpp:2024
static ref_ptr< BObjectImp > SharedInstanceOwner
Definition: bobject.h:468
void ins_set_member_id_consume_plusequal(const Instruction &ins)
Definition: executor.cpp:1349
void ins_makeLocal(const Instruction &ins)
Definition: executor.cpp:849
unsigned char module
Definition: token.h:55
virtual BObjectImp * selfModulusObjImp(const BObjectImp &objimp) const
Definition: object.cpp:557
void ins_get_member_id(const Instruction &ins)
Definition: executor.cpp:1484
void ins_call_method_id(const Instruction &ins)
Definition: executor.cpp:2262
#define ERROR_PRINT
Definition: logfacility.h:230
double paramAsDouble(unsigned param)
Definition: executor.cpp:231
virtual std::string getStringRep() const POL_OVERRIDE
Definition: object.cpp:1870
virtual BObjectImp * selfBitXorObjImp(const BObjectImp &objimp) const
Definition: object.cpp:802
BObject * makeObj(const Token &token)
Definition: executor.cpp:757
BObjectRefVec * Locals2
Definition: executor.h:115
void ins_jmpiftrue(const Instruction &ins)
Definition: executor.cpp:1244
void ins_bitwise_not(const Instruction &ins)
Definition: executor.cpp:2561
double value() const
Definition: bobject.h:713
void ins_plusequal(const Instruction &ins)
Definition: executor.cpp:2161
unsigned int cycles
Definition: eprog.h:41
void getArg(const Token &token)
Definition: executor.cpp:893
void ins_greaterequal(const Instruction &ins)
Definition: executor.cpp:1945
#define passert_always(exp)
Definition: passert.h:80
#define INFO_PRINT
Definition: logfacility.h:223
void show_context(unsigned atPC)
Definition: executor.cpp:2914
void ins_statementbegin(const Instruction &ins)
Definition: executor.cpp:2385
void ins_insert_into(const Instruction &ins)
Definition: executor.cpp:2149
void ins_gosub(const Instruction &ins)
Definition: executor.cpp:2463
void ins_addmember2(const Instruction &ins)
Definition: executor.cpp:2058
static Clib::SpinLock _executor_lock
Definition: executor.h:84
std::lock_guard< SpinLock > SpinLockGuard
Definition: spinlock.h:33
void initForFnCall(unsigned in_PC)
Definition: executor.cpp:2986
virtual BObjectRef operDotMinus(const char *name)
Definition: object.cpp:956
virtual size_t sizeEstimate() const
Definition: executor.cpp:3099
void ins_array_assign(const Instruction &ins)
Definition: executor.cpp:1594
virtual BObjectImp * array_assign(BObjectImp *idx, BObjectImp *target, bool copy)
Definition: object.cpp:328
bool getObjArrayParam(unsigned param, ObjArray *&pobjarr)
Definition: executor.cpp:457
virtual BObjectImp * selfDividedByObjImp(const BObjectImp &objimp) const
Definition: object.cpp:508
int executor_count
Definition: escriptv.cpp:18
void ins_multisubscript(const Instruction &ins)
Definition: executor.cpp:1978
void ins_long(const Instruction &ins)
Definition: executor.cpp:1279
const char * data() const
Definition: impstr.h:66
void ins_set_member_consume(const Instruction &ins)
Definition: executor.cpp:1318
Definition: berror.cpp:12
BObjectRef & LocalVar(unsigned int varnum)
Definition: executor.cpp:708
void ins_casejmp(const Instruction &ins)
Definition: executor.cpp:1224
static ExecInstrFunc GetInstrFunc(const Token &token)
Definition: executor.cpp:2576
void ins_consume(const Instruction &ins)
Definition: executor.cpp:1285
void ins_assign_consume(const Instruction &ins)
Definition: executor.cpp:1546
static const char * typestr(BObjectType typ)
Definition: object.cpp:218
static UninitObject * SharedInstance
Definition: bobject.h:467
virtual void operTimesEqual(BObject &obj, BObjectImp &objimp)
Definition: object.cpp:874
BObjectImp * getParamImp(unsigned param)
Definition: executor.cpp:266
virtual BObjectImp * selfPlusObjImp(const BObjectImp &objimp) const
Definition: object.cpp:361
ModuleFunction * current_module_function
Definition: executor.h:218
ExecInstrFunc func
Definition: eprog.h:40
unsigned scripts_thread_scriptPC
Definition: passert.cpp:37
bool getParam(unsigned param, int &value)
Definition: executor.cpp:363
void display_executor_instances()
Definition: executor.cpp:61
std::vector< ExecutorModule * > availmodules
Definition: executor.h:209