• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

polserver / polserver / 26709257347

31 May 2026 09:45AM UTC coverage: 60.926% (+0.005%) from 60.921%
26709257347

push

github

web-flow
Funcrefs do not detect pid change (#889)

* test for sending a function to the same program

* store executor pid inside funcrefs and classes

* docs

18 of 19 new or added lines in 4 files covered. (94.74%)

2 existing lines in 1 file now uncovered.

44645 of 73278 relevant lines covered (60.93%)

507692.25 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

78.23
/pol-core/bscript/bclassinstance.cpp
1
#include "bclassinstance.h"
2

3
#include "berror.h"
4
#include "bobject.h"
5
#include "clib/clib.h"
6
#include "clib/stlutil.h"
7
#include "executor.h"
8
#include "objmembers.h"
9
#include "objmethods.h"
10

11
namespace Pol::Bscript
12
{
13
BClassInstance::BClassInstance( ref_ptr<EScriptProgram> program, int index,
402✔
14
                                std::weak_ptr<ValueStackCont> globals, unsigned int pid )
402✔
15
    : BStruct( OTClassInstance ),
16
      prog_( std::move( program ) ),
402✔
17
      index_( index ),
402✔
18
      pid_( pid ),
402✔
19
      globals( std::move( globals ) )
804✔
20
{
21
  passert( index_ < prog_->class_descriptors.size() );
402✔
22
}
402✔
23

24
BClassInstance::BClassInstance( const BClassInstance& B ) : BStruct( B, OTClassInstance )
×
25
{
26
  prog_ = B.prog_;
×
27
  index_ = B.index_;
×
NEW
28
  pid_ = B.pid_;
×
29
  globals = B.globals;
×
30
}
×
31

32
size_t BClassInstance::sizeEstimate() const
145✔
33
{
34
  return base::sizeEstimate() + Clib::memsize( constructors_called ) +
145✔
35
         sizeof( ref_ptr<EScriptProgram> ) + 2 * sizeof( unsigned int ) +
36
         sizeof( std::weak_ptr<ValueStackCont> );
145✔
37
}
38

39
ref_ptr<EScriptProgram> BClassInstance::prog() const
239✔
40
{
41
  return prog_;
239✔
42
}
43

44
unsigned BClassInstance::index() const
753✔
45
{
46
  return index_;
753✔
47
}
48

49
BFunctionRef* BClassInstance::makeMethod( const char* method_name )
191✔
50
{
51
  const auto& methods = prog_->class_descriptors[index_].methods;
191✔
52
  auto method_itr =
53
      std::find_if( methods.begin(), methods.end(),
191✔
54
                    [&]( const auto& it )
411✔
55
                    {
56
                      if ( it.first < prog_->symbols.length() )
411✔
57
                      {
58
                        return stricmp( method_name, prog_->symbols.array() + it.first ) == 0;
411✔
59
                      }
60
                      return false;
×
61
                    } );
62

63
  if ( method_itr == methods.end() )
191✔
64
    return nullptr;
6✔
65

66
  return new BFunctionRef( prog_, pid_, method_itr->second.function_reference_index, globals,
185✔
67
                           ValueStackCont{} );
370✔
68
}
69

70
const char* BClassInstance::typetag() const
6✔
71
{
72
  // Return the class name as the type tag.
73
  return prog_->symbols.array() + prog_->class_descriptors[index_].name_offset;
6✔
74
}
75

76
const char* BClassInstance::typeOf() const
×
77
{
78
  return "Class";
×
79
}
80

81
u8 BClassInstance::typeOfInt() const
×
82
{
83
  return OTClassInstance;
×
84
}
85

86
BObjectImp* BClassInstance::copy() const
×
87
{
88
  passert_always_r( false, "BClassInstance::copy() should never be called" );
×
89
  return nullptr;
90
}
91

92
bool BClassInstance::isTrue() const
×
93
{
94
  return true;
×
95
}
96

97
BObjectImp* BClassInstance::call_method( const char* method_name, Executor& ex )
668✔
98
{
99
  BFunctionRef* funcr = nullptr;
668✔
100

101
  BObjectImp* callee{ nullptr };
668✔
102
  // Prefer members over class methods by checking contents first.
103
  auto member_itr = contents().find( method_name );
668✔
104

105
  if ( member_itr != contents().end() )
668✔
106
  {
107
    // If the member exists and is NOT a function reference, we will still try
108
    // to "call" it. This is _intentional_, and will result in a runtime
109
    // BError. This is similar to `var foo := 3; print(foo.bar());`, resulting
110
    // in a "Method 'bar' not found" error.
111
    callee = member_itr->second.get()->impptr();
9✔
112

113
    funcr = member_itr->second.get()->impptr_if<BFunctionRef>();
9✔
114
  }
115
  else
116
  {
117
    // Have we already looked up this method?
118
    Executor::ClassMethodKey key{ ex.prog_, index(), method_name };
659✔
119
    auto cache_itr = ex.class_methods.find( key );
659✔
120
    if ( cache_itr != ex.class_methods.end() )
659✔
121
    {
122
      // Switch the callee to the function reference: if the
123
      // funcr->validCall fails, we will go into the funcref
124
      // ins_call_method, giving the error about invalid parameter counts.
125
      funcr = cache_itr->second->impptr_if<BFunctionRef>();
468✔
126
      callee = funcr;
468✔
127
      method_name = getObjMethod( MTH_CALL_METHOD )->code;
468✔
128
    }
129
    else
130
    {
131
      // Does the class define this method?
132
      funcr = makeMethod( method_name );
191✔
133

134
      if ( funcr != nullptr )
191✔
135
      {
136
        // Cache the method for future lookups
137
        ex.class_methods[key] = BObjectRef( funcr );
185✔
138

139
        // Switch the callee to the function reference.
140
        callee = funcr;
185✔
141
        method_name = getObjMethod( MTH_CALL_METHOD )->code;
185✔
142
      }
143
    }
144
  }
659✔
145

146
  if ( funcr != nullptr )
668✔
147
  {
148
    Instruction jmp;
659✔
149
    int id;
150

151
    // Add `this` to the front of the argument list only for class methods,
152
    // skipping eg. an instance member function reference set via
153
    // `this.foo := @(){};`.
154
    if ( funcr->class_method() )
659✔
155
    {
156
      id = MTH_CALL_METHOD;
653✔
157
      ex.fparams.insert( ex.fparams.begin(), ex.ValueStack.back() );
653✔
158
    }
159
    else
160
    {
161
      id = MTH_CALL;
6✔
162
    }
163

164
    if ( funcr->validCall( id, ex, &jmp ) )
659✔
165
    {
166
      BObjectRef funcobj( funcr );  // valuestack gets modified, protect BFunctionRef
638✔
167
      ex.call_function_reference( funcr, nullptr, jmp );
638✔
168
      return BSpecialUserFuncJump::get();
638✔
169
    }
638✔
170
  }
659✔
171
  if ( callee )
30✔
172
    return callee->call_method( method_name, ex );
24✔
173
  return new BError( fmt::format( "Method '{}' not found in class '{}'", method_name, typetag() ) );
12✔
174
}
175

176
BObjectImp* BClassInstance::call_method_id( const int id, Executor& ex, bool /*forcebuiltin*/ )
3✔
177
{
178
  auto method = getObjMethod( id );
3✔
179
  return call_method( method->code, ex );
3✔
180
}
181

182
BObjectRef BClassInstance::get_member_id( const int id )
120✔
183
{
184
  if ( id == MBR_FUNCTION )
120✔
185
  {
186
    const auto funcref_index =
187
        prog_->class_descriptors.at( index_ ).constructor_function_reference_index;
18✔
188

189
    return BObjectRef( new BFunctionRef( prog_, pid_, funcref_index, globals, ValueStackCont{} ) );
36✔
190
  }
191

192
  return base::get_member_id( id );
102✔
193
}
194

195
std::string BClassInstance::getStringRep() const
327✔
196
{
197
  auto class_name = prog_->symbols.array() + prog_->class_descriptors[index_].name_offset;
327✔
198
  return fmt::format( "<class {}>", class_name );
654✔
199
}
200

201
BClassInstanceRef::BClassInstanceRef( BClassInstance* inst )
772✔
202
    : BObjectImp( BObjectType::OTClassInstanceRef ), class_instance_( inst )
772✔
203
{
204
}
772✔
205

206
size_t BClassInstanceRef::sizeEstimate() const
145✔
207
{
208
  return sizeof( BClassInstanceRef ) + class_instance_->sizeEstimate();
145✔
209
}
210

211
const char* BClassInstanceRef::typeOf() const
3✔
212
{
213
  return "ClassInstanceRef";
3✔
214
}
215

216
u8 BClassInstanceRef::typeOfInt() const
6✔
217
{
218
  return OTClassInstanceRef;
6✔
219
}
220

221
BObjectImp* BClassInstanceRef::copy() const
370✔
222
{
223
  return new BClassInstanceRef( class_instance_.get() );
370✔
224
}
225

226
bool BClassInstanceRef::isTrue() const
×
227
{
228
  return true;
×
229
}
230

231
BObjectImp* BClassInstanceRef::call_method( const char* methodname, Executor& ex )
665✔
232
{
233
  return class_instance_->call_method( methodname, ex );
665✔
234
}
235

236
BObjectImp* BClassInstanceRef::call_method_id( const int id, Executor& ex, bool forcebuiltin )
3✔
237
{
238
  return class_instance_->call_method_id( id, ex, forcebuiltin );
3✔
239
}
240

241
BObjectRef BClassInstanceRef::get_member_id( const int id )
120✔
242
{
243
  return class_instance_->get_member_id( id );
120✔
244
}
245

246
std::string BClassInstanceRef::getStringRep() const
327✔
247
{
248
  return class_instance_->getStringRep();
327✔
249
}
250

251
ContIterator* BClassInstanceRef::createIterator( BObject* pIterVal )
6✔
252
{
253
  return class_instance_->createIterator( pIterVal );
6✔
254
}
255

256
BObjectRef BClassInstanceRef::OperSubscript( const BObject& obj )
×
257
{
258
  return class_instance_->OperSubscript( obj );
×
259
}
260

261
BObjectRef BClassInstanceRef::set_member( const char* membername, BObjectImp* value, bool copy )
401✔
262
{
263
  return class_instance_->set_member( membername, value, copy );
401✔
264
}
265

266
BObjectRef BClassInstanceRef::get_member( const char* membername )
1,507✔
267
{
268
  return class_instance_->get_member( membername );
1,507✔
269
}
270

271
BObjectRef BClassInstanceRef::operDotPlus( const char* name )
×
272
{
273
  return class_instance_->operDotPlus( name );
×
274
}
275

276
BObjectRef BClassInstanceRef::operDotMinus( const char* name )
×
277
{
278
  return class_instance_->operDotMinus( name );
×
279
}
280

281
BObjectRef BClassInstanceRef::operDotQMark( const char* name )
×
282
{
283
  return class_instance_->operDotQMark( name );
×
284
}
285

286
BObjectImp* BClassInstanceRef::array_assign( BObjectImp* idx, BObjectImp* target, bool copy )
×
287
{
288
  return class_instance_->array_assign( idx, target, copy );
×
289
}
290
}  // namespace Pol::Bscript
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc