Coverage Report

Created: 2026-05-30 06:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/sources/xsDebug.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2026  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Runtime.
5
 * 
6
 *   The Moddable SDK Runtime is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU Lesser General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Runtime is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU Lesser General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU Lesser General Public License
17
 *   along with the Moddable SDK Runtime.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 * This file incorporates work covered by the following copyright and  
20
 * permission notice:  
21
 *
22
 *       Copyright (C) 2010-2016 Marvell International Ltd.
23
 *       Copyright (C) 2002-2010 Kinoma, Inc.
24
 *
25
 *       Licensed under the Apache License, Version 2.0 (the "License");
26
 *       you may not use this file except in compliance with the License.
27
 *       You may obtain a copy of the License at
28
 *
29
 *        http://www.apache.org/licenses/LICENSE-2.0
30
 *
31
 *       Unless required by applicable law or agreed to in writing, software
32
 *       distributed under the License is distributed on an "AS IS" BASIS,
33
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34
 *       See the License for the specific language governing permissions and
35
 *       limitations under the License.
36
 */
37
38
#include "xsAll.h"
39
40
#if MODDEF_XS_TEST
41
  #undef MODDEF_XS_XSBUG_HOOKS
42
  #define MODDEF_XS_XSBUG_HOOKS 1
43
#endif
44
45
#if defined(DEBUG_EFM)
46
char _lastDebugStrBuffer[256];
47
char _debugStrBuffer[256];
48
#endif
49
static void fxVReportException(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments);
50
51
#if defined(mxInstrument) || defined (mxDebug)  
52
static const char gxHexaDigits[] ICACHE_FLASH_ATTR = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
53
#endif
54
55
#ifdef mxDebug
56
static void fxClearAllBreakpoints(txMachine* the);
57
static void fxClearBreakpoint(txMachine* the, txString thePath, txInteger theLine, size_t theID);
58
static void fxDebugEval(txMachine* the, txSlot* frame, txString buffer, txInteger index);
59
static txU1* fxDebugEvalAtom(txMachine* the, txU1* p, Atom* atom, txString t);
60
static void fxDebugEvalBuffer(txMachine* the, txString buffer, txSlot* expression);
61
static txBoolean fxDebugEvalExpression(txMachine* the, txSlot* frame, txSlot* expression, txSlot* result);
62
static void fxDebugParse(txMachine* the);
63
static void fxDebugParseTag(txMachine* the, txString name);
64
static void fxDebugPopTag(txMachine* the);
65
static void fxDebugPushTag(txMachine* the);
66
static void fxDebugScriptCDATA(txMachine* the, char c);
67
static void fxEcho(txMachine* the, txString theString);
68
static void fxEchoAddress(txMachine* the, txSlot* theSlot);
69
static void fxEchoArrayBuffer(txMachine* the, txSlot* theInstance, txInspectorNameList* theList);
70
static void fxEchoBigInt(txMachine* the, txBigInt* bigint);
71
static void fxEchoCharacter(txMachine* the, char theCharacter);
72
static void fxEchoException(txMachine* the, txSlot* exception);
73
static void fxEchoFlags(txMachine* the, txString state, txFlag flag);
74
static void fxEchoFormat(txMachine* the, txString theFormat, c_va_list theArguments);
75
static void fxEchoFrameName(txMachine* the, txSlot* theFrame);
76
static void fxEchoFramePathLine(txMachine* the, txSlot* theFrame);
77
static void fxEchoInteger(txMachine* the, txInteger theInteger);
78
static void fxEchoInstance(txMachine* the, txSlot* theInstance, txInspectorNameList* theList);
79
static void fxEchoModule(txMachine* the, txSlot* module, txInspectorNameList* list);
80
static void fxEchoNumber(txMachine* the, txNumber theNumber);
81
static void fxEchoPathLine(txMachine* the, txString thePath, txInteger theLine);
82
static void fxEchoProperty(txMachine* the, txSlot* theProperty, txInspectorNameList* theList, txString thePrefix, txIndex theIndex, txString theSuffix);
83
static void fxEchoPropertyHost(txMachine* the, txInspectorNameList* theList, txSlot* theInstance, txSlot* theHost);
84
static void fxEchoPropertyInstance(txMachine* the, txInspectorNameList* theList, txString thePrefix, txIndex theIndex, txString theSuffix, txID theID, txFlag theFlag, txSlot* theInstance);
85
static void fxEchoPropertyName(txMachine* the, txString thePrefix, txIndex theIndex, txString theSuffix, txID theID);
86
static void fxEchoStart(txMachine* the);
87
static void fxEchoStop(txMachine* the);
88
static void fxEchoString(txMachine* the, txString theString);
89
static void fxEchoTypedArray(txMachine* the, txSlot* theInstance, txInspectorNameList* theList);
90
static txSlot* fxFindFrame(txMachine* the);
91
static txSlot* fxFindRealm(txMachine* the);
92
static void fxGo(txMachine* the);
93
static void fxIndexToString(txMachine* the, txIndex theIndex, txString theBuffer, txSize theSize);
94
static void fxListFrames(txMachine* the);
95
static void fxListGlobal(txMachine* the);
96
static void fxListLocal(txMachine* the);
97
static void fxListModules(txMachine* the);
98
static void fxSetBreakpoint(txMachine* the, txString thePath, txInteger theLine, size_t theID);
99
static void fxSetBreakpointCondition(txMachine* the, txSlot* reference, txString it);
100
static void fxSetBreakpointHitCount(txMachine* the, txSlot* reference, txString it);
101
static void fxSetBreakpointTrace(txMachine* the, txSlot* reference, txString it);
102
static void fxSelect(txMachine* the, txSlot* slot);
103
static void fxStep(txMachine* the);
104
static void fxStepInside(txMachine* the);
105
static void fxStepOutside(txMachine* the);
106
static txSlot* fxToInstanceInspector(txMachine* the, txSlot* instance);
107
static void fxToggle(txMachine* the, txSlot* slot);
108
static void fxReportException(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...);
109
110
#define mxIsDigit(c) \
111
  (('0' <= c) && (c <= '9'))
112
#define mxIsFirstLetter(c) \
113
0
  ((('A' <= c) && (c <= 'Z')) || (('a' <= c) && (c <= 'z')) || (c == '_') || (c == ':'))
114
#define mxIsNextLetter(c) \
115
0
  ((('0' <= c) && (c <= '9')) || (('A' <= c) && (c <= 'Z')) || (('a' <= c) && (c <= 'z')) || (c == '.') || (c == '-') || (c == '_') || (c == ':'))
116
#define mxIsSpace(c) \
117
0
  ((c == ' ') || (c == '\n') || (c == '\r') || (c == '\t'))
118
  
119
enum {
120
  XS_BODY_STATE = 0,
121
  XS_CR_STATE,
122
  XS_LF_STATE,
123
  XS_TAG_STATE,
124
  XS_START_TAG_NAME_STATE,
125
  XS_START_TAG_SPACE_STATE,
126
  XS_ATTRIBUTE_NAME_STATE,
127
  XS_ATTRIBUTE_SPACE_STATE,
128
  XS_ATTRIBUTE_EQUAL_STATE,
129
  XS_ATTRIBUTE_VALUE_STATE,
130
  XS_EMPTY_TAG_STATE,
131
  XS_END_TAG_STATE,
132
  XS_END_TAG_NAME_STATE,
133
  XS_END_TAG_SPACE_STATE,
134
  XS_PROCESSING_INSTRUCTION_STATE,
135
  XS_PROCESSING_INSTRUCTION_SPACE_STATE,
136
  XS_START_CDATA_STATE_1,
137
  XS_START_CDATA_STATE_2,
138
  XS_START_CDATA_STATE_3,
139
  XS_START_CDATA_STATE_4,
140
  XS_START_CDATA_STATE_5,
141
  XS_START_CDATA_STATE_6,
142
  XS_START_CDATA_STATE_7,
143
  XS_CDATA_STATE,
144
  XS_END_CDATA_STATE_1,
145
  XS_END_CDATA_STATE_2,
146
  XS_END_CDATA_STATE_3,
147
  XS_ERROR_STATE
148
};
149
150
enum {
151
  XS_ABORT_TAG = 0,
152
  XS_BREAKPOINT_TAG,
153
  XS_BREAKPOINT_CONDITION_TAG,
154
  XS_BREAKPOINT_HIT_COUNT_TAG,
155
  XS_BREAKPOINT_TRACE_TAG,
156
  XS_CLEAR_ALL_BREAKPOINTS_TAG,
157
  XS_CLEAR_BREAKPOINTS_TAG,
158
  XS_EVAL_TAG,
159
  XS_GO_TAG,
160
  XS_IMPORT_TAG,
161
  XS_LOGOUT_TAG,
162
  XS_MODULE_TAG,
163
  XS_SCRIPT_TAG,
164
  XS_SET_BREAKPOINT_TAG,
165
  XS_SET_ALL_BREAKPOINTS_TAG,
166
  XS_SELECT_TAG,
167
  XS_STEP_TAG,
168
  XS_STEP_INSIDE_TAG,
169
  XS_STEP_OUTSIDE_TAG,
170
  XS_TOGGLE_TAG,
171
  XS_START_PROFILING_TAG,
172
  XS_STOP_PROFILING_TAG,
173
  XS_UNKNOWN_TAG
174
};
175
176
enum {
177
  XS_ID_ATTRIBUTE = 0,
178
  XS_LINE_ATTRIBUTE,
179
  XS_PATH_ATTRIBUTE,
180
  XS_UNKNOWN_ATTRIBUTE
181
};
182
183
void fxCheck(txMachine* the, txString thePath, txInteger theLine)
184
0
{
185
#if mxWindows
186
  printf("%s(%ld): fatal!\n", thePath, (int)theLine);
187
#else
188
0
  c_printf("%s:%d: fatal!\n", thePath, (int)theLine);
189
0
#endif
190
0
  fxAbort(the, XS_FATAL_CHECK_EXIT);
191
0
}
192
193
void fxClearAllBreakpoints(txMachine* the)
194
0
{
195
0
  mxBreakpoints.value.list.first = C_NULL;
196
0
}
197
198
void fxClearBreakpoint(txMachine* the, txString thePath, txInteger theLine, size_t theID)
199
0
{
200
0
  txID path;
201
0
  txSlot** breakpointAddress;
202
0
  txSlot* breakpoint;
203
204
0
  if (!thePath)
205
0
    return;
206
0
  if ((theID == 0) && (theLine == 0)) { 
207
0
    if (!c_strcmp(thePath, "exceptions")) {
208
0
      the->breakOnExceptionsFlag = 0;
209
0
      return;
210
0
    }  
211
0
    if (!c_strcmp(thePath, "start")) {
212
0
      the->breakOnStartFlag = 0;
213
0
      return;
214
0
    }  
215
0
  }
216
0
  path = fxFindName(the, thePath);
217
0
  if (!path)
218
0
    return;
219
0
  breakpointAddress = &(mxBreakpoints.value.list.first);
220
0
  while ((breakpoint = *breakpointAddress)) {
221
0
    if ((breakpoint->ID == path) && (breakpoint->value.breakpoint.line == theLine)) {
222
0
      *breakpointAddress = breakpoint->next;
223
0
      break;
224
0
    }
225
0
    breakpointAddress = &(breakpoint->next);
226
0
  }
227
0
}
228
229
void fxDebugCommand(txMachine* the)
230
0
{
231
0
  the->debugExit = 0;
232
0
  the->debugModule = C_NULL;
233
0
  while (fxIsConnected(the)) {
234
0
    fxReceive(the);
235
0
    fxDebugParse(the);
236
0
    if ((the->debugState == XS_LF_STATE) && (the->debugExit > 0))
237
0
      break;
238
0
  }
239
0
  mxHostInspectors.value.list.first = C_NULL;
240
0
  mxHostInspectors.value.list.last = C_NULL;
241
#if MODDEF_XS_XSBUG_HOOKS
242
  if (the->debugTag == XS_IMPORT_TAG)
243
    fxQueueJob(the, 2, C_NULL);
244
  else if (the->debugTag == XS_SCRIPT_TAG)
245
    fxQueueJob(the, 6, C_NULL);
246
#endif
247
0
}
248
249
void fxDebugEval(txMachine* the, txSlot* frame, txString buffer, txInteger index)
250
0
{
251
0
  txSlot* result;
252
0
  txSlot* expression;
253
0
  mxHostInspectors.value.list.first = C_NULL;
254
0
  mxHostInspectors.value.list.last = C_NULL;
255
0
  mxTemporary(result);
256
0
  mxTemporary(expression);
257
0
  fxDebugEvalBuffer(the, buffer, expression);
258
0
  if (fxDebugEvalExpression(the, frame, expression, result)) {
259
0
    txInspectorNameList aList = { C_NULL, C_NULL };
260
0
    fxEchoStart(the);
261
0
    fxEcho(the, "<result line=\"");
262
0
    fxEchoInteger(the, index);
263
0
    fxEcho(the, "\">");
264
0
    if (result->kind == XS_REFERENCE_KIND) {
265
0
      txSlot* instance = result->value.reference;
266
0
      txSlot* instanceInspector = fxToInstanceInspector(the, instance);
267
0
      if (!instanceInspector)
268
0
        fxToggle(the, instance);
269
0
      fxEchoProperty(the, result, &aList, C_NULL, -1, C_NULL);
270
0
      if (!instanceInspector)
271
0
        fxToggle(the, instance);
272
0
    }
273
0
    else
274
0
      fxEchoProperty(the, result, &aList, C_NULL, -1, C_NULL);
275
0
    fxEcho(the, "</result>");
276
0
    fxListLocal(the);
277
0
    fxListGlobal(the);
278
0
    fxListModules(the);
279
0
    fxEchoStop(the);
280
0
  }
281
0
  else {
282
0
    fxEchoStart(the);
283
0
    fxEcho(the, "<result line=\"");
284
0
    fxEchoInteger(the, index);
285
0
    fxEcho(the, "\"># ");
286
0
    fxEchoException(the, result);
287
0
    fxEcho(the, "</result>");
288
0
    fxListLocal(the);
289
0
    fxListGlobal(the);
290
0
    fxListModules(the);
291
0
    fxEchoStop(the);
292
0
  }
293
0
  mxPop();
294
0
  mxPop();
295
0
}
296
297
txU1* fxDebugEvalAtom(txMachine* the, txU1* p, Atom* atom, txString t)
298
0
{
299
0
  atom->atomSize = (p[0] << 24) + (p[1] << 16) + (p[2] << 8) + p[3];
300
0
  if ((t[0] != p[4]) || (t[1] != p[5]) || (t[2] != p[6]) || (t[3] != p[7]))
301
0
    mxUnknownError("invalid buffer");
302
0
  return p + 8;
303
0
}
304
305
void fxDebugEvalBuffer(txMachine* the, txString buffer, txSlot* expression)
306
0
{
307
0
  mxTry(the) {
308
0
    txU1* src = (txU1*)buffer;
309
0
    txU1* dst = src;
310
0
    Atom atom;
311
0
    txScript script;
312
0
    txSlot* instance;
313
0
    txSlot* code;
314
0
    txSlot* home;
315
0
    for (;;) {
316
0
      txU4 byte = 0;
317
0
      txU1 c = *src++;
318
0
      if (c == 0)
319
0
        break;
320
0
      if (!fxParseHex(c, &byte))
321
0
        mxUnknownError("invalid buffer");
322
0
      c = *src++;
323
0
      if (!fxParseHex(c, &byte))
324
0
        mxUnknownError("invalid buffer");
325
0
      *dst++ = (txU1)byte;
326
0
    }
327
0
    src = fxDebugEvalAtom(the, (txU1*)buffer, &atom, "XS_B");
328
0
    if (atom.atomSize != (txSize)(dst - (txU1*)buffer)) mxUnknownError("invalid buffer");
329
0
    src = fxDebugEvalAtom(the, src, &atom, "VERS");
330
0
    if (atom.atomSize != 12) mxUnknownError("invalid buffer");
331
0
    if (src[0] != XS_MAJOR_VERSION) mxUnknownError("invalid buffer");
332
0
    if (src[1] != XS_MINOR_VERSION) mxUnknownError("invalid buffer");
333
0
    src = fxDebugEvalAtom(the, src + 4, &atom, "SYMB");
334
0
    script.symbolsSize = atom.atomSize - sizeof(atom);
335
0
    script.symbolsBuffer = (txByte*)src;
336
0
    src = fxDebugEvalAtom(the, src + script.symbolsSize, &atom, "CODE");
337
0
    script.codeSize = atom.atomSize - sizeof(atom);
338
0
    script.codeBuffer = (txByte*)src;
339
0
    fxRemapScript(the, &script);
340
0
    mxPop();
341
0
    mxPush(mxFunctionPrototype);
342
0
    instance = fxNewFunctionInstance(the, XS_NO_ID);
343
0
    code = instance->next;
344
0
    code->value.code.address = fxNewChunk(the, script.codeSize);
345
0
    c_memcpy(code->value.code.address, script.codeBuffer, script.codeSize);
346
0
    code->kind = XS_CODE_KIND;
347
0
    home = mxFunctionInstanceHome(instance);
348
0
    home->ID = fxGenerateProfileID(the);
349
0
    mxPullSlot(expression);
350
0
  }
351
0
  mxCatch(the) {
352
0
    mxPush(mxException);
353
0
    mxException = mxUndefined;
354
0
    mxPullSlot(expression);
355
0
  }
356
0
}
357
358
txBoolean fxDebugEvalExpression(txMachine* the, txSlot* frame, txSlot* expression, txSlot* result)
359
0
{
360
0
  txBoolean success = 0;
361
0
  if (mxIsFunction(expression->value.reference)) {
362
0
    txSlot* scope = C_NULL;
363
0
    if (frame == the->frame)
364
0
      scope = the->scope;
365
0
    else {
366
0
      txSlot* current = the->frame;
367
0
      while (current->next != frame)
368
0
        current = current->next;
369
0
      if (current)
370
0
        scope = current->value.frame.scope;
371
0
      else
372
0
        scope = C_NULL;
373
0
    }
374
  
375
0
    txSlot* _this = frame + 3;
376
0
    txSlot* environment = mxFrameToEnvironment(frame);
377
0
    txSlot* function = frame + 2;
378
0
    txSlot* home = (function->kind == XS_REFERENCE_KIND) ? mxFunctionInstanceHome(function->value.reference) : C_NULL;
379
0
    txSlot* closures;
380
0
    txSlot* property;
381
382
0
    the->debugEval = 1;
383
384
0
    mxOverflow(-5);
385
    /* THIS */
386
0
    mxPushSlot(_this);
387
    /* FUNCTION */
388
0
    mxPushSlot(function);
389
    /* RESULT */
390
0
    mxPushUndefined();
391
    /* FRAME */
392
0
    (--the->stack)->next = the->frame;
393
0
    the->stack->ID = 0;
394
0
    the->stack->flag = XS_C_FLAG | (frame->flag & (XS_STRICT_FLAG | XS_FIELD_FLAG));
395
0
    the->stack->kind = XS_FRAME_KIND;
396
0
    the->stack->value.frame.code = the->code;
397
0
    the->stack->value.frame.scope = the->scope;
398
0
    the->frame = the->stack;
399
    /* ENVIRONMENT */
400
0
    mxPushUndefined();
401
0
    closures = fxNewEnvironmentInstance(the, C_NULL);
402
0
    if (scope) {
403
0
      txSlot* local = scope;
404
0
      txID id;
405
0
      property = closures->next;
406
0
      while (local < environment) {
407
0
        id = local->ID;
408
0
        if ((0 < id) && (id < the->keyCount)) {
409
0
          property = fxNextSlotProperty(the, property, local, id, local->flag);
410
0
        }
411
0
        local++;
412
0
      }
413
0
    }
414
0
    the->scope = the->stack;
415
0
    the->code = C_NULL;
416
        
417
0
    property = mxFunctionInstanceCode(expression->value.reference);
418
0
    property->value.code.closures = closures;
419
0
    property = mxFunctionInstanceHome(expression->value.reference);
420
0
    if (home) {
421
0
      property->value.home.object = home->value.home.object;
422
0
      property->value.home.module = home->value.home.module;
423
0
    }
424
0
    if (property->value.home.module == C_NULL)
425
0
      property->value.home.module = mxProgram.value.reference;
426
  
427
0
    {
428
0
      mxTry(the) {
429
        /* TARGET */
430
0
        if (frame->flag & XS_TARGET_FLAG)
431
0
          mxPushSlot(frame + 4);
432
        /* THIS */
433
0
        mxPushSlot(mxThis);
434
0
        the->stack->ID = XS_NO_ID;
435
        /* FUNCTION */
436
0
        mxPushSlot(expression);
437
        /* RESULT */
438
0
        mxPushUndefined();
439
        /* FRAME */
440
0
        mxPushUninitialized();
441
0
        if (frame->flag & XS_TARGET_FLAG)
442
0
          the->stack->flag |= XS_TARGET_FLAG;
443
0
        mxRunCount(0);
444
0
        mxPullSlot(result);
445
0
        success = 1;
446
0
      }
447
0
      mxCatch(the) {
448
0
        mxPush(mxException);
449
0
        mxException = mxUndefined;
450
0
        mxPullSlot(result);
451
0
      }
452
0
    }
453
  
454
0
    property = mxFunctionInstanceCode(expression->value.reference);
455
0
    property->value.code.closures = C_NULL;
456
0
    property = mxFunctionInstanceHome(expression->value.reference);
457
0
    property->value.home.object = C_NULL;
458
0
    property->value.home.module = C_NULL;
459
    
460
0
    if (scope) {
461
0
      txSlot* local = scope;
462
0
      txID id;
463
0
      property = closures->next->next;
464
0
      while (local < environment) {
465
0
        id = local->ID;
466
0
        if ((0 < id) && (id < the->keyCount)) {
467
0
          if (property->kind != XS_CLOSURE_KIND) {
468
0
            local->kind = property->kind;
469
0
            local->value = property->value;
470
0
          }
471
0
          property = property->next;
472
0
        }
473
0
        local++;
474
0
      }   
475
0
    }
476
  
477
0
    fxEndHost(the);
478
  
479
0
    the->debugEval = 0;
480
0
  }
481
0
  else {
482
0
    mxPushSlot(expression);
483
0
    mxPullSlot(result);
484
0
  }
485
0
  return success;
486
0
}
487
488
#if MODDEF_XS_XSBUG_HOOKS
489
void fxDebugImport(txMachine* the, txSlot* module, txString path)
490
{
491
  if (!fxIsConnected(the))
492
    return;
493
  fxEchoStart(the);
494
  fxEcho(the, "<import path=\"");
495
  fxEcho(the, path + 8);
496
  fxEcho(the, "\"/>");
497
  fxEchoStop(the);
498
  the->debugExit = 0;
499
  the->debugModule = module;
500
  while (fxIsConnected(the)) {
501
    fxReceive(the);
502
    fxDebugParse(the);
503
    if ((the->debugState == XS_LF_STATE) && (the->debugExit > 1))
504
      break;
505
  }
506
    if (the->debugTag == XS_MODULE_TAG){
507
        mxRunCount(6);
508
        mxPop();
509
    }
510
}
511
#endif
512
513
void fxDebugLine(txMachine* the, txID path, txInteger line, txID function)
514
0
{
515
0
  txSlot* breakpoint = C_NULL;
516
0
  breakpoint = mxBreakpoints.value.list.first;
517
0
  while (breakpoint) {
518
0
    if (breakpoint->value.breakpoint.line == line) {
519
0
      if (breakpoint->ID == path)
520
0
        break;
521
0
    }
522
0
    else if (breakpoint->value.breakpoint.line == 0) {
523
0
      if (breakpoint->ID == function)
524
0
        break;
525
0
    }
526
0
    breakpoint = breakpoint->next;
527
0
  }
528
0
  if (breakpoint) {
529
0
    txSlot* instance = breakpoint->value.breakpoint.info;
530
0
    if (instance) {
531
0
      txSlot* property = instance->next;
532
0
      if (!mxIsUndefined(property)) {
533
0
        txSlot* result;
534
0
        txBoolean skip = 1;
535
0
        mxTemporary(result);
536
0
        if (fxDebugEvalExpression(the, the->frame, property, result)) {
537
0
          mxPushSlot(result);
538
0
          skip = (fxRunTest(the)) ? 0 : 1;
539
0
        }
540
0
        else {
541
0
          fxEchoStart(the);
542
0
          fxEcho(the, "<log");
543
0
          fxEchoPathLine(the, fxGetKeyName(the, path), line);
544
0
          fxEcho(the, "># ");
545
0
          fxEchoException(the, result);
546
0
          fxEcho(the, "\n</log>");
547
0
          fxEchoStop(the);
548
0
        }
549
0
        mxPop();
550
0
        if (skip)
551
0
          breakpoint = C_NULL;
552
0
      }
553
0
      if (breakpoint) {
554
0
        property = property->next;
555
0
        if (!mxIsUndefined(property)) {
556
0
          txInteger offset = property->value.dataView.offset + 1;
557
0
          txInteger size = property->value.dataView.size;
558
0
          txBoolean skip = 1;
559
0
          switch (property->ID) {
560
0
          case XS_CODE_EQUAL: if (offset == size) skip = 0; break;
561
0
          case XS_CODE_LESS: if (offset < size) skip = 0; break;
562
0
          case XS_CODE_LESS_EQUAL: if (offset <= size) skip = 0; break;
563
0
          case XS_CODE_MODULO: if ((offset % size) == 0) skip = 0; break;
564
0
          case XS_CODE_MORE: if (offset > size) skip = 0; break;
565
0
          case XS_CODE_MORE_EQUAL: if (offset >= size) skip = 0; break;
566
0
          }
567
0
          property->value.dataView.offset = offset;
568
0
          if (skip)
569
0
            breakpoint = C_NULL;
570
0
        }
571
0
      }
572
0
      if (breakpoint) {
573
0
        property = property->next;
574
0
        if (!mxIsUndefined(property)) {
575
0
          txSlot* result;
576
0
          mxTemporary(result);
577
0
          if (fxDebugEvalExpression(the, the->frame, property, result)) {
578
0
            fxToString(the, result);
579
0
            fxEchoStart(the);
580
0
            fxEcho(the, "<log");
581
0
            fxEchoPathLine(the, fxGetKeyName(the, path), line);
582
0
            fxEcho(the, ">");
583
0
            fxEchoString(the, result->value.string);
584
0
            fxEcho(the, "\n</log>");
585
0
            fxEchoStop(the);
586
0
          }
587
0
          else {
588
0
            fxEchoStart(the);
589
0
            fxEcho(the, "<log");
590
0
            fxEchoPathLine(the, fxGetKeyName(the, path), line);
591
0
            fxEcho(the, "># ");
592
0
            fxEchoException(the, result);
593
0
            fxEcho(the, "\n</log>");
594
0
            fxEchoStop(the);
595
0
          }
596
0
          mxPop();
597
0
          breakpoint = C_NULL;
598
0
        }
599
0
      }
600
0
    }
601
0
  }
602
0
  if (breakpoint)
603
0
    fxDebugLoop(the, C_NULL, 0, "breakpoint");
604
0
  else if ((the->frame->flag & XS_STEP_OVER_FLAG))
605
0
    fxDebugLoop(the, C_NULL, 0, "step");
606
0
}
607
608
void fxDebugLoop(txMachine* the, txString path, txInteger line, txString message)
609
5.54k
{
610
5.54k
  txSlot* frame;
611
5.54k
  if (!fxIsConnected(the))
612
5.54k
    return;
613
614
#ifdef mxInstrument
615
  if (the->onBreak)
616
    (the->onBreak)(the, 1);
617
#endif
618
0
#if defined(mxInstrument) || defined(mxProfile)
619
0
  fxSuspendProfiler(the);
620
0
#endif
621
622
0
  fxEchoStart(the);
623
0
  frame = the->frame;
624
0
  do {
625
0
    frame->flag &= ~XS_DEBUG_FLAG;
626
0
    frame = frame->next;
627
0
  } while (frame);
628
0
  the->frame->flag |= XS_DEBUG_FLAG;
629
0
  fxListFrames(the);
630
0
  fxListLocal(the);
631
0
  fxListGlobal(the);
632
0
  fxListModules(the);
633
0
  fxEcho(the, "<break");
634
0
  frame = the->frame;
635
0
  while (frame && !path) {
636
0
    txSlot* environment = mxFrameToEnvironment(frame);
637
0
    if (environment->ID != XS_NO_ID) {
638
0
      path = fxGetKeyName(the, environment->ID);
639
0
      line = environment->value.environment.line;
640
0
    }
641
0
    frame = frame->next;
642
0
  }
643
0
  if (path)
644
0
    fxEchoPathLine(the, path, line);
645
0
  fxEcho(the, "># Break: ");
646
0
  if (!c_strcmp(message, "throw"))
647
0
    fxEchoException(the, &mxException);
648
0
  else
649
0
    fxEchoString(the, message);
650
0
  fxEcho(the, "!\n</break>");
651
0
  fxEchoStop(the);
652
653
0
  the->debugExit = 0;
654
0
  the->debugModule = C_NULL;
655
0
  while (fxIsConnected(the)) {
656
0
    fxReceive(the);
657
0
    fxDebugParse(the);
658
0
    if ((the->debugState == XS_LF_STATE) && (the->debugExit > 1))
659
0
      break;
660
0
  }
661
0
  mxHostInspectors.value.list.first = C_NULL;
662
0
  mxHostInspectors.value.list.last = C_NULL;
663
664
0
#if defined(mxInstrument) || defined(mxProfile)
665
0
  fxResumeProfiler(the);
666
0
#endif
667
#ifdef mxInstrument
668
  if (the->onBreak)
669
    (the->onBreak)(the, 0);
670
#endif
671
0
}
672
673
void fxDebugParse(txMachine* the)
674
0
{
675
0
  txString string = the->debugBuffer;
676
0
  txString limit = string + the->debugOffset;
677
0
  char c;
678
0
  while (string < limit) {
679
0
    c = *string++;
680
0
    switch (the->debugState) {
681
0
    case XS_BODY_STATE:
682
0
      if (c == '<') 
683
0
        the->debugState = XS_TAG_STATE;
684
0
      else if (c == '\r') 
685
0
        the->debugState = XS_CR_STATE;
686
0
      break;
687
      
688
0
    case XS_CR_STATE:
689
0
      if (c == '\n') 
690
0
        the->debugState = XS_LF_STATE;
691
0
      else
692
0
        the->debugState = XS_ERROR_STATE;
693
0
      break;
694
      
695
0
    case XS_LF_STATE:
696
0
      if (c == '<') 
697
0
        the->debugState = XS_TAG_STATE;
698
0
      else if (c == '\r') 
699
0
        the->debugState = XS_CR_STATE;
700
0
      break;
701
      
702
0
    case XS_TAG_STATE:
703
0
      if (c == '/')
704
0
        the->debugState = XS_END_TAG_STATE;
705
0
      else if (c == '!')
706
0
        the->debugState = XS_START_CDATA_STATE_1;
707
0
      else if (c == '?')
708
0
        the->debugState = XS_PROCESSING_INSTRUCTION_STATE;
709
0
      else if (mxIsFirstLetter(c)) {
710
0
        the->debugState = XS_START_TAG_NAME_STATE;
711
0
        the->nameBuffer[0] = c;
712
0
        the->nameIndex = 1;
713
0
      }
714
0
      else
715
0
        the->debugState = XS_ERROR_STATE;
716
0
      break;
717
0
    case XS_START_TAG_NAME_STATE:
718
0
      if (mxIsNextLetter(c)) {
719
0
        if (the->nameIndex < 255) {
720
0
          the->nameBuffer[the->nameIndex] = c;
721
0
          the->nameIndex++;
722
0
        }
723
0
        else
724
0
          the->debugState = XS_ERROR_STATE;
725
0
        break;
726
0
      }
727
0
      the->debugState = XS_START_TAG_SPACE_STATE;
728
0
      the->nameBuffer[the->nameIndex] = 0;
729
0
      fxDebugParseTag(the, the->nameBuffer);
730
      /* continue */
731
0
    case XS_START_TAG_SPACE_STATE:
732
0
      if (mxIsFirstLetter(c)) {
733
0
        the->debugState = XS_ATTRIBUTE_NAME_STATE;
734
0
        the->nameBuffer[0] = c;
735
0
        the->nameIndex = 1;
736
0
      }
737
0
      else if (c == '/')
738
0
        the->debugState = XS_EMPTY_TAG_STATE;
739
0
      else if (c == '>') {
740
0
        the->debugState = XS_BODY_STATE;
741
0
        fxDebugPushTag(the);
742
0
      }
743
0
      else if (!mxIsSpace(c))
744
0
        the->debugState = XS_ERROR_STATE;
745
0
      break;
746
      
747
0
    case XS_ATTRIBUTE_NAME_STATE:
748
0
      if (mxIsNextLetter(c)) {
749
0
        if (the->nameIndex < 255) {
750
0
          the->nameBuffer[the->nameIndex] = c;
751
0
          the->nameIndex++;
752
0
        }
753
0
        else
754
0
          the->debugState = XS_ERROR_STATE;
755
0
        break;
756
0
      }
757
0
      the->nameBuffer[the->nameIndex] = 0;
758
0
      if (!c_strcmp(the->nameBuffer, "path")) {
759
0
        the->debugAttribute = XS_PATH_ATTRIBUTE;
760
0
        the->pathIndex = 0;
761
0
      }
762
0
      else if (!c_strcmp(the->nameBuffer, "line")) {
763
0
        the->debugAttribute = XS_LINE_ATTRIBUTE;
764
0
        the->lineValue = 0;
765
0
      }
766
0
      else if (!c_strcmp(the->nameBuffer, "id")) {
767
0
        the->debugAttribute = XS_ID_ATTRIBUTE;
768
0
        the->idValue = 0;
769
0
      }
770
0
      else
771
0
        the->debugAttribute = XS_UNKNOWN_ATTRIBUTE;
772
      /* continue */
773
0
    case XS_ATTRIBUTE_SPACE_STATE:
774
0
      if (c == '=')
775
0
        the->debugState = XS_ATTRIBUTE_EQUAL_STATE;
776
0
      else if (!mxIsSpace(c))
777
0
        the->debugState = XS_ERROR_STATE;
778
0
      break;
779
0
    case XS_ATTRIBUTE_EQUAL_STATE:
780
0
      if (c == '"')
781
0
        the->debugState = XS_ATTRIBUTE_VALUE_STATE;
782
0
      else if (!mxIsSpace(c))
783
0
        the->debugState = XS_ERROR_STATE;
784
0
      break;
785
0
    case XS_ATTRIBUTE_VALUE_STATE:
786
0
      if (the->debugAttribute == XS_PATH_ATTRIBUTE) {
787
0
        if (the->pathIndex == the->pathCount) {
788
0
          the->pathCount += 256;
789
0
          the->pathValue = c_realloc(the->pathValue, the->pathCount);
790
0
          if (!the->pathValue)
791
0
            fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
792
0
        }
793
0
        if (c == '"') {
794
0
          the->debugState = XS_START_TAG_SPACE_STATE;
795
0
          the->pathValue[the->pathIndex] = 0;
796
0
        }
797
0
        else {
798
0
          the->pathValue[the->pathIndex] = c;
799
0
          the->pathIndex++;
800
0
        }
801
0
      }
802
0
      else if (the->debugAttribute == XS_LINE_ATTRIBUTE) {
803
0
        if (c == '"')
804
0
          the->debugState = XS_START_TAG_SPACE_STATE;
805
0
        else if (('0' <= c) && (c <= '9'))
806
0
          the->lineValue = (the->lineValue * 10) + (c - '0');
807
0
        else
808
0
          the->debugState = XS_ERROR_STATE;
809
0
      }
810
0
      else if (the->debugAttribute == XS_ID_ATTRIBUTE) {
811
0
        if (c == '"')
812
0
          the->debugState = XS_START_TAG_SPACE_STATE;
813
0
        else if (('0' <= c) && (c <= '9'))
814
0
          the->idValue = (the->idValue << 4) | (c - '0');
815
0
        else if (('A' <= c) && (c <= 'F'))
816
0
          the->idValue = (the->idValue << 4) | (c - 'A' + 10);
817
0
        else if ((c != '@') || (the->idValue != 0))
818
0
          the->debugState = XS_ERROR_STATE;
819
0
      }
820
0
      else {
821
0
        if (c == '"')
822
0
          the->debugState = XS_START_TAG_SPACE_STATE;
823
0
      }
824
0
      break;
825
      
826
0
    case XS_EMPTY_TAG_STATE:
827
0
      if (c == '>') {
828
0
        the->debugState = XS_BODY_STATE;
829
0
        fxDebugPushTag(the);
830
0
        fxDebugPopTag(the);
831
0
      }
832
0
      else
833
0
        the->debugState = XS_ERROR_STATE;
834
0
      break;
835
      
836
0
    case XS_END_TAG_STATE:
837
0
      if (mxIsFirstLetter(c))  {
838
0
        the->debugState = XS_END_TAG_NAME_STATE;
839
0
        the->nameBuffer[0] = c;
840
0
        the->nameIndex = 1;
841
0
      }
842
0
      else
843
0
        the->debugState = XS_ERROR_STATE;
844
0
      break;
845
0
    case XS_END_TAG_NAME_STATE:
846
0
      if (mxIsNextLetter(c)) {
847
0
        if (the->nameIndex < 255) {
848
0
          the->nameBuffer[the->nameIndex] = c;
849
0
          the->nameIndex++;
850
0
        }
851
0
        else 
852
0
          the->debugState = XS_ERROR_STATE;
853
0
        break;
854
0
      }
855
0
      the->nameBuffer[the->nameIndex] = 0;
856
0
      the->debugState = XS_END_TAG_SPACE_STATE;
857
0
      fxDebugParseTag(the, the->nameBuffer);
858
      /* continue */
859
0
    case XS_END_TAG_SPACE_STATE:
860
0
      if (c == '>') {
861
0
        the->debugState = XS_BODY_STATE;
862
0
        fxDebugPopTag(the);
863
0
      }
864
0
      else if (!mxIsSpace(c))
865
0
        the->debugState = XS_ERROR_STATE;
866
0
      break;
867
868
0
    case XS_PROCESSING_INSTRUCTION_STATE:
869
0
      if (c == '?')
870
0
        the->debugState = XS_PROCESSING_INSTRUCTION_SPACE_STATE;
871
0
      break;
872
0
    case XS_PROCESSING_INSTRUCTION_SPACE_STATE:
873
0
      if (c == '>')
874
0
        the->debugState = XS_BODY_STATE;
875
0
      else
876
0
        the->debugState = XS_ERROR_STATE;
877
0
      break;
878
      
879
0
    case XS_START_CDATA_STATE_1:
880
0
      if (c == '[') 
881
0
        the->debugState = XS_START_CDATA_STATE_2;
882
0
      else
883
0
        the->debugState = XS_ERROR_STATE;
884
0
      break;
885
0
    case XS_START_CDATA_STATE_2:
886
0
      if (c == 'C') 
887
0
        the->debugState = XS_START_CDATA_STATE_3;
888
0
      else
889
0
        the->debugState = XS_ERROR_STATE;
890
0
      break;
891
0
    case XS_START_CDATA_STATE_3:
892
0
      if (c == 'D') 
893
0
        the->debugState = XS_START_CDATA_STATE_4;
894
0
      else
895
0
        the->debugState = XS_ERROR_STATE;
896
0
      break;
897
0
    case XS_START_CDATA_STATE_4:
898
0
      if (c == 'A') 
899
0
        the->debugState = XS_START_CDATA_STATE_5;
900
0
      else
901
0
        the->debugState = XS_ERROR_STATE;
902
0
      break;
903
0
    case XS_START_CDATA_STATE_5:
904
0
      if (c == 'T') 
905
0
        the->debugState = XS_START_CDATA_STATE_6;
906
0
      else
907
0
        the->debugState = XS_ERROR_STATE;
908
0
      break;
909
0
    case XS_START_CDATA_STATE_6:
910
0
      if (c == 'A') 
911
0
        the->debugState = XS_START_CDATA_STATE_7;
912
0
      else
913
0
        the->debugState = XS_ERROR_STATE;
914
0
      break;
915
0
    case XS_START_CDATA_STATE_7:
916
0
      if (c == '[')
917
0
        the->debugState = XS_CDATA_STATE;
918
0
      else
919
0
        the->debugState = XS_ERROR_STATE;
920
0
      break;
921
0
    case XS_CDATA_STATE:
922
0
      if (c == ']') 
923
0
        the->debugState = XS_END_CDATA_STATE_1;
924
0
      else if (c == 0) {
925
0
        fxDebugScriptCDATA(the, 0xF4);
926
0
        fxDebugScriptCDATA(the, 0x90);
927
0
        fxDebugScriptCDATA(the, 0x80);
928
0
        fxDebugScriptCDATA(the, 0x80);
929
0
      }
930
0
      else
931
0
        fxDebugScriptCDATA(the, c);
932
0
      break;
933
0
    case XS_END_CDATA_STATE_1:
934
0
      if (c == ']') 
935
0
        the->debugState = XS_END_CDATA_STATE_2;
936
0
      else {
937
0
        fxDebugScriptCDATA(the, ']');
938
0
        fxDebugScriptCDATA(the, c);
939
0
        the->debugState = XS_CDATA_STATE;
940
0
      }
941
0
      break;
942
0
    case XS_END_CDATA_STATE_2:
943
0
      if (c == '>') {
944
0
        fxDebugScriptCDATA(the, 0);
945
0
        the->debugState = XS_BODY_STATE;
946
0
      }
947
0
      else {
948
0
        fxDebugScriptCDATA(the, ']');
949
0
        fxDebugScriptCDATA(the, ']');
950
0
        fxDebugScriptCDATA(the, c);
951
0
        the->debugState = XS_CDATA_STATE;
952
0
      }
953
0
      break;
954
      
955
0
    case XS_ERROR_STATE:
956
//      fprintf(stderr, "\nERROR: %c\n", c);
957
0
      break;
958
0
    }
959
0
  }
960
0
  the->debugOffset = 0;
961
0
}
962
963
void fxDebugParseTag(txMachine* the, txString name)
964
0
{
965
0
  if (!c_strcmp(name, "abort"))
966
0
    the->debugTag = XS_ABORT_TAG;
967
0
  else if (!c_strcmp(name, "breakpoint")) {
968
0
    the->debugTag = XS_BREAKPOINT_TAG;
969
0
    the->idValue = 0;
970
0
  }
971
0
  else if (!c_strcmp(name, "breakpoint-condition"))
972
0
    the->debugTag = XS_BREAKPOINT_CONDITION_TAG;
973
0
  else if (!c_strcmp(name, "breakpoint-hit-count"))
974
0
    the->debugTag = XS_BREAKPOINT_HIT_COUNT_TAG;
975
0
  else if (!c_strcmp(name, "breakpoint-trace"))
976
0
    the->debugTag = XS_BREAKPOINT_TRACE_TAG;
977
0
  else if (!c_strcmp(name, "clear-all-breakpoints"))
978
0
    the->debugTag = XS_CLEAR_ALL_BREAKPOINTS_TAG;
979
0
  else if (!c_strcmp(name, "clear-breakpoint"))
980
0
    the->debugTag = XS_CLEAR_BREAKPOINTS_TAG;
981
0
  else if (!c_strcmp(name, "eval"))
982
0
    the->debugTag = XS_EVAL_TAG;
983
0
  else if (!c_strcmp(name, "go"))
984
0
    the->debugTag = XS_GO_TAG;
985
0
  else if (!c_strcmp(name, "logout"))
986
0
    the->debugTag = XS_LOGOUT_TAG;
987
0
  else if (!c_strcmp(name, "select"))
988
0
    the->debugTag = XS_SELECT_TAG;
989
0
  else if (!c_strcmp(name, "set-all-breakpoints"))
990
0
    the->debugTag = XS_SET_ALL_BREAKPOINTS_TAG;
991
0
  else if (!c_strcmp(name, "set-breakpoint")) {
992
0
    the->debugTag = XS_SET_BREAKPOINT_TAG;
993
0
    the->idValue = 0;
994
0
  }
995
0
  else if (!c_strcmp(name, "start-profiling"))
996
0
    the->debugTag = XS_START_PROFILING_TAG;
997
0
  else if (!c_strcmp(name, "step"))
998
0
    the->debugTag = XS_STEP_TAG;
999
0
  else if (!c_strcmp(name, "step-inside"))
1000
0
    the->debugTag = XS_STEP_INSIDE_TAG;
1001
0
  else if (!c_strcmp(name, "step-outside"))
1002
0
    the->debugTag = XS_STEP_OUTSIDE_TAG;
1003
0
  else if (!c_strcmp(name, "stop-profiling"))
1004
0
    the->debugTag = XS_STOP_PROFILING_TAG;
1005
0
  else if (!c_strcmp(name, "toggle"))
1006
0
    the->debugTag = XS_TOGGLE_TAG;
1007
#if MODDEF_XS_XSBUG_HOOKS
1008
  else if (!c_strcmp(name, "import"))
1009
    the->debugTag = XS_IMPORT_TAG;
1010
  else if (!c_strcmp(name, "module"))
1011
    the->debugTag = XS_MODULE_TAG;
1012
  else if (!c_strcmp(name, "script"))
1013
    the->debugTag = XS_SCRIPT_TAG;
1014
#endif
1015
0
  else
1016
0
    the->debugTag = XS_UNKNOWN_TAG;
1017
0
}
1018
1019
void fxDebugPopTag(txMachine* the)
1020
0
{
1021
0
  switch (the->debugTag) {
1022
0
  case XS_ABORT_TAG:
1023
0
    the->debugExit |= 2;
1024
0
    break;
1025
0
  case XS_BREAKPOINT_TAG:
1026
0
    mxPop();
1027
0
    break;
1028
0
  case XS_BREAKPOINT_CONDITION_TAG:
1029
0
    break;
1030
0
  case XS_BREAKPOINT_HIT_COUNT_TAG:
1031
0
    break;
1032
0
  case XS_BREAKPOINT_TRACE_TAG:
1033
0
    break;
1034
0
  case XS_CLEAR_ALL_BREAKPOINTS_TAG:
1035
0
    the->debugExit |= 1;
1036
0
    break;
1037
0
  case XS_CLEAR_BREAKPOINTS_TAG:
1038
0
    the->debugExit |= 1;
1039
0
    break;
1040
0
  case XS_EVAL_TAG:
1041
0
    break;
1042
0
  case XS_GO_TAG:
1043
0
    the->debugExit |= 2;
1044
0
    break;
1045
0
  case XS_LOGOUT_TAG:
1046
0
    the->debugExit |= 2;
1047
0
    break;
1048
0
  case XS_SELECT_TAG:
1049
0
    break;
1050
0
  case XS_SET_ALL_BREAKPOINTS_TAG:
1051
0
    the->debugExit |= 1;
1052
0
    break;
1053
0
  case XS_SET_BREAKPOINT_TAG:
1054
0
    mxPop();
1055
0
    the->debugExit |= 1;
1056
0
    break;
1057
0
  case XS_START_PROFILING_TAG:
1058
0
    the->debugExit |= 1;
1059
0
    break;
1060
0
  case XS_STEP_TAG:
1061
0
    the->debugExit |= 2;
1062
0
    break;
1063
0
  case XS_STEP_INSIDE_TAG:
1064
0
    the->debugExit |= 2;
1065
0
    break;
1066
0
  case XS_STEP_OUTSIDE_TAG:
1067
0
    the->debugExit |= 2;
1068
0
    break;
1069
0
  case XS_STOP_PROFILING_TAG:
1070
0
    the->debugExit |= 1;
1071
0
    break;
1072
0
  case XS_TOGGLE_TAG:
1073
0
    break;
1074
#if MODDEF_XS_XSBUG_HOOKS
1075
  case XS_IMPORT_TAG:
1076
    the->debugExit |= 2;
1077
    break;
1078
  case XS_MODULE_TAG:
1079
  case XS_SCRIPT_TAG:
1080
    the->debugExit |= 2;
1081
    break;
1082
#endif
1083
0
  }
1084
0
}
1085
1086
void fxDebugPushTag(txMachine* the)
1087
0
{
1088
0
  switch (the->debugTag) {
1089
0
  case XS_ABORT_TAG:
1090
0
    fxLogout(the);
1091
0
    fxGo(the);
1092
0
    fxAbort(the, XS_DEBUGGER_EXIT);
1093
0
    break;
1094
0
  case XS_BREAKPOINT_TAG:
1095
0
    fxSetBreakpoint(the, the->pathValue, the->lineValue, the->idValue);
1096
0
    break;
1097
0
  case XS_BREAKPOINT_CONDITION_TAG:
1098
0
    fxSetBreakpointCondition(the, the->stack, the->pathValue);
1099
0
    break;
1100
0
  case XS_BREAKPOINT_HIT_COUNT_TAG:
1101
0
    fxSetBreakpointHitCount(the, the->stack, the->pathValue);
1102
0
    break;
1103
0
  case XS_BREAKPOINT_TRACE_TAG:
1104
0
    fxSetBreakpointTrace(the, the->stack, the->pathValue);
1105
0
    break;
1106
0
  case XS_CLEAR_ALL_BREAKPOINTS_TAG:
1107
0
    fxClearAllBreakpoints(the);
1108
0
    break;
1109
0
  case XS_CLEAR_BREAKPOINTS_TAG:
1110
0
    fxClearBreakpoint(the, the->pathValue, the->lineValue, the->idValue);
1111
0
    break;
1112
0
  case XS_EVAL_TAG:
1113
0
    fxDebugEval(the, (txSlot*)the->idValue, the->pathValue, the->lineValue);
1114
0
    break;
1115
0
  case XS_GO_TAG:
1116
0
    fxGo(the);
1117
0
    break;
1118
0
  case XS_LOGOUT_TAG:
1119
0
    fxLogout(the);
1120
0
    fxGo(the);
1121
0
    break;
1122
0
  case XS_SELECT_TAG:
1123
0
    fxSelect(the, (txSlot*)the->idValue);
1124
0
    fxEchoStart(the);
1125
0
    fxListLocal(the);
1126
0
    fxListGlobal(the);
1127
0
    fxListModules(the);
1128
0
    fxEchoStop(the);
1129
0
    break;
1130
0
  case XS_SET_ALL_BREAKPOINTS_TAG:
1131
0
    break;
1132
0
  case XS_SET_BREAKPOINT_TAG:
1133
0
    fxSetBreakpoint(the, the->pathValue, the->lineValue, the->idValue);
1134
0
    break;
1135
0
  case XS_START_PROFILING_TAG:
1136
0
    fxStartProfiling(the);
1137
0
    break;
1138
0
  case XS_STEP_TAG:
1139
0
    fxStep(the);
1140
0
    break;
1141
0
  case XS_STEP_INSIDE_TAG:
1142
0
    fxStepInside(the);
1143
0
    break;
1144
0
  case XS_STEP_OUTSIDE_TAG:
1145
0
    fxStepOutside(the);
1146
0
    break;
1147
0
  case XS_STOP_PROFILING_TAG:
1148
0
    fxStopProfiling(the, C_NULL);
1149
0
    break;
1150
0
  case XS_TOGGLE_TAG:
1151
0
    fxToggle(the, (txSlot*)the->idValue);
1152
0
    fxEchoStart(the);
1153
0
    fxListLocal(the);
1154
0
    fxListGlobal(the);
1155
0
    fxListModules(the);
1156
0
    fxEchoStop(the);
1157
0
    break;
1158
#if MODDEF_XS_XSBUG_HOOKS
1159
  case XS_IMPORT_TAG: 
1160
    /* THIS */
1161
    mxPushUndefined();
1162
    /* FUNCTION */
1163
    mxPush(mxGlobal);
1164
    mxGetID(fxID(the, "<xsbug:import>"));
1165
        mxCall();
1166
    mxPushStringC("xsbug://");
1167
    fxConcatStringC(the, the->stack, the->pathValue);
1168
    mxPushInteger(the->lineValue);
1169
    break;
1170
  case XS_MODULE_TAG:
1171
  case XS_SCRIPT_TAG:
1172
    fxCollectGarbage(the);
1173
    /* THIS */
1174
    mxPushUndefined();
1175
    /* FUNCTION */
1176
    mxPush(mxGlobal);
1177
    if (the->debugTag == XS_MODULE_TAG)
1178
      mxGetID(fxID(the, "<xsbug:module>"));
1179
    else
1180
      mxGetID(mxID(__xsbug_script_));
1181
    mxCall();
1182
    if (the->debugModule)
1183
      mxPushSlot(the->debugModule);
1184
    else
1185
      mxPushUndefined();
1186
    mxPushStringC(the->pathValue);
1187
    mxPushInteger(the->lineValue);
1188
    mxPushUndefined();
1189
    fxStringBuffer(the, the->stack, C_NULL, 256);
1190
    mxPushInteger(256);
1191
    mxPushInteger(0);
1192
    break;
1193
#endif
1194
0
  }
1195
0
}
1196
1197
void fxDebugScriptCDATA(txMachine* the, char c)
1198
0
{
1199
#if MODDEF_XS_XSBUG_HOOKS
1200
  if ((the->debugTag == XS_MODULE_TAG) || (the->debugTag == XS_SCRIPT_TAG)) {
1201
    txString string = the->stack[2].value.string;
1202
    txInteger size = the->stack[1].value.integer;
1203
    txInteger offset = the->stack[0].value.integer;
1204
    if (offset == size) {
1205
      txString result = (txString)fxRenewChunk(the, string, size + 256);
1206
      if (!result) {
1207
        result = (txString)fxNewChunk(the, size + 256);
1208
        string = the->stack[2].value.string;
1209
        c_memcpy(result, string, size);
1210
      }
1211
      the->stack[2].value.string = string = result;
1212
      the->stack[1].value.integer = size + 256;
1213
    }
1214
    string[offset++] = c;
1215
    the->stack[0].value.integer = offset;
1216
  }
1217
#endif
1218
0
}
1219
1220
void fxDebugThrow(txMachine* the, txString path, txInteger line, txString message)
1221
2.07M
{
1222
2.07M
  if (the->debugEval)
1223
0
    return;
1224
2.07M
  if (fxIsConnected(the) && (the->breakOnExceptionsFlag))
1225
0
    fxDebugLoop(the, path, line, message);
1226
2.07M
  else {
1227
2.07M
    txSlot* frame = the->frame;
1228
5.45M
    while (frame && !path) {
1229
3.38M
      txSlot* environment = mxFrameToEnvironment(frame);
1230
3.38M
      if (environment->ID != XS_NO_ID) {
1231
2.06M
        path = fxGetKeyName(the, environment->ID);
1232
2.06M
        line = environment->value.environment.line;
1233
2.06M
      }
1234
3.38M
      frame = frame->next;
1235
3.38M
    }
1236
2.07M
    fxReportException(the, path, line, "%s", message);
1237
2.07M
  }
1238
2.07M
}
1239
1240
void fxEcho(txMachine* the, txString theString)
1241
0
{
1242
0
  txInteger srcLength = mxStringLength(theString);
1243
0
  txInteger dstLength = sizeof(the->echoBuffer) - the->echoOffset;
1244
0
  while (srcLength > dstLength) {
1245
0
    c_memcpy(the->echoBuffer + the->echoOffset, theString, dstLength);
1246
0
    theString += dstLength;
1247
0
    srcLength -= dstLength;
1248
0
    the->echoOffset = sizeof(the->echoBuffer);
1249
0
    fxSend(the, 1);
1250
0
    the->echoOffset = 0;
1251
0
    dstLength = sizeof(the->echoBuffer);
1252
0
  }
1253
0
  c_memcpy(the->echoBuffer + the->echoOffset, theString, srcLength);
1254
0
  the->echoOffset += srcLength;
1255
0
}
1256
1257
void fxEchoAddress(txMachine* the, txSlot* theSlot)
1258
0
{
1259
0
  uintptr_t aValue = (uintptr_t)theSlot;
1260
0
  int aShift;
1261
1262
0
  fxEcho(the, " value=\"@");
1263
0
  aShift = (8 * sizeof(aValue)) - 4;
1264
0
  while (aShift >= 0) {
1265
0
    fxEchoCharacter(the, c_read8(gxHexaDigits + ((aValue >> aShift) & 0x0F)));
1266
0
    aShift -= 4;
1267
0
  }
1268
0
  fxEcho(the, "\"");
1269
0
}
1270
1271
void fxEchoArrayBuffer(txMachine* the, txSlot* theInstance, txInspectorNameList* theList)
1272
0
{
1273
0
  txSlot* arrayBuffer = theInstance->next;
1274
0
  txSlot* bufferInfo = arrayBuffer->next;
1275
0
  txU1* address = (txU1*)(arrayBuffer->value.arrayBuffer.address);
1276
0
  txInteger size = bufferInfo->value.bufferInfo.length;
1277
0
  txInteger offset = 0, index;
1278
0
  if (size > 1024)
1279
0
    size = 1024;
1280
0
  while (offset < size) {
1281
0
    fxEcho(the, "<property");
1282
0
    fxEchoFlags(the, " ", 0);
1283
0
    fxEcho(the, " name=\"");
1284
0
    fxEchoCharacter(the, c_read8(gxHexaDigits + ((offset >> 12) & 0xF)));
1285
0
    fxEchoCharacter(the, c_read8(gxHexaDigits + ((offset >> 8) & 0xF)));
1286
0
    fxEchoCharacter(the, c_read8(gxHexaDigits + ((offset >> 4) & 0xF)));
1287
0
    fxEchoCharacter(the, c_read8(gxHexaDigits + (offset & 0xF)));
1288
0
    fxEcho(the, "\"");
1289
0
    fxEcho(the, " value=\"");
1290
0
    index = 0;
1291
0
    while (index < 16) {
1292
0
      txByte byte = *address++;
1293
0
      fxEchoCharacter(the, c_read8(gxHexaDigits + ((byte >> 4) & 0xF)));
1294
0
      fxEchoCharacter(the, c_read8(gxHexaDigits + (byte & 0xF)));
1295
0
      fxEcho(the, " ");
1296
0
      index++;
1297
0
      offset++;
1298
0
      if (offset == size)
1299
0
        break;
1300
0
    }
1301
0
    address -= index;
1302
0
    offset -= index;
1303
0
    while (index < 16) {
1304
0
      fxEcho(the, "   ");
1305
0
      index++;
1306
0
    }    
1307
0
    index = 0;
1308
0
    while (index < 16) {
1309
0
      txByte byte = *address++;
1310
0
      if ((32 <= byte) && (byte < 127))
1311
0
        fxEchoCharacter(the, byte);
1312
0
      else
1313
0
        fxEchoCharacter(the, '.');
1314
0
      index++;
1315
0
      offset++;
1316
0
      if (offset == size)
1317
0
        break;
1318
0
    }
1319
0
    fxEcho(the, " \"/>");
1320
0
  }
1321
0
}
1322
1323
void fxEchoBigInt(txMachine* the, txBigInt* bigint)
1324
0
{
1325
0
  int i = bigint->size - 1;
1326
0
  if (i < 0) {
1327
0
    fxEchoCharacter(the, 'N');
1328
0
    fxEchoCharacter(the, 'a');
1329
0
    fxEchoCharacter(the, 'N');
1330
0
  }
1331
0
  else {
1332
0
    int echo = 0;
1333
0
    if (bigint->sign)
1334
0
      fxEchoCharacter(the, '-');
1335
0
    fxEchoCharacter(the, '0');
1336
0
    fxEchoCharacter(the, 'x');
1337
0
    while (i >= 0) {
1338
0
      txU4 value = bigint->data[i];
1339
0
      txU4 mask = 0xF;
1340
0
      int shift = 28;
1341
0
      while (shift >= 0) {
1342
0
        char digit = c_read8(gxHexaDigits + ((value & (mask << shift)) >> shift));
1343
0
        if (echo || (digit != '0')) {
1344
0
          echo = 1;
1345
0
          fxEchoCharacter(the, digit);
1346
0
        }
1347
0
        shift -= 4;
1348
0
      }
1349
0
      i--;
1350
0
    }
1351
0
    if (!echo)
1352
0
      fxEchoCharacter(the, '0');
1353
0
    fxEchoCharacter(the, 'n');
1354
0
  }
1355
0
}
1356
1357
void fxEchoCharacter(txMachine* the, char theCharacter)
1358
0
{
1359
0
  char c[2];
1360
0
  c[0] = theCharacter;
1361
0
  c[1] = 0;
1362
0
  fxEchoString(the, c);
1363
0
}
1364
1365
void fxEchoException(txMachine* the, txSlot* exception)
1366
0
{
1367
0
  switch (exception->kind) {
1368
0
  case XS_REFERENCE_KIND: {
1369
0
    txSlot* instance = exception->value.reference;
1370
0
    txSlot* internal = instance->next;
1371
0
    if (internal && (internal->kind == XS_ERROR_KIND)) {
1372
0
      switch (internal->value.error.which) {
1373
0
      case XS_UNKNOWN_ERROR: fxEcho(the, "Error"); break;
1374
0
      case XS_EVAL_ERROR: fxEcho(the, "EvalError"); break;
1375
0
      case XS_RANGE_ERROR: fxEcho(the, "RangeError"); break;
1376
0
      case XS_REFERENCE_ERROR: fxEcho(the, "ReferenceError"); break;
1377
0
      case XS_SYNTAX_ERROR: fxEcho(the, "SyntaxError"); break;
1378
0
      case XS_TYPE_ERROR: fxEcho(the, "TypeError"); break;
1379
0
      case XS_URI_ERROR: fxEcho(the, "URIError"); break;
1380
0
      case XS_AGGREGATE_ERROR: fxEcho(the, "AggregateError"); break;
1381
0
      case XS_SUPPRESSED_ERROR: fxEcho(the, "SuppressedError"); break;
1382
0
      }
1383
0
      fxEcho(the, ": ");
1384
0
      internal = internal->next;
1385
0
      if (internal && ((internal->kind == XS_STRING_KIND) || (internal->kind == XS_STRING_X_KIND))) {
1386
0
        fxEchoString(the, internal->value.string);
1387
0
      }
1388
0
    }
1389
0
    else {
1390
0
      fxEcho(the, "(");
1391
0
      if (instance->flag & XS_CAN_CALL_FLAG)
1392
0
        fxEcho(the, mxFunctionString.value.string);
1393
0
      else
1394
0
        fxEcho(the, mxObjectString.value.string);
1395
0
      fxEcho(the, ")");
1396
0
    }
1397
0
    } break;
1398
0
  case XS_UNDEFINED_KIND:
1399
0
    fxEcho(the, "undefined");
1400
0
    break;
1401
0
  case XS_NULL_KIND:
1402
0
    fxEcho(the, "null");
1403
0
    break;
1404
0
  case XS_BOOLEAN_KIND:
1405
0
    if (exception->value.boolean)
1406
0
      fxEcho(the, "true");
1407
0
    else
1408
0
      fxEcho(the, "false");
1409
0
    break;
1410
0
  case XS_INTEGER_KIND:
1411
0
    fxEchoInteger(the, exception->value.integer);
1412
0
    break;
1413
0
  case XS_NUMBER_KIND:
1414
0
    fxEchoNumber(the, exception->value.number);
1415
0
    break;
1416
0
  case XS_STRING_KIND:
1417
0
  case XS_STRING_X_KIND:
1418
0
    fxEchoString(the, exception->value.string);
1419
0
    break;
1420
0
  case XS_SYMBOL_KIND:
1421
0
    fxEcho(the, "Symbol(");
1422
0
    fxEchoString(the, fxGetKeyString(the, exception->value.symbol, C_NULL));
1423
0
    fxEcho(the, ")\"/>");
1424
0
    break;
1425
0
  case XS_BIGINT_KIND:
1426
0
  case XS_BIGINT_X_KIND:
1427
0
    fxEchoBigInt(the, &exception->value.bigint);
1428
0
    break;
1429
0
  }
1430
0
}
1431
1432
void fxEchoFlags(txMachine* the, txString state, txFlag flag)
1433
0
{
1434
0
  fxEcho(the, " flags=\"");
1435
0
  fxEcho(the, state);
1436
0
  if (flag & XS_DONT_DELETE_FLAG)
1437
0
    fxEcho(the, "C");
1438
0
  else
1439
0
    fxEcho(the, "c");
1440
0
  if (flag & XS_DONT_ENUM_FLAG)
1441
0
    fxEcho(the, "E");
1442
0
  else
1443
0
    fxEcho(the, "e");
1444
0
  if (flag & XS_DONT_SET_FLAG)
1445
0
    fxEcho(the, "W");
1446
0
  else
1447
0
    fxEcho(the, "w");
1448
0
  if (flag & XS_INSPECTOR_FLAG)
1449
0
    fxEcho(the, "I");
1450
0
  else if (flag & XS_MARK_FLAG)
1451
0
    fxEcho(the, "M");
1452
0
  else
1453
0
    fxEcho(the, "_");
1454
0
  fxEcho(the, "\"");
1455
0
}
1456
1457
void fxEchoFormat(txMachine* the, txString theFormat, c_va_list theArguments)
1458
0
{
1459
0
  char *p, c;
1460
1461
0
  p = theFormat;
1462
0
  while ((c = c_read8(p++))) {
1463
0
    if (c != '%')
1464
0
      fxEchoCharacter(the, c);
1465
0
    else {
1466
0
      if (c_strncmp(p, "c", 1) == 0) {
1467
0
        fxEchoCharacter(the, c_va_arg(theArguments, int));
1468
0
        p++;
1469
0
      }
1470
0
      else if (c_strncmp(p, "hd", 2) == 0) {
1471
0
        fxEchoInteger(the, c_va_arg(theArguments, int));
1472
0
        p += 2;
1473
0
      }
1474
0
      else if (c_strncmp(p, "d", 1) == 0) {
1475
0
        fxEchoInteger(the, c_va_arg(theArguments, int));
1476
0
        p++;
1477
0
      }
1478
0
      else if (c_strncmp(p, "ld", 2) == 0) {
1479
0
        fxEchoInteger(the, c_va_arg(theArguments, long));
1480
0
        p += 2;
1481
0
      }
1482
0
      else if (c_strncmp(p, "g", 1) == 0) {
1483
0
        fxEchoNumber(the, c_va_arg(theArguments, double));
1484
0
        p++;
1485
0
      }
1486
0
      else if (c_strncmp(p, "s", 1) == 0) {
1487
0
        char *s = c_va_arg(theArguments, char *);
1488
0
        fxEchoString(the, s);
1489
0
        p++;
1490
0
      }
1491
0
      else {
1492
0
        fxEchoCharacter(the, c);
1493
0
        p++;
1494
0
      }
1495
0
    }
1496
0
  }
1497
0
}
1498
1499
void fxEchoFrameName(txMachine* the, txSlot* theFrame)
1500
0
{
1501
0
  char buffer[128] = "";
1502
0
  fxBufferFrameName(the, buffer, sizeof(buffer), theFrame, "");
1503
0
  fxEcho(the, buffer);
1504
0
}
1505
1506
void fxEchoFramePathLine(txMachine* the, txSlot* theFrame)
1507
0
{
1508
0
  if (theFrame) {
1509
0
    txSlot* environment = mxFrameToEnvironment(theFrame);
1510
0
    if (environment->ID != XS_NO_ID)
1511
0
      fxEchoPathLine(the, fxGetKeyName(the, environment->ID), environment->value.environment.line);
1512
0
  }
1513
0
}
1514
1515
void fxEchoInteger(txMachine* the, txInteger theInteger)
1516
0
{
1517
0
  char aBuffer[256];
1518
1519
0
  fxIntegerToString(the, theInteger, aBuffer, sizeof(aBuffer));
1520
0
  fxEcho(the, aBuffer);
1521
0
}
1522
1523
void fxEchoInstance(txMachine* the, txSlot* theInstance, txInspectorNameList* theList)
1524
0
{
1525
0
  txSlot* aParent;
1526
0
  txSlot* aProperty;
1527
0
  txSlot* aSlot;
1528
0
  txInteger anIndex;
1529
1530
#if mxAliasInstance
1531
  if (theInstance->ID) {
1532
    txSlot* aliasInstance = the->aliasArray[theInstance->ID];
1533
    if (aliasInstance)
1534
      theInstance = aliasInstance;
1535
  }
1536
#endif
1537
0
  aParent = fxGetPrototype(the, theInstance);
1538
0
  if (aParent)
1539
0
    fxEchoPropertyInstance(the, theList, "(..)", -1, C_NULL, XS_NO_ID, theInstance->flag & XS_MARK_FLAG, aParent);
1540
0
  aProperty = theInstance->next;
1541
0
  if (aProperty && (aProperty->flag & XS_INTERNAL_FLAG) && (aProperty->ID == XS_ARRAY_BEHAVIOR)) {
1542
0
    fxEchoProperty(the, aProperty, theList, "(array)", -1, C_NULL);
1543
0
  }
1544
0
  else if (aProperty && (aProperty->flag & XS_INTERNAL_FLAG)) {
1545
0
    switch (aProperty->kind) {
1546
0
    case XS_CALLBACK_KIND:
1547
0
    case XS_CALLBACK_X_KIND:
1548
0
    case XS_CODE_KIND:
1549
0
    case XS_CODE_X_KIND:
1550
0
      if (aProperty->value.code.closures)
1551
0
        fxEchoPropertyInstance(the, theList, "(closures)", -1, C_NULL, XS_NO_ID, aProperty->flag & (XS_GET_ONLY | XS_INSPECTOR_FLAG | XS_MARK_FLAG), aProperty->value.code.closures);
1552
0
      fxEchoProperty(the, aProperty, theList, "(function)", -1, C_NULL);
1553
0
      aProperty = aProperty->next;
1554
0
      if ((aProperty->kind == XS_HOME_KIND) && (aProperty->value.home.object))
1555
0
        fxEchoPropertyInstance(the, theList, "(home)", -1, C_NULL, XS_NO_ID, aProperty->flag, aProperty->value.home.object);
1556
0
      aProperty = aProperty->next;
1557
0
      break;
1558
0
    case XS_ARRAY_BUFFER_KIND:
1559
0
      fxEchoArrayBuffer(the, theInstance, theList);
1560
0
      aProperty = aProperty->next;
1561
0
      fxEchoProperty(the, aProperty, theList, "(buffer)", -1, C_NULL);
1562
0
      aProperty = aProperty->next;
1563
0
      break;
1564
0
    case XS_STRING_KIND:
1565
0
    case XS_STRING_X_KIND:
1566
0
      fxEchoProperty(the, aProperty, theList, "(string)", -1, C_NULL);
1567
0
      aProperty = aProperty->next;
1568
0
      break;
1569
0
    case XS_BOOLEAN_KIND:
1570
0
      fxEchoProperty(the, aProperty, theList, "(boolean)", -1, C_NULL);
1571
0
      aProperty = aProperty->next;
1572
0
      break;
1573
0
    case XS_NUMBER_KIND:
1574
0
      fxEchoProperty(the, aProperty, theList, "(number)", -1, C_NULL);
1575
0
      aProperty = aProperty->next;
1576
0
      break;
1577
0
    case XS_BIGINT_KIND:
1578
0
    case XS_BIGINT_X_KIND:
1579
0
      fxEchoProperty(the, aProperty, theList, "(bigint)", -1, C_NULL);
1580
0
      aProperty = aProperty->next;
1581
0
      break;
1582
0
    case XS_DATA_VIEW_KIND:
1583
0
      fxEchoProperty(the, aProperty, theList, "(view)", -1, C_NULL);
1584
0
      aProperty = aProperty->next;
1585
0
      fxEchoProperty(the, aProperty, theList, "(data)", -1, C_NULL);
1586
0
      aProperty = aProperty->next;
1587
0
      break;
1588
0
    case XS_DATE_KIND:
1589
0
      fxEchoProperty(the, aProperty, theList, "(date)", -1, C_NULL);
1590
0
      aProperty = aProperty->next;
1591
0
      break;
1592
0
    case XS_REGEXP_KIND:
1593
0
      fxEchoProperty(the, aProperty, theList, "(regexp)", -1, C_NULL);
1594
0
      aProperty = aProperty->next;
1595
0
      break;
1596
0
    case XS_HOST_KIND:
1597
0
            fxEchoProperty(the, aProperty, theList, "(host)", -1, C_NULL);
1598
0
      if (aProperty->value.host.data)
1599
0
        fxEchoPropertyHost(the, theList, theInstance, aProperty);
1600
0
      aProperty = aProperty->next;
1601
0
      break;
1602
0
    case XS_GLOBAL_KIND:
1603
0
      aProperty = aProperty->next;
1604
0
      break;
1605
0
    case XS_PROMISE_KIND:
1606
0
            fxEchoProperty(the, aProperty, theList, "(promise)", -1, C_NULL);
1607
0
      aProperty = aProperty->next;
1608
0
      anIndex = 0;
1609
0
      aSlot = aProperty->value.reference->next;
1610
0
      if (aSlot) {
1611
0
        fxEchoProperty(the, aSlot, theList, "(then)", -1, C_NULL);
1612
0
        anIndex++;
1613
0
        aSlot = aSlot->next;
1614
0
      }
1615
0
      while (aSlot) {
1616
0
        fxEchoProperty(the, aSlot, theList, "(", anIndex, ")");
1617
0
        anIndex++;
1618
0
        aSlot = aSlot->next;
1619
0
      }
1620
0
      aProperty = aProperty->next;
1621
0
            fxEchoProperty(the, aProperty, theList, "(value)", -1, C_NULL);
1622
0
      aProperty = aProperty->next;
1623
0
      break;
1624
0
    case XS_MAP_KIND:
1625
0
      aProperty = aProperty->next;
1626
0
      anIndex = 0;
1627
0
      aSlot = aProperty->value.list.first;
1628
0
      while (aSlot) {
1629
0
        if (!(aSlot->flag & XS_DONT_ENUM_FLAG)) {
1630
0
          fxEchoProperty(the, aSlot, theList, "(", anIndex, ".0)");
1631
0
          fxEchoProperty(the, aSlot->next, theList, "(", anIndex, ".1)");
1632
0
        }
1633
0
        anIndex++;
1634
0
        aSlot = aSlot->next->next;
1635
0
      }
1636
0
      aProperty = aProperty->next;
1637
0
      break;
1638
0
    case XS_MODULE_KIND:
1639
0
      aProperty = aProperty->next;
1640
0
      fxEchoProperty(the, aProperty, theList, "(export)", -1, C_NULL);
1641
0
      aProperty = aProperty->next;
1642
0
      break;
1643
0
#if mxModuleStuff
1644
0
    case XS_MODULE_STUFF_KIND:
1645
0
      aProperty = aProperty->next;
1646
0
      fxEchoProperty(the, aProperty, theList, "(namespace)", -1, C_NULL);
1647
0
      aProperty = aProperty->next;
1648
0
      fxEchoProperty(the, aProperty, theList, "(imports)", -1, C_NULL);
1649
0
      aProperty = aProperty->next;
1650
0
      fxEchoProperty(the, aProperty, theList, "(source)", -1, C_NULL);
1651
0
      aProperty = aProperty->next;
1652
0
      fxEchoProperty(the, aProperty, theList, "(handler)", -1, C_NULL);
1653
0
      aProperty = aProperty->next;
1654
0
      fxEchoProperty(the, aProperty, theList, "(importHook)", -1, C_NULL);
1655
0
      aProperty = aProperty->next;
1656
0
      fxEchoProperty(the, aProperty, theList, "(importMetaHook)", -1, C_NULL);
1657
0
      aProperty = aProperty->next;
1658
0
      fxEchoProperty(the, aProperty, theList, "(importNowHook)", -1, C_NULL);
1659
0
      aProperty = aProperty->next;
1660
0
      break;
1661
0
#endif
1662
0
    case XS_PROGRAM_KIND:
1663
0
      aSlot = aProperty->value.module.realm;
1664
0
      fxEchoProperty(the, mxRealmGlobal(aSlot), theList, "(globals)", -1, C_NULL);
1665
0
      fxEchoProperty(the, mxOwnModules(aSlot), theList, "(modules)", -1, C_NULL);
1666
0
      break;
1667
0
    case XS_SET_KIND:
1668
0
      aProperty = aProperty->next;
1669
0
      anIndex = 0;
1670
0
      aSlot = aProperty->value.list.first;
1671
0
      while (aSlot) {
1672
0
        if (!(aSlot->flag & XS_DONT_ENUM_FLAG))
1673
0
          fxEchoProperty(the, aSlot, theList, "(", anIndex, ")");
1674
0
        anIndex++;
1675
0
        aSlot = aSlot->next;
1676
0
      }
1677
0
      aProperty = aProperty->next;
1678
0
      break;
1679
0
    case XS_TYPED_ARRAY_KIND:
1680
0
      fxEchoTypedArray(the, theInstance, theList);
1681
0
      aProperty = aProperty->next;
1682
0
      fxEchoProperty(the, aProperty, theList, "(view)", -1, C_NULL);
1683
0
      aProperty = aProperty->next;
1684
0
      fxEchoProperty(the, aProperty, theList, "(buffer)", -1, C_NULL);
1685
0
      aProperty = aProperty->next;
1686
0
      break;
1687
0
    case XS_PROXY_KIND:
1688
0
      if (aProperty->value.proxy.target)
1689
0
        fxEchoPropertyInstance(the, theList, "(target)", -1, C_NULL, XS_NO_ID, aProperty->flag, aProperty->value.proxy.target);
1690
0
      if (aProperty->value.proxy.handler)
1691
0
        fxEchoPropertyInstance(the, theList, "(handler)", -1, C_NULL, XS_NO_ID, aProperty->flag, aProperty->value.proxy.handler);
1692
0
      aProperty = aProperty->next;
1693
0
      break;
1694
0
    }
1695
0
  }
1696
0
  while (aProperty) {
1697
0
    if (aProperty->flag & XS_INTERNAL_FLAG) {
1698
0
      if (aProperty->kind == XS_ARRAY_KIND) {
1699
0
        txSlot* item = aProperty->value.array.address;
1700
0
        txIndex c = fxGetIndexSize(the, aProperty), i;
1701
0
        if (c > 1024)
1702
0
          c = 1024;
1703
0
        for (i = 0; i < c; i++) {
1704
0
          txIndex index = *((txIndex*)item);
1705
0
          fxEchoProperty(the, item, theList, "[", index, "]");
1706
0
          item++;
1707
0
        }
1708
0
      }
1709
0
      else if (aProperty->kind == XS_PRIVATE_KIND) {
1710
0
        txSlot* instanceInspector = fxToInstanceInspector(the, aProperty);
1711
0
        char buffer[128] = "(";
1712
0
        txSlot* check = aProperty->value.private.check;
1713
0
        txSlot* item = aProperty->value.private.first;
1714
0
        fxBufferFunctionName(the, &buffer[1], sizeof(buffer) - 1, check, ")");
1715
0
        fxEcho(the, "<property");
1716
0
        if (instanceInspector) {
1717
0
          if (instanceInspector->value.instanceInspector.link)
1718
0
            fxEchoFlags(the, " ", aProperty->flag);
1719
0
          else
1720
0
            fxEchoFlags(the, "-", aProperty->flag);
1721
0
        }
1722
0
        else
1723
0
          fxEchoFlags(the, "+", aProperty->flag);
1724
0
        fxEcho(the, " name=\"");
1725
0
        fxEchoString(the, buffer);
1726
0
        fxEcho(the, "\"");
1727
0
        if (instanceInspector) {
1728
0
          if (instanceInspector->value.instanceInspector.link) {
1729
0
            txInspectorNameLink* link = theList->first;
1730
0
            fxEcho(the, " value=\"");
1731
0
            while (link) {
1732
0
              fxEchoPropertyName(the, link->prefix, link->index, link->suffix, link->id);
1733
0
              if (link == instanceInspector->value.instanceInspector.link)
1734
0
                break;
1735
0
              fxEcho(the, ".");
1736
0
              link = link->next;
1737
0
            }
1738
0
            fxEcho(the, "\"/>");
1739
0
          }
1740
0
          else {
1741
0
            txInspectorNameLink link;
1742
0
            link.previous = theList->last;
1743
0
            link.next = C_NULL;
1744
0
            link.prefix = buffer;
1745
0
            link.index = 0;
1746
0
            link.suffix = C_NULL;
1747
0
            link.id = XS_NO_ID;
1748
0
            if (theList->first)
1749
0
              theList->last->next = &link;
1750
0
            else
1751
0
              theList->first = &link;
1752
0
            theList->last = &link;
1753
0
            instanceInspector->value.instanceInspector.link = &link;
1754
0
            fxEchoAddress(the, aProperty);
1755
0
            fxEcho(the, ">");
1756
0
            while (item) {
1757
0
              fxEchoProperty(the, item, theList, C_NULL, -1, C_NULL);
1758
0
              item = item->next;
1759
0
            }
1760
0
            fxEcho(the, "</property>");
1761
0
            instanceInspector->value.instanceInspector.link = C_NULL;
1762
0
            if (link.previous)
1763
0
              link.previous->next = C_NULL;
1764
0
            else
1765
0
              theList->first = C_NULL;
1766
0
            theList->last = link.previous;
1767
0
          }
1768
0
        }
1769
0
        else {
1770
0
          fxEchoAddress(the, aProperty);
1771
0
          fxEcho(the, "/>");
1772
0
        }
1773
0
      }
1774
0
    }
1775
0
    else {
1776
0
      fxEchoProperty(the, aProperty, theList, C_NULL, -1, C_NULL);
1777
0
    }
1778
0
    aProperty = aProperty->next;
1779
0
  }
1780
0
}
1781
1782
void fxEchoModule(txMachine* the, txSlot* module, txInspectorNameList* list)
1783
0
{
1784
0
  txSlot* exports = mxModuleExports(module);
1785
0
  txSlot* instanceInspector = fxToInstanceInspector(the, module);
1786
0
  txSlot* slot;
1787
0
  fxEcho(the, "<node");
1788
0
  if (instanceInspector)
1789
0
    fxEchoFlags(the, "-", exports->flag);
1790
0
  else
1791
0
    fxEchoFlags(the, "+", exports->flag);
1792
0
  fxEcho(the, " name=\"");
1793
0
  slot = mxModuleInternal(module);
1794
0
  fxEcho(the, fxGetKeyName(the, slot->value.module.id));
1795
0
  fxEcho(the, "\"");
1796
0
  fxEchoAddress(the, module);
1797
0
  if (instanceInspector) {
1798
0
    fxEcho(the, ">");
1799
0
    fxEchoInstance(the, fxGetInstance(the, exports), list);
1800
0
    fxEcho(the, "</node>");
1801
0
  }
1802
0
  else
1803
0
    fxEcho(the, "/>");
1804
0
}
1805
1806
void fxEchoNumber(txMachine* the, txNumber theNumber)
1807
0
{
1808
0
  char aBuffer[256];
1809
1810
0
  fxNumberToString(the, theNumber, aBuffer, sizeof(aBuffer), 0, 0);
1811
0
  fxEcho(the, aBuffer);
1812
0
}
1813
1814
void fxEchoPathLine(txMachine* the, txString thePath, txInteger theLine)
1815
0
{
1816
0
  if (thePath && theLine) {
1817
0
    fxEcho(the, " path=\"");
1818
0
    fxEchoString(the, thePath);
1819
0
    fxEcho(the, "\"");
1820
0
    fxEcho(the, " line=\"");
1821
0
    fxEchoInteger(the, theLine);
1822
0
    fxEcho(the, "\"");
1823
0
  }
1824
0
}
1825
1826
void fxEchoProperty(txMachine* the, txSlot* theProperty, txInspectorNameList* theList, txString thePrefix, txIndex theIndex, txString theSuffix)
1827
0
{
1828
0
  txID ID = theProperty->ID;
1829
0
  txFlag flag = theProperty->flag;
1830
0
  txSlot* instance;
1831
0
  if ((theProperty->kind == XS_CLOSURE_KIND) || (theProperty->kind == XS_EXPORT_KIND)) {
1832
0
    theProperty = theProperty->value.closure;
1833
0
        if (!theProperty)
1834
0
            return;
1835
#if mxAliasInstance
1836
    if (theProperty->ID) {
1837
      txSlot* slot = the->aliasArray[theProperty->ID];
1838
      if (slot)
1839
        theProperty = slot;
1840
    }
1841
#endif
1842
0
  }
1843
0
  if (theProperty->kind == XS_REFERENCE_KIND) {
1844
0
    instance = fxGetInstance(the, theProperty);
1845
0
    if (instance)
1846
0
      fxEchoPropertyInstance(the, theList, thePrefix, theIndex, theSuffix, ID, flag, instance);
1847
0
  }
1848
0
  else if (theProperty->kind == XS_ACCESSOR_KIND) {
1849
0
    instance = theProperty->value.accessor.getter;
1850
0
    if (instance)
1851
0
      fxEchoPropertyInstance(the, theList, thePrefix, theIndex, theSuffix, ID, flag | XS_GETTER_FLAG, instance);
1852
0
    instance = theProperty->value.accessor.setter;
1853
0
    if (instance)
1854
0
      fxEchoPropertyInstance(the, theList, thePrefix, theIndex, theSuffix, ID, flag | XS_SETTER_FLAG, instance);
1855
0
  }
1856
0
  else {
1857
0
    fxEcho(the, "<property");
1858
0
    fxEchoFlags(the, " ", flag);
1859
0
    fxEcho(the, " name=\"");
1860
0
    fxEchoPropertyName(the, thePrefix, theIndex, theSuffix, ID);
1861
0
    fxEcho(the, "\"");
1862
  
1863
0
    switch (theProperty->kind) {
1864
0
    case XS_UNDEFINED_KIND:
1865
0
      fxEcho(the, " value=\"undefined\"/>");
1866
0
      break;
1867
0
    case XS_NULL_KIND:
1868
0
      fxEcho(the, " value=\"null\"/>");
1869
0
      break;
1870
0
    case XS_CALLBACK_KIND:
1871
0
    case XS_CALLBACK_X_KIND:
1872
0
      fxEcho(the, " value=\"(C code)\"/>");
1873
0
      break;
1874
0
    case XS_CODE_KIND:
1875
0
    case XS_CODE_X_KIND:
1876
0
      fxEcho(the, " value=\"");
1877
0
      {
1878
0
        txByte* p = theProperty->value.code.address + 2;
1879
0
        if (*p == XS_CODE_FILE) {
1880
0
          txID file;
1881
0
          txS2 line;
1882
0
          p++;
1883
0
          mxDecodeID(p, file);
1884
0
          p++;
1885
0
          mxDecode2(p, line);
1886
0
          fxEchoString(the, fxGetKeyName(the, file));
1887
0
          fxEcho(the, "\" line=\"");
1888
0
          fxEchoInteger(the, line);
1889
0
        }
1890
0
        else
1891
0
          fxEcho(the, "(XS code)");
1892
0
      }
1893
0
      fxEcho(the, "\"/>");
1894
0
      break;
1895
  #if mxHostFunctionPrimitive
1896
    case XS_HOST_FUNCTION_KIND:
1897
      fxEcho(the, " value=\"(host function)\"/>");
1898
      break;
1899
  #endif
1900
0
    case XS_ARRAY_KIND:
1901
0
      fxEcho(the, " value=\"");
1902
0
      fxEchoInteger(the, theProperty->value.array.length);
1903
0
      fxEcho(the, " items\"/>");
1904
0
      break;
1905
0
    case XS_BUFFER_INFO_KIND:
1906
0
      fxEcho(the, " value=\"");
1907
0
      fxEchoInteger(the, theProperty->value.bufferInfo.length);
1908
0
      if (theProperty->value.bufferInfo.maxLength >= 0) {
1909
0
        fxEcho(the, " bytes <= ");
1910
0
        fxEchoInteger(the, theProperty->value.bufferInfo.maxLength);
1911
0
      }
1912
0
      fxEcho(the, " bytes\"/>");
1913
0
      break;
1914
0
    case XS_STRING_KIND:
1915
0
    case XS_STRING_X_KIND:
1916
0
      fxEcho(the, " value=\"'");
1917
0
      fxEchoString(the, theProperty->value.string);
1918
0
      fxEcho(the, "'\"/>");
1919
0
      break;
1920
0
    case XS_BOOLEAN_KIND:
1921
0
      fxEcho(the, " value=\"");
1922
0
      if (theProperty->value.boolean)
1923
0
        fxEcho(the, "true");
1924
0
      else
1925
0
        fxEcho(the, "false");
1926
0
      fxEcho(the, "\"/>");
1927
0
      break;
1928
0
    case XS_INTEGER_KIND:
1929
0
      fxEcho(the, " value=\"");
1930
0
      fxEchoInteger(the, theProperty->value.integer);
1931
0
      fxEcho(the, "\"/>");
1932
0
      break;
1933
0
    case XS_NUMBER_KIND:
1934
0
      fxEcho(the, " value=\"");
1935
0
      fxEchoNumber(the, theProperty->value.number);
1936
0
      fxEcho(the, "\"/>");
1937
0
      break;
1938
0
    case XS_BIGINT_KIND:
1939
0
    case XS_BIGINT_X_KIND:
1940
0
      fxEcho(the, " value=\"");
1941
0
      fxEchoBigInt(the, &theProperty->value.bigint);
1942
0
      fxEcho(the, "\"/>");
1943
0
      break;
1944
0
    case XS_DATE_KIND:
1945
0
      fxEcho(the, " value=\"");
1946
0
      fxEchoNumber(the, theProperty->value.number);
1947
0
      fxEcho(the, "\"/>");
1948
0
      break;
1949
0
    case XS_REGEXP_KIND:
1950
0
      fxEcho(the, " value=\"\"/>");
1951
0
      break;
1952
0
    case XS_HOST_KIND:
1953
0
      if (theProperty->value.host.data) {
1954
0
        if (theProperty->flag & XS_HOST_CHUNK_FLAG)
1955
0
          fxEcho(the, " value=\"XS data\"/>");
1956
0
        else
1957
0
          fxEcho(the, " value=\"C data\"/>");
1958
0
      }
1959
0
      else
1960
0
          fxEcho(the, " value=\"NULL\"/>");
1961
0
      break;
1962
0
    case XS_PROMISE_KIND:
1963
0
      switch (theProperty->value.integer) {
1964
0
      case mxUndefinedStatus: fxEcho(the, " value=\"?\"/>"); break;
1965
0
      case mxPendingStatus: fxEcho(the, " value=\"pending\"/>"); break;
1966
0
      case mxFulfilledStatus: fxEcho(the, " value=\"fulfilled\"/>"); break;
1967
0
      case mxRejectedStatus: fxEcho(the, " value=\"rejected\"/>"); break;
1968
0
      }
1969
0
      break;
1970
0
    case XS_KEY_KIND:
1971
0
    case XS_KEY_X_KIND:
1972
0
      fxEcho(the, " value=\"'");
1973
0
      fxEchoString(the, theProperty->value.key.string);
1974
0
      fxEcho(the, "'\"/>");
1975
0
      break;
1976
0
    case XS_SYMBOL_KIND:
1977
0
      fxEcho(the, " value=\"Symbol(");
1978
0
      fxEchoString(the, fxGetKeyString(the, theProperty->value.symbol, C_NULL));
1979
0
      fxEcho(the, ")\"/>");
1980
0
      break;
1981
0
    case XS_DATA_VIEW_KIND:
1982
0
      fxEcho(the, " value=\"");
1983
0
      fxEchoInteger(the, theProperty->value.dataView.offset);
1984
0
      fxEcho(the, ", ");
1985
0
      fxEchoInteger(the, fxGetDataViewSize(the, theProperty, theProperty->next));
1986
0
      fxEcho(the, " bytes\"/>");
1987
0
      break;
1988
0
    default:
1989
0
      fxEcho(the, "/>");
1990
0
      break;
1991
0
    }
1992
0
  }
1993
0
}
1994
1995
void fxEchoPropertyHost(txMachine* the, txInspectorNameList* theList, txSlot* theInstance, txSlot* theHost)
1996
0
{
1997
0
  txSlot* instanceInspector = fxToInstanceInspector(the, theInstance);
1998
0
  if (instanceInspector) {
1999
0
    txSlot* hostInspectors = &mxHostInspectors;
2000
0
    txSlot* hostInspector;
2001
0
    txSlot* cache;
2002
0
    txSlot* cacheProperty;
2003
0
    hostInspector = hostInspectors->value.list.first;
2004
0
    while (hostInspector) {
2005
0
      if (hostInspector->value.hostInspector.instance == theInstance) {
2006
0
        break;
2007
0
      }
2008
0
      hostInspector = hostInspector->next;
2009
0
    }
2010
0
    if (!hostInspector) {
2011
0
      txSlot* aParent;
2012
0
      cache = fxNewInstance(the);
2013
0
      hostInspector = fxNewSlot(the);
2014
0
      hostInspector->kind = XS_HOST_INSPECTOR_KIND;
2015
0
      hostInspector->value.hostInspector.cache = cache;
2016
0
      hostInspector->value.hostInspector.instance = theInstance;
2017
0
      if (hostInspectors->value.list.first) 
2018
0
        hostInspectors->value.list.last->next = hostInspector;
2019
0
      else
2020
0
        hostInspectors->value.list.first = hostInspector;
2021
0
      hostInspectors->value.list.last = hostInspector;
2022
0
      mxPop();
2023
      
2024
0
      aParent = theInstance;
2025
0
      while (aParent && (aParent->next->kind == XS_HOST_KIND)) {
2026
0
        txSlot* aParentProperty = aParent->next;
2027
0
        while (aParentProperty) {
2028
0
          if ((aParentProperty->kind == XS_ACCESSOR_KIND) && (aParentProperty->value.accessor.getter)) {
2029
0
            cacheProperty = mxBehaviorGetProperty(the, cache, aParentProperty->ID, 0, XS_ANY);
2030
0
            if (!cacheProperty) {
2031
0
              txSlot* aFunction = aParentProperty->value.accessor.getter;
2032
0
              if (mxIsFunction(aFunction)) {
2033
0
                fxBeginHost(the);
2034
0
                the->frame->flag &= ~(XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG);
2035
                /* THIS */
2036
0
                mxPushReference(theInstance);
2037
                /* FUNCTION */
2038
0
                mxPushReference(aFunction);
2039
0
                mxCall();
2040
0
                mxRunCount(0);
2041
0
                cacheProperty = mxBehaviorSetProperty(the, cache, aParentProperty->ID, 0, XS_ANY);
2042
0
                cacheProperty->flag |= XS_INSPECTOR_FLAG;
2043
0
                cacheProperty->kind = the->stack->kind;
2044
0
                cacheProperty->value = the->stack->value;
2045
0
                mxPop();
2046
0
                fxEndHost(the);
2047
0
              }
2048
0
            }
2049
0
          }
2050
0
          aParentProperty = aParentProperty->next;
2051
0
        }
2052
0
        aParent = fxGetPrototype(the, aParent);
2053
0
      }
2054
0
    }
2055
0
    cache = hostInspector->value.hostInspector.cache;
2056
0
    cacheProperty = cache->next;
2057
0
    while (cacheProperty) {
2058
0
      if (cacheProperty->ID)
2059
0
        fxEchoProperty(the, cacheProperty, theList, C_NULL, -1, C_NULL);
2060
0
      cacheProperty = cacheProperty->next;
2061
0
    }
2062
0
  }
2063
0
}
2064
2065
2066
void fxEchoPropertyInstance(txMachine* the, txInspectorNameList* theList, txString thePrefix, txIndex theIndex, txString theSuffix, txID theID, txFlag theFlag, txSlot* theInstance)
2067
0
{
2068
0
  txSlot* instanceInspector = fxToInstanceInspector(the, theInstance);
2069
0
  char buffer[128];
2070
0
  txString p = buffer;
2071
0
  txString q = p + sizeof(buffer);
2072
2073
0
  if (theFlag & XS_GETTER_FLAG) {
2074
0
    c_strcpy(p, "get ");
2075
0
    p += 4;
2076
0
  }
2077
0
  else if (theFlag & XS_SETTER_FLAG) {
2078
0
    c_strcpy(p, "set ");
2079
0
    p += 4;
2080
0
  }
2081
0
  if (thePrefix) {
2082
0
    c_strcpy(p, thePrefix);
2083
0
    p += mxStringLength(thePrefix);
2084
0
    if (theSuffix) {
2085
0
      fxIndexToString(the, theIndex, p, mxPtrDiff(q - p - 1)); // assume mxStringLength(theSuffix) == 1;
2086
0
      c_strcat(p, theSuffix);
2087
0
    }
2088
0
  }
2089
0
  else
2090
0
    fxIDToString(the, theID, p, mxPtrDiff(q - p));
2091
2092
0
  fxEcho(the, "<property");
2093
0
  if (instanceInspector) {
2094
0
    if (instanceInspector->value.instanceInspector.link)
2095
0
      fxEchoFlags(the, " ", theFlag);
2096
0
    else
2097
0
      fxEchoFlags(the, "-", theFlag);
2098
0
  }
2099
0
  else
2100
0
    fxEchoFlags(the, "+", theFlag);
2101
0
  fxEcho(the, " name=\"");
2102
0
  if (theFlag & XS_GETTER_FLAG)
2103
0
    fxEcho(the, "get ");
2104
0
  else if (theFlag & XS_SETTER_FLAG)
2105
0
    fxEcho(the, "set ");
2106
0
  fxEchoPropertyName(the, thePrefix, theIndex, theSuffix, theID);
2107
0
  fxEcho(the, "\"");
2108
  
2109
0
  if (instanceInspector) {
2110
0
    if (instanceInspector->value.instanceInspector.link) {
2111
0
      txInspectorNameLink* link = theList->first;
2112
0
      fxEcho(the, " value=\"");
2113
0
      while (link) {
2114
0
        fxEchoPropertyName(the, link->prefix, link->index, link->suffix, link->id);
2115
0
        if (link == instanceInspector->value.instanceInspector.link)
2116
0
          break;
2117
0
        fxEcho(the, ".");
2118
0
        link = link->next;
2119
0
      }
2120
0
      fxEcho(the, "\"/>");
2121
0
    }
2122
0
    else {
2123
0
      txInspectorNameLink link;
2124
0
      link.previous = theList->last;
2125
0
      link.next = C_NULL;
2126
0
      link.prefix = thePrefix;
2127
0
      link.index = theIndex;
2128
0
      link.suffix = theSuffix;
2129
0
      link.id = theID;
2130
0
      if (theList->first)
2131
0
        theList->last->next = &link;
2132
0
      else
2133
0
        theList->first = &link;
2134
0
      theList->last = &link;
2135
0
      instanceInspector->value.instanceInspector.link = &link;
2136
      
2137
0
      fxEchoAddress(the, theInstance);
2138
0
      fxEcho(the, ">");
2139
0
      fxEchoInstance(the, theInstance, theList);
2140
0
      fxEcho(the, "</property>");
2141
      
2142
0
      instanceInspector->value.instanceInspector.link = C_NULL;
2143
0
      if (link.previous)
2144
0
        link.previous->next = C_NULL;
2145
0
      else
2146
0
        theList->first = C_NULL;
2147
0
      theList->last = link.previous;
2148
0
    }
2149
0
  }
2150
0
  else {
2151
0
    fxEchoAddress(the, theInstance);
2152
0
    fxEcho(the, "/>");
2153
0
  }
2154
0
}
2155
2156
void fxEchoPropertyName(txMachine* the, txString thePrefix, txIndex theIndex, txString theSuffix, txID theID)
2157
0
{
2158
0
  if (thePrefix) {
2159
0
    fxEchoString(the, thePrefix);
2160
0
    if (theSuffix) {
2161
0
      fxIndexToString(the, theIndex, the->nameBuffer, sizeof(the->nameBuffer));
2162
0
      fxEchoString(the, the->nameBuffer);
2163
0
      fxEchoString(the, theSuffix);
2164
0
    }
2165
0
  }
2166
0
  else {
2167
0
    if (theID != XS_NO_ID) {
2168
0
      txBoolean adorn;
2169
0
      txString string = fxGetKeyString(the, theID, &adorn);
2170
0
      if (adorn) {
2171
0
        fxEcho(the, "Symbol(");
2172
0
        fxEchoString(the, string);
2173
0
        fxEcho(the, ")");
2174
0
      }
2175
0
      else
2176
0
        fxEchoString(the, string);
2177
0
    }
2178
0
    else
2179
0
      fxEcho(the, "?");
2180
0
  }
2181
0
}
2182
2183
void fxEchoStart(txMachine* the)
2184
0
{
2185
0
  the->echoOffset = 0;
2186
0
  fxEcho(the, "\15\12<xsbug>");
2187
0
}
2188
2189
void fxEchoStop(txMachine* the)
2190
0
{
2191
0
  fxEcho(the, "</xsbug>\15\12");
2192
0
  fxSend(the, 0);
2193
0
  the->echoOffset = 0;
2194
0
}
2195
2196
void fxEchoString(txMachine* the, txString theString)
2197
0
{
2198
0
  static const txByte gxEscape[256] ICACHE_FLASH_ATTR = {
2199
  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
2200
0
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
2201
0
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
2202
0
     1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 2x   !"#$%&'()*+,-./  */
2203
0
     1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1, /* 3x  0123456789:;<=>?  */
2204
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x  @ABCDEFGHIJKLMNO  */
2205
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5X  PQRSTUVWXYZ[\]^_  */
2206
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x  `abcdefghijklmno  */
2207
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,   /* 7X  pqrstuvwxyz{|}~   */
2208
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 8X                    */
2209
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9X                    */
2210
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* AX                    */
2211
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* BX                    */
2212
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* CX                    */
2213
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* FX                    */
2214
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* EX                    */
2215
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1  /* FX                    */
2216
0
  };
2217
0
  txU1 tmp;
2218
0
  txU1* src;
2219
0
  txU1* dst;
2220
0
  txU1* start;
2221
0
  txU1* stop;
2222
2223
0
  src = (txU1*)theString;
2224
0
  dst = (txU1*)the->echoBuffer + the->echoOffset;
2225
0
  start = (txU1*)the->echoBuffer;
2226
0
  stop = (txU1*)the->echoBuffer + sizeof(the->echoBuffer) - 1;
2227
0
  while ((tmp = c_read8(src))) {
2228
0
    src++;
2229
0
    if (dst + 6 > stop) {
2230
0
      the->echoOffset = mxPtrDiff(dst - start);
2231
0
      fxSend(the, 1);
2232
0
      dst = start;
2233
0
    }
2234
0
#if mxCESU8
2235
0
    if (tmp & 0x80) {
2236
0
      txInteger character;
2237
0
      src = (txU1*)fxCESU8Decode((txString)src - 1, &character);
2238
0
      if (character > 128) {
2239
0
        dst = (txU1*)fxUTF8Encode((txString)dst, character);
2240
0
        continue;
2241
0
      }
2242
0
      tmp = (txU1)character;
2243
0
    }
2244
0
#endif
2245
0
    if (c_read8(gxEscape + tmp))
2246
0
      *dst++ = tmp;
2247
0
    else {
2248
0
      *(dst++) = '&';
2249
0
      *(dst++) = '#';
2250
0
      if (tmp >= 100) {
2251
0
        *(dst++) = '0' + (tmp / 100);
2252
0
        tmp %= 100;
2253
0
        *(dst++) = '0' + (tmp / 10);
2254
0
        tmp %= 10;
2255
0
        *(dst++) = '0' + tmp;
2256
0
      }
2257
0
      else if (tmp >= 10) {
2258
0
        *(dst++) = '0' + (tmp / 10);
2259
0
        tmp %= 10;
2260
0
        *(dst++) = '0' + tmp;
2261
0
      }
2262
0
      else {
2263
0
        *(dst++) = '0' + tmp;
2264
0
      }
2265
0
      *(dst++) = ';';
2266
0
    }
2267
0
  }
2268
0
  the->echoOffset = mxPtrDiff(dst - start);
2269
0
}
2270
2271
void fxEchoTypedArray(txMachine* the, txSlot* theInstance, txInspectorNameList* theList)
2272
0
{
2273
0
  txSlot* dispatch = theInstance->next;
2274
0
  txSlot* view = dispatch->next;
2275
0
  txSlot* buffer = view->next;
2276
0
  txU2 shift = dispatch->value.typedArray.dispatch->shift;
2277
0
  txInteger size = fxGetDataViewSize(the, view, buffer) >> shift;
2278
0
  fxEcho(the, "<property");
2279
0
  fxEchoFlags(the, " ", dispatch->flag);
2280
0
  fxEcho(the, " name=\"(");
2281
0
  fxIDToString(the, dispatch->value.typedArray.dispatch->constructorID, the->nameBuffer, sizeof(the->nameBuffer));
2282
0
  fxEchoString(the, the->nameBuffer);
2283
0
  fxEcho(the, ")\"");
2284
0
  fxEcho(the, " value=\"");
2285
0
  fxEchoInteger(the, size);
2286
0
  fxEcho(the, " items\"/>");
2287
0
  if (size > 0) {
2288
0
    txInteger index = 0;
2289
0
    if (size > 1024)
2290
0
      size = 1024;
2291
0
    mxPushUndefined();
2292
0
    while (index < size) {
2293
0
      (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), the->stack, EndianNative);
2294
0
      fxEchoProperty(the, the->stack, theList, "[", index, "]");
2295
0
      index++;
2296
0
    }
2297
0
    mxPop();
2298
0
  }
2299
0
}
2300
2301
txSlot* fxFindFrame(txMachine* the)
2302
0
{
2303
0
  txSlot* frame = the->frame;
2304
0
  while (frame) {
2305
0
    if (frame->flag & XS_DEBUG_FLAG)
2306
0
      break;
2307
0
    frame = frame->next;
2308
0
  }
2309
0
  return frame;
2310
0
}
2311
2312
txSlot* fxFindRealm(txMachine* the)
2313
0
{
2314
0
  txSlot* frame = fxFindFrame(the);
2315
0
  txSlot* realm = C_NULL;
2316
0
  if (frame && (!(frame->flag & XS_C_FLAG))) {
2317
0
    txSlot* function = frame + 2;
2318
0
    if (mxIsReference(function)) {
2319
0
            txSlot* instance = function->value.reference;
2320
0
            txSlot* home = mxFunctionInstanceHome(instance);
2321
0
      txSlot* module = home->value.home.module;
2322
0
            if (module)
2323
0
                realm = mxModuleInstanceInternal(module)->value.module.realm;
2324
0
    }
2325
0
  }
2326
0
  if (!realm)
2327
0
    realm = mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm;
2328
0
  return realm;
2329
0
}
2330
2331
void fxGo(txMachine* the)
2332
0
{
2333
0
  txSlot* aSlot = the->frame;
2334
0
  while (aSlot) {
2335
0
    aSlot->flag &= ~(XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG);
2336
0
    aSlot = aSlot->next;
2337
0
  }
2338
0
}
2339
2340
void fxIndexToString(txMachine* the, txIndex theIndex, txString theBuffer, txSize theSize)
2341
0
{
2342
0
  c_snprintf(theBuffer, theSize, "%u", (unsigned int)theIndex);
2343
0
}
2344
2345
void fxListFrames(txMachine* the)
2346
0
{
2347
0
  txSlot* aFrame;
2348
2349
0
  fxEcho(the, "<frames>");
2350
0
  aFrame = the->frame;
2351
0
  while (aFrame) {
2352
0
    fxEcho(the, "<frame");
2353
0
    fxEcho(the, " name=\"");
2354
0
    fxEchoFrameName(the, aFrame);
2355
0
    fxEcho(the, "\"");
2356
0
    fxEchoAddress(the, aFrame);
2357
0
    fxEchoFramePathLine(the, aFrame);
2358
0
    fxEcho(the, "/>");
2359
0
    aFrame = aFrame->next;
2360
0
  }
2361
0
  fxEcho(the, "</frames>");
2362
0
}
2363
2364
void fxListGlobal(txMachine* the)
2365
0
{
2366
0
  txInspectorNameList aList = { C_NULL, C_NULL };
2367
0
  txSlot* realm = fxFindRealm(the);
2368
0
  txSlot* global = mxRealmGlobal(realm)->value.reference;
2369
0
  txSlot* slot = fxGetPrototype(the, global);
2370
0
  fxEcho(the, "<global>");
2371
0
  if (slot != mxObjectPrototype.value.reference) {
2372
0
    fxEchoPropertyInstance(the, &aList, "(..)", -1, C_NULL, XS_NO_ID, global->flag & XS_MARK_FLAG, slot);
2373
0
  }
2374
0
  slot = global->next;
2375
0
  while (slot->flag & XS_INTERNAL_FLAG) {
2376
0
    slot = slot->next;
2377
0
  }
2378
0
  while (slot) {
2379
0
    fxEchoProperty(the, slot, &aList, C_NULL, -1, C_NULL);
2380
0
    slot = slot->next;
2381
0
  }
2382
0
  global = mxRealmClosures(realm)->value.reference;
2383
0
  slot = global->next;
2384
0
  while (slot) {
2385
0
    fxEchoProperty(the, slot, &aList, C_NULL, -1, C_NULL);
2386
0
    slot = slot->next;
2387
0
  }
2388
0
  fxEcho(the, "</global>");
2389
0
}
2390
2391
void fxListLocal(txMachine* the)
2392
0
{
2393
0
  txInspectorNameList aList = { C_NULL, C_NULL };
2394
0
  txSlot* frame = fxFindFrame(the);
2395
0
  txSlot* scope = C_NULL;
2396
0
  if (!frame) // @@
2397
0
    return;
2398
0
  fxEcho(the, "<local");
2399
0
  fxEcho(the, " name=\"");
2400
0
  fxEchoFrameName(the, frame);
2401
0
  fxEcho(the, "\"");
2402
0
  fxEchoAddress(the, frame);
2403
0
  fxEchoFramePathLine(the, frame);
2404
0
  fxEcho(the, ">");
2405
0
  fxEchoProperty(the, frame + 1, &aList, "(return)", -1, C_NULL);
2406
0
  fxEchoProperty(the, frame + 2, &aList, "(function)", -1, C_NULL);
2407
0
  fxEchoProperty(the, frame + 3, &aList, "this", -1, C_NULL);
2408
0
  if (frame->flag & XS_TARGET_FLAG)
2409
0
    fxEchoProperty(the, frame + 4, &aList, "new.target", -1, C_NULL);
2410
0
  if (frame == the->frame)
2411
0
    scope = the->scope;
2412
0
  else {
2413
0
    txSlot* current = the->frame;
2414
0
    while (current->next != frame)
2415
0
      current = current->next;
2416
0
    if (current)
2417
0
      scope = current->value.frame.scope;
2418
0
  }
2419
0
  if (frame->flag & XS_C_FLAG) {
2420
0
    txInteger aCount, anIndex;
2421
0
    aCount = (txInteger)(frame->ID);
2422
0
    for (anIndex = 0; anIndex < aCount; anIndex++) {
2423
0
      fxEchoProperty(the, (frame - 1 - anIndex), &aList, "arg(", anIndex, ")");
2424
0
    }
2425
0
    if (scope) {
2426
0
      aCount = scope->value.environment.variable.count;
2427
0
      for (anIndex = 0; anIndex < aCount; anIndex++) {
2428
0
        fxEchoProperty(the, (scope - 1 - anIndex), &aList, "var(", anIndex, ")");
2429
0
      }
2430
0
    }
2431
0
  }
2432
0
  else {
2433
0
    if (scope) {
2434
0
      txSlot* aSlot = mxFrameToEnvironment(frame);
2435
0
      txID id;
2436
0
      while (aSlot > scope) {
2437
0
        aSlot--;
2438
0
        id = aSlot->ID;
2439
0
        if ((0 < id) && (id < the->keyCount)) {
2440
0
          txSlot* key;
2441
0
          if (id < the->keyOffset)
2442
0
            key = the->keyArrayHost[id];
2443
0
          else
2444
0
            key = the->keyArray[id - the->keyOffset];
2445
0
          if (key) {
2446
0
            txKind kind = mxGetKeySlotKind(key);
2447
0
            if ((kind == XS_KEY_KIND) || (kind == XS_KEY_X_KIND)) {
2448
0
               if (key->value.key.string[0] != '#')
2449
0
                fxEchoProperty(the, aSlot, &aList, C_NULL, -1, C_NULL);
2450
0
            }
2451
0
            else
2452
0
              fxEchoProperty(the, aSlot, &aList, C_NULL, -1, C_NULL);
2453
0
          }
2454
0
        }
2455
0
      }
2456
0
    }
2457
0
  }
2458
0
  fxEcho(the, "</local>");
2459
0
}
2460
2461
void fxListModules(txMachine* the)
2462
0
{
2463
0
  txInspectorNameList aList = { C_NULL, C_NULL };
2464
0
  txSlot* realm = fxFindRealm(the);
2465
0
  txSlot* moduleMap = mxModuleMap(realm);
2466
0
  txSlot* instance = fxGetInstance(the, moduleMap);
2467
0
  txSlot* instanceInspector = fxToInstanceInspector(the, instance);
2468
0
  txSlot* modules = mxOwnModules(realm)->value.reference;
2469
0
  txSlot* module;
2470
0
  fxEcho(the, "<grammar>");
2471
0
  if (instance->next) {
2472
0
    fxEcho(the, "<node");
2473
0
    if (instanceInspector)
2474
0
      fxEchoFlags(the, "-", moduleMap->flag);
2475
0
    else
2476
0
      fxEchoFlags(the, "+", moduleMap->flag);
2477
0
    fxEcho(the, " name=\"(map)\"");
2478
0
    fxEchoAddress(the, instance);
2479
0
    if (instanceInspector) {
2480
0
      fxEcho(the, ">");
2481
0
      fxEchoInstance(the, instance, &aList);
2482
0
      fxEcho(the, "</node>");
2483
0
    }
2484
0
    else
2485
0
      fxEcho(the, "/>");
2486
0
  }
2487
0
  module = modules->next;
2488
0
  while (module) {
2489
0
        if (mxIsReference(module))
2490
0
            fxEchoModule(the, module, &aList);
2491
0
    module = module->next;
2492
0
  }
2493
0
  modules = modules->value.instance.prototype;
2494
0
  if (modules) {
2495
0
    module = modules->next;
2496
0
    while (module) {
2497
0
      if (mxIsReference(module))
2498
0
        fxEchoModule(the, module, &aList);
2499
0
      module = module->next;
2500
0
    }
2501
0
  }
2502
0
  fxEcho(the, "</grammar>");
2503
0
}
2504
2505
void fxLogin(txMachine* the)
2506
24.5k
{
2507
24.5k
  if (!fxIsConnected(the)) {
2508
24.5k
    fxConnect(the);
2509
24.5k
    if (!fxIsConnected(the))
2510
24.5k
      return;
2511
24.5k
  }
2512
0
  fxEchoStart(the);
2513
0
  fxEcho(the, "<login name=\"");
2514
0
  if (the->name)
2515
0
    fxEchoString(the, the->name);
2516
0
  else
2517
0
    fxEchoString(the, "xslib");
2518
0
  fxEcho(the, "\" value=\"");
2519
0
  fxEcho(the, "XS ");
2520
0
  fxEchoInteger(the, XS_MAJOR_VERSION);
2521
0
  fxEcho(the, ".");
2522
0
  fxEchoInteger(the, XS_MINOR_VERSION);
2523
0
  fxEcho(the, ".");
2524
0
  fxEchoInteger(the, XS_PATCH_VERSION);
2525
0
  fxEcho(the, " ");
2526
0
  fxEchoInteger(the, (txInteger)(sizeof(txSlot*)*8));
2527
0
  fxEcho(the, "-bit ");
2528
#if mxBigEndian
2529
  fxEcho(the, "BE ");
2530
#else
2531
0
  fxEcho(the, "LE ");
2532
0
#endif
2533
0
  fxEchoInteger(the, (txInteger)(sizeof(txID)*8));
2534
0
  fxEcho(the, "-bit ID\" flags=\"e");
2535
0
  fxEcho(the, "\"/>");
2536
0
  fxEchoStop(the);
2537
#if mxAliasInstance
2538
  {
2539
    txSlot* slot = &mxGlobal;
2540
    if (mxIsReference(slot)) {
2541
      slot = slot->value.reference->value.instance.prototype;
2542
      if (slot != mxObjectPrototype.value.reference)
2543
        fxToggle(the, slot);
2544
    }
2545
    slot = &mxCompartmentGlobal;
2546
    if (mxIsReference(slot)) {
2547
      slot = slot->value.reference->value.instance.prototype;
2548
      if (slot != mxObjectPrototype.value.reference)
2549
        fxToggle(the, slot);
2550
    }
2551
  }
2552
#endif
2553
0
  fxDebugCommand(the);
2554
0
}
2555
2556
void fxLogout(txMachine* the)
2557
24.5k
{
2558
24.5k
  if (!fxIsConnected(the))
2559
24.5k
    return;
2560
0
  fxStopProfiling(the, C_NULL);
2561
0
  fxDisconnect(the);
2562
0
}
2563
2564
void fxSelect(txMachine* the, txSlot* slot)
2565
0
{
2566
0
  txSlot* frame = the->frame;
2567
0
  while (frame) {
2568
0
    if (frame == slot)
2569
0
      frame->flag |= XS_DEBUG_FLAG;
2570
0
    else
2571
0
      frame->flag &= ~XS_DEBUG_FLAG;
2572
0
    frame = frame->next;
2573
0
  }
2574
0
}
2575
2576
void fxSetBreakpoint(txMachine* the, txString thePath, txInteger theLine, size_t theID)
2577
0
{
2578
0
  txID path;
2579
0
  txSlot* breakpoint;
2580
2581
0
  if (!thePath)
2582
0
    return;
2583
0
  if ((theID == 0) && (theLine == 0)) { 
2584
0
    if (!c_strcmp(thePath, "exceptions")) {
2585
0
      the->breakOnExceptionsFlag = 1;
2586
0
      mxPushUndefined();
2587
0
      return;
2588
0
    } 
2589
0
    if (!c_strcmp(thePath, "start")) {
2590
0
      the->breakOnStartFlag = 1;
2591
0
      mxPushUndefined();
2592
0
      return;
2593
0
    } 
2594
0
  }
2595
0
  path = fxNewNameC(the, thePath);
2596
0
  if (!path)
2597
0
    return;
2598
0
  breakpoint = mxBreakpoints.value.list.first;
2599
0
  while (breakpoint) {
2600
0
    if ((breakpoint->ID == path) && (breakpoint->value.breakpoint.line == theLine)) {
2601
0
      break;
2602
0
    }
2603
0
    breakpoint = breakpoint->next;
2604
0
  }
2605
0
  if (!breakpoint) {
2606
0
    breakpoint = fxNewSlot(the);
2607
0
    breakpoint->next = mxBreakpoints.value.list.first;
2608
0
    breakpoint->ID = path;
2609
0
    breakpoint->kind = XS_BREAKPOINT_KIND;
2610
0
    breakpoint->value.breakpoint.line = theLine;
2611
0
    mxBreakpoints.value.list.first = breakpoint;
2612
0
  }
2613
0
  if (theID == 0) {
2614
0
    mxPushUndefined();
2615
0
    breakpoint->value.breakpoint.info = C_NULL;
2616
0
  }
2617
0
  else {
2618
0
    txSlot* instance = fxNewInstance(the);
2619
0
    txSlot* property = fxLastProperty(the, instance);
2620
0
    property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG);
2621
0
    property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG);
2622
0
    property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG);
2623
0
    breakpoint->value.breakpoint.info = instance;
2624
0
  }
2625
0
}
2626
2627
void fxSetBreakpointCondition(txMachine* the, txSlot* reference, txString it)
2628
0
{
2629
0
  txSlot* instance = fxToInstance(the, reference);
2630
0
  txSlot* property = instance->next;
2631
0
  fxDebugEvalBuffer(the, it, property);
2632
0
}
2633
2634
void fxSetBreakpointHitCount(txMachine* the, txSlot* reference, txString it)
2635
0
{
2636
0
  txSlot* instance = fxToInstance(the, reference);
2637
0
  txSlot* property = instance->next->next;
2638
0
  char c = *it;
2639
0
  txID op = XS_CODE_MORE_EQUAL;
2640
0
  txInteger count = 0;
2641
0
  if (c == '%') {
2642
0
    it++;
2643
0
    op = XS_CODE_MODULO;
2644
0
  }
2645
0
  else if (c == '<') {
2646
0
    it++;
2647
0
    if (*it == '=') {
2648
0
      it++;
2649
0
      op = XS_CODE_LESS_EQUAL;
2650
0
    }
2651
0
    else
2652
0
      op = XS_CODE_LESS;
2653
0
  }
2654
0
  else if (*it == '=') {
2655
0
    op = XS_CODE_EQUAL;
2656
0
    it++;
2657
0
  }
2658
0
  else if (*it == '>') {
2659
0
    it++;
2660
0
    if (*it == '=') {
2661
0
      it++;
2662
0
      op = XS_CODE_MORE_EQUAL;
2663
0
    }
2664
0
    else
2665
0
      op = XS_CODE_MORE;
2666
0
  }
2667
0
  it = fxSkipSpaces(it);
2668
0
  while ((c = *it++)) {
2669
0
    if (('0' <= c) && (c <= '9'))
2670
0
      count = (count * 10) + (c - '0');
2671
0
    else
2672
0
      break;
2673
0
  }
2674
0
  property->ID = op;
2675
0
  property->kind = XS_DATA_VIEW_KIND;
2676
0
  property->value.dataView.offset = 0;
2677
0
  property->value.dataView.size = count;
2678
0
}
2679
2680
void fxSetBreakpointTrace(txMachine* the, txSlot* reference, txString it)
2681
0
{
2682
0
  txSlot* instance = fxToInstance(the, reference);
2683
0
  txSlot* property = instance->next->next->next;
2684
0
  fxDebugEvalBuffer(the, it, property);
2685
0
}
2686
2687
void fxStep(txMachine* the)
2688
0
{
2689
0
  txSlot* aSlot = the->frame;
2690
0
  if (aSlot) {
2691
0
    while (aSlot) {
2692
0
      aSlot->flag &= ~XS_STEP_INTO_FLAG;
2693
0
      aSlot->flag |= XS_STEP_OVER_FLAG;
2694
0
      aSlot = aSlot->next;
2695
0
    }
2696
0
  }
2697
0
  else {
2698
0
    the->breakOnStartFlag = 1;
2699
0
  }
2700
0
}
2701
2702
void fxStepInside(txMachine* the)
2703
0
{
2704
0
  txSlot* aSlot = the->frame;
2705
0
  while (aSlot) {
2706
0
    aSlot->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
2707
0
    aSlot = aSlot->next;
2708
0
  }
2709
0
}
2710
2711
void fxStepOutside(txMachine* the)
2712
0
{
2713
0
  txSlot* aSlot = the->frame;
2714
0
  if (aSlot) {
2715
0
    aSlot->flag &= ~(XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG);
2716
0
    aSlot = aSlot->next;
2717
0
    while (aSlot) {
2718
0
      aSlot->flag &= ~XS_STEP_INTO_FLAG;
2719
0
      aSlot->flag |= XS_STEP_OVER_FLAG;
2720
0
      aSlot = aSlot->next;
2721
0
    }
2722
0
  }
2723
0
}
2724
2725
txSlot* fxToInstanceInspector(txMachine* the, txSlot* slot)
2726
0
{
2727
0
  txSlot* instanceInspector = mxInstanceInspectors.value.list.first;
2728
0
  while (instanceInspector) {
2729
0
    if (instanceInspector->value.instanceInspector.slot == slot)
2730
0
      return instanceInspector;
2731
0
    if (instanceInspector->value.instanceInspector.slot > slot)
2732
0
      break;
2733
0
    instanceInspector = instanceInspector->next;
2734
0
  }
2735
0
  return C_NULL;
2736
0
}
2737
2738
void fxToggle(txMachine* the, txSlot* slot)
2739
0
{
2740
0
  txSlot** instanceInspectorAddress = &(mxInstanceInspectors.value.list.first);
2741
0
  txSlot* instanceInspector;
2742
0
  while ((instanceInspector = *instanceInspectorAddress)) {
2743
0
    if (instanceInspector->value.instanceInspector.slot == slot) {
2744
0
      *instanceInspectorAddress = instanceInspector->next;
2745
0
      return;
2746
0
    }
2747
0
    if (instanceInspector->value.instanceInspector.slot > slot)
2748
0
      break;
2749
0
    instanceInspectorAddress = &(instanceInspector->next);
2750
0
  }
2751
0
  instanceInspector = fxNewSlot(the);
2752
0
  instanceInspector->next = *instanceInspectorAddress;
2753
0
  instanceInspector->kind = XS_INSTANCE_INSPECTOR_KIND;
2754
0
  instanceInspector->value.instanceInspector.slot = slot;
2755
0
  instanceInspector->value.instanceInspector.link = C_NULL;
2756
0
  *instanceInspectorAddress = instanceInspector;
2757
0
}
2758
2759
#endif
2760
2761
void fxBubble(txMachine* the, txInteger flags, void* message, txInteger length, txString conversation)
2762
0
{
2763
0
#ifdef mxDebug
2764
0
  if (fxIsConnected(the)) {
2765
0
    txString path = C_NULL;
2766
0
    txInteger line = 0;
2767
0
    txSlot* frame = the->frame;
2768
0
    while (frame && !path) {
2769
0
      txSlot* environment = mxFrameToEnvironment(frame);
2770
0
      if (environment->ID != XS_NO_ID) {
2771
0
        path = fxGetKeyName(the, environment->ID);
2772
0
        line = environment->value.environment.line;
2773
0
      }
2774
0
      frame = frame->next;
2775
0
    }
2776
0
    fxEchoStart(the);
2777
0
    fxEcho(the, "<bubble name=\"");
2778
0
    if (conversation)
2779
0
      fxEchoString(the, conversation);
2780
0
    fxEcho(the, "\" value=\"");
2781
0
    fxEchoInteger(the, flags);
2782
0
    fxEcho(the, "\"");
2783
0
    fxEchoPathLine(the, path, line);
2784
0
    fxEcho(the, ">");
2785
0
    if (flags & XS_BUBBLE_BINARY) {
2786
0
      txU1* bytes = message;
2787
0
      txInteger byteLength = length;
2788
0
      while (byteLength) {
2789
0
        txU1 byte = c_read8(bytes);
2790
0
        fxEchoCharacter(the, gxHexaDigits[(byte & 0xF0) >> 4]);
2791
0
        fxEchoCharacter(the, gxHexaDigits[(byte & 0x0F)]);  
2792
0
        bytes++;
2793
0
        byteLength--;
2794
0
      }
2795
0
    }
2796
0
    else
2797
0
      fxEchoString(the, message);
2798
0
    fxEcho(the, "</bubble>");
2799
0
    fxEchoStop(the);
2800
0
  }
2801
#elif defined(mxInstrument)
2802
  if (!(flags & XS_BUBBLE_BINARY)) {
2803
    if (conversation)
2804
      fxReport(the, "%s: %s\n", conversation, message);
2805
    else
2806
      fxReport(the, "%s\n", message);
2807
  }
2808
#endif
2809
0
}
2810
2811
void fxFileEvalString(txMachine* the, txString string, txString tag)
2812
0
{
2813
0
  #ifdef mxDebug
2814
0
  if (fxIsConnected(the)) {
2815
0
    fxEchoStart(the);
2816
0
    fxEcho(the, "<eval path=\"");
2817
0
    fxEchoString(the, tag);
2818
0
    fxEcho(the, "\"");
2819
0
    fxEcho(the, ">");
2820
0
    fxEchoString(the, string);
2821
0
    fxEcho(the, "</eval>");
2822
0
    fxEchoStop(the);
2823
0
  }
2824
0
#endif
2825
0
}
2826
2827
void fxReport(txMachine* the, txString theFormat, ...)
2828
90
{
2829
90
  c_va_list arguments;
2830
2831
90
  c_va_start(arguments, theFormat);
2832
90
  fxVReport(the, theFormat, arguments);
2833
90
  c_va_end(arguments);
2834
#ifndef mxNoConsole
2835
  c_va_start(arguments, theFormat);
2836
#ifdef pebble
2837
char foo[128];
2838
c_vsnprintf(foo, 128, theFormat, arguments);
2839
modLog_transmit(foo);
2840
#else
2841
  c_vprintf(theFormat, arguments);
2842
  c_va_end(arguments);
2843
#endif
2844
#endif
2845
90
}
2846
2847
void fxReportException(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2848
2.07M
{
2849
2.07M
  c_va_list arguments;
2850
2851
2.07M
  c_va_start(arguments, theFormat);
2852
2.07M
  fxVReportException(the, thePath, theLine, theFormat, arguments);
2853
2.07M
  c_va_end(arguments);
2854
#ifndef mxNoConsole
2855
  if (thePath && theLine)
2856
#if mxWindows
2857
    printf("%s(%d): exception: ", thePath, (int)theLine);
2858
#else
2859
    c_printf("%s:%d: exception: ", thePath, (int)theLine);
2860
#endif
2861
  else
2862
    c_printf("# exception: ");
2863
  c_va_start(arguments, theFormat);
2864
  c_vprintf(theFormat, arguments);
2865
  c_va_end(arguments);
2866
  c_printf("!\n");
2867
#endif
2868
2.07M
}
2869
2870
void fxReportError(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2871
0
{
2872
0
  c_va_list arguments;
2873
2874
0
  c_va_start(arguments, theFormat);
2875
0
  fxVReportError(the, thePath, theLine, theFormat, arguments);
2876
0
  c_va_end(arguments);
2877
#ifndef mxNoConsole
2878
  if (thePath && theLine)
2879
#if mxWindows
2880
    printf("%s(%d): error: ", thePath, (int)theLine);
2881
#else
2882
    c_printf("%s:%d: error: ", thePath, (int)theLine);
2883
#endif
2884
  else
2885
    c_printf("# error: ");
2886
  c_va_start(arguments, theFormat);
2887
  c_vprintf(theFormat, arguments);
2888
  c_va_end(arguments);
2889
  c_printf("!\n");
2890
#endif
2891
0
}
2892
2893
void fxReportWarning(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2894
0
{
2895
0
  c_va_list arguments;
2896
2897
0
  c_va_start(arguments, theFormat);
2898
0
  fxVReportWarning(the, thePath, theLine, theFormat, arguments);
2899
0
  c_va_end(arguments);
2900
#ifndef mxNoConsole
2901
  if (thePath && theLine)
2902
#if mxWindows
2903
    printf("%s(%d): warning: ", thePath, (int)theLine);
2904
#else
2905
    c_printf("%s:%d: warning: ", thePath, (int)theLine);
2906
#endif
2907
  else
2908
    c_printf("# warning: ");
2909
  c_va_start(arguments, theFormat);
2910
  c_vprintf(theFormat, arguments);
2911
  c_va_end(arguments);
2912
  c_printf("!\n");
2913
#endif
2914
0
}
2915
2916
txID fxGenerateProfileID(void* console)
2917
15.5M
{
2918
15.5M
  txMachine* the = console;
2919
15.5M
  txID id = the->profileID;
2920
15.5M
  the->profileID++;
2921
15.5M
  return id;
2922
15.5M
}
2923
2924
void fxGenerateTag(void* console, txString buffer, txInteger bufferSize, txString path)
2925
1.00M
{
2926
1.00M
  txMachine* the = console;
2927
1.00M
  if (path)
2928
0
    c_snprintf(buffer, bufferSize, "#%d@%s", (int)the->tag, path);
2929
1.00M
  else
2930
1.00M
    c_snprintf(buffer, bufferSize, "#%d", (int)the->tag);
2931
1.00M
  the->tag++;
2932
1.00M
}
2933
2934
void fxVReport(void* console, txString theFormat, c_va_list theArguments)
2935
90
{
2936
90
#ifdef mxDebug
2937
90
  txMachine* the = console;
2938
90
  if (fxIsConnected(the)) {
2939
0
    fxEchoStart(the);
2940
0
    fxEcho(the, "<log>");
2941
0
    fxEchoFormat(the, theFormat, theArguments);
2942
0
    fxEcho(the, "</log>");
2943
0
    fxEchoStop(the);
2944
0
  }
2945
#elif defined(nrf52) && defined(mxInstrument)
2946
  char buf[256];
2947
  vsnprintf(buf, 256, theFormat, theArguments);
2948
  modLog_transmit(buf);
2949
#elif defined(DEBUG_EFM)
2950
  memmove(_lastDebugStrBuffer, _debugStrBuffer, 256);
2951
  vsprintf(_debugStrBuffer, theFormat, theArguments);
2952
  _debugStrBuffer[255] = '\0';
2953
#endif
2954
90
}
2955
2956
void fxVReportException(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
2957
2.07M
{
2958
2.07M
#ifdef mxDebug
2959
2.07M
  txMachine* the = console;
2960
2.07M
  if (fxIsConnected(the)) {
2961
0
    fxEchoStart(the);
2962
0
    fxEcho(the, "<log");
2963
0
    fxEchoPathLine(the, thePath, theLine);
2964
0
    fxEcho(the, "># Exception: ");
2965
0
    fxEchoFormat(the, theFormat, theArguments);
2966
0
    fxEcho(the, "!\n</log>");
2967
0
    fxEchoStop(the);
2968
0
  }
2969
#elif defined(nrf52) && defined(mxInstrument)
2970
  char buf[256];
2971
  if (thePath && theLine)
2972
    c_snprintf(buf, 256, "%s:%d: exception: ", thePath, (int)theLine);
2973
  else
2974
    c_snprintf(buf, 256, "# exception: ");
2975
  modLog_transmit(buf);
2976
  c_snprintf(buf, 256, theFormat, theArguments);
2977
  modLog_transmit(buf);
2978
#elif defined(DEBUG_EFM)
2979
  if (thePath && theLine)
2980
    sprintf(_debugStrBuffer, "%s:%d: exception: ", thePath, (int)theLine);
2981
  else
2982
    sprintf(_debugStrBuffer, "# exception: ");
2983
  memmove(_lastDebugStrBuffer, _debugStrBuffer, 256);
2984
  vsprintf(_debugStrBuffer, theFormat, theArguments);
2985
  _debugStrBuffer[255] = '\0';
2986
#endif
2987
2.07M
}
2988
2989
void fxVReportError(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
2990
469k
{
2991
469k
#ifdef mxDebug
2992
469k
  txMachine* the = console;
2993
469k
  if (fxIsConnected(the)) {
2994
0
    fxEchoStart(the);
2995
0
    fxEcho(the, "<log");
2996
0
    fxEchoPathLine(the, thePath, theLine);
2997
0
    fxEcho(the, "># Error: ");
2998
0
    fxEchoFormat(the, theFormat, theArguments);
2999
0
    fxEcho(the, "!\n</log>");
3000
0
    fxEchoStop(the);
3001
0
  }
3002
#elif defined(nrf52) && defined(mxInstrument)
3003
  char buf[256];
3004
  if (thePath && theLine)
3005
    c_snprintf(buf, 256, "%s:%d: error: ", thePath, (int)theLine);
3006
  else
3007
    c_snprintf(buf, 256, "# error: ");
3008
  modLog_transmit(buf);
3009
  c_snprintf(buf, 256, theFormat, theArguments);
3010
  modLog_transmit(buf);
3011
#elif defined(DEBUG_EFM)
3012
  if (thePath && theLine)
3013
    sprintf(_debugStrBuffer, "%s:%d: error: ", thePath, (int)theLine);
3014
  else
3015
    sprintf(_debugStrBuffer, "# error: ");
3016
  vsprintf(_debugStrBuffer, theFormat, theArguments);
3017
  _debugStrBuffer[255] = '\0';
3018
#endif
3019
469k
}
3020
3021
void fxVReportWarning(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
3022
0
{
3023
0
#ifdef mxDebug
3024
0
  txMachine* the = console;
3025
0
  if (fxIsConnected(the)) {
3026
0
    fxEchoStart(the);
3027
0
    fxEcho(the, "<log");
3028
0
    fxEchoPathLine(the, thePath, theLine);
3029
0
    fxEcho(the, "># Warning: ");
3030
0
    fxEchoFormat(the, theFormat, theArguments);
3031
0
    fxEcho(the, "!\n</log>");
3032
0
    fxEchoStop(the);
3033
0
  }
3034
0
#endif
3035
#if defined(DEBUG_EFM)
3036
  if (thePath && theLine)
3037
    sprintf(_debugStrBuffer, "%s:%d: warning: ", thePath, (int)theLine);
3038
  else
3039
    sprintf(_debugStrBuffer, "# warning: ");
3040
  vsprintf(_debugStrBuffer, theFormat, theArguments);
3041
  _debugStrBuffer[255] = '\0';
3042
#endif
3043
0
}
3044
3045
#ifdef mxInstrument 
3046
#if kCPUESP32C6 || kCPUESP32H2
3047
#define ICACHE_XS6STRING_ATTR
3048
#endif
3049
#define xsInstrumentCount 12
3050
static char* const xsInstrumentNames[xsInstrumentCount] ICACHE_XS6STRING_ATTR = {
3051
  "Chunk used",
3052
  "Chunk available",
3053
  "Slot used",
3054
  "Slot available",
3055
  "Stack used",
3056
  "Stack available",
3057
  "Garbage collections",
3058
  "Keys used",
3059
  "Modules loaded",
3060
  "Parser used",
3061
  "Floating Point",
3062
  "Promises settled"
3063
};
3064
static char* const xsInstrumentUnits[xsInstrumentCount] ICACHE_XS6STRING_ATTR = {
3065
  " / ",
3066
  " bytes",
3067
  " / ",
3068
  " bytes",
3069
  " / ",
3070
  " bytes",
3071
  " times",
3072
  " keys",
3073
  " modules",
3074
  " bytes",
3075
  " operations",
3076
  " promises",
3077
};
3078
3079
void fxDescribeInstrumentation(txMachine* the, txInteger count, txString* names, txString* units)
3080
{
3081
  txInteger i, j = 0;
3082
#ifdef mxDebug
3083
  if (fxIsConnected(the)) {
3084
    fxEchoStart(the);
3085
    fxEcho(the, "<instruments>");
3086
    for (i = 0; i < count; i++, j++) {
3087
      fxEcho(the, "<instrument name=\"");
3088
      fxEchoString(the, names[i]);
3089
      fxEcho(the, "\" value=\"");
3090
      fxEchoString(the, units[i]);
3091
      fxEcho(the, "\"/>");
3092
    }
3093
    for (i = 0; i < xsInstrumentCount; i++, j++) {
3094
      fxEcho(the, "<instrument name=\"");
3095
      fxEchoString(the, (txString) xsInstrumentNames[i]);
3096
      fxEcho(the, "\" value=\"");
3097
      fxEchoString(the, (txString) xsInstrumentUnits[i]);
3098
      fxEcho(the, "\"/>");
3099
    }
3100
    fxEcho(the, "</instruments>");
3101
    fxEchoStop(the);
3102
    //fxReceive(the);
3103
    return;
3104
  }
3105
#endif
3106
#ifndef mxNoConsole
3107
#if !pebble
3108
  j = 0;
3109
  c_printf("instruments key: ");
3110
  for (i = 0; i < count; i++, j++) {
3111
    if (j)
3112
      c_printf(",");
3113
    c_printf("%s", names[i]);
3114
  }
3115
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3116
    if (j)
3117
      c_printf(",");
3118
    c_printf("%s", xsInstrumentNames[i]);
3119
  }
3120
  c_printf("\n");
3121
#else // pebble
3122
  j = 0;
3123
  modLog_transmit("instruments key: ");
3124
  for (i = 0; i < count; i++, j++) {
3125
    if (!names[i])
3126
      break;
3127
    if (j)
3128
      modLog_transmit(",");
3129
    modLog_transmit(names[i]);
3130
  }
3131
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3132
    if (j)
3133
      modLog_transmit(",");
3134
    modLog_transmit(xsInstrumentNames[i]);
3135
  }
3136
  modLog_transmit("\n");
3137
#endif
3138
#endif
3139
}
3140
3141
void fxSampleInstrumentation(txMachine* the, txInteger count, txInteger* values)
3142
{
3143
  txInteger xsInstrumentValues[xsInstrumentCount];
3144
  xsInstrumentValues[0] = the->currentChunksSize;
3145
  xsInstrumentValues[1] = the->maximumChunksSize;
3146
  xsInstrumentValues[2] = the->currentHeapCount * sizeof(txSlot);
3147
  xsInstrumentValues[3] = the->maximumHeapCount * sizeof(txSlot);
3148
  xsInstrumentValues[4] = (mxPtrDiff(the->stackTop - the->stackPeak)) * sizeof(txSlot);
3149
  xsInstrumentValues[5] = (mxPtrDiff(the->stackTop - the->stackBottom)) * sizeof(txSlot);
3150
  xsInstrumentValues[6] = the->garbageCollectionCount;
3151
  xsInstrumentValues[7] = the->keyIndex - the->keyOffset - the->keyholeCount;
3152
  xsInstrumentValues[8] = the->loadedModulesCount;
3153
  xsInstrumentValues[9] = the->peakParserSize;
3154
  xsInstrumentValues[10] = the->floatingPointOps;
3155
  xsInstrumentValues[11] = the->promisesSettledCount;
3156
3157
  txInteger i, j = 0;
3158
#ifdef mxDebug
3159
  if (fxIsConnected(the)) {
3160
    fxEchoStart(the);
3161
    fxEcho(the, "<samples>");
3162
    for (i = 0; i < count; i++, j++) {
3163
      if (j)
3164
        fxEcho(the, ",");
3165
      fxEchoInteger(the, values[i]);
3166
    }
3167
    for (i = 0; i < xsInstrumentCount; i++, j++) {
3168
      if (j)
3169
        fxEcho(the, ",");
3170
      fxEchoInteger(the, xsInstrumentValues[i]);
3171
    }
3172
    fxEcho(the, "</samples>");
3173
    fxEchoStop(the);
3174
    return;
3175
  }
3176
#endif
3177
#ifndef mxNoConsole
3178
#if !pebble
3179
  j = 0;
3180
  c_printf("instruments: ");
3181
  for (i = 0; i < count; i++, j++) {
3182
    if (j)
3183
      c_printf(",");
3184
    c_printf("%d", values[i]);
3185
  }
3186
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3187
    if (j)
3188
      c_printf(",");
3189
    c_printf("%d", xsInstrumentValues[i]);
3190
  }
3191
  c_printf("\n");
3192
#else // pebble
3193
  j = 0;
3194
  modLog_transmit("instruments: ");
3195
  for (i = 0; i < count; i++, j++) {
3196
    if (j)
3197
      modLog_transmit(",");
3198
    char tmp[10];
3199
    fxIntegerToString(the, (int)values[i], tmp, sizeof(tmp));
3200
    modLog_transmit(tmp);
3201
  }
3202
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3203
    if (j)
3204
      modLog_transmit(",");
3205
    char tmp[10];
3206
    fxIntegerToString(the, (int)xsInstrumentValues[i], tmp, sizeof(tmp));
3207
    modLog_transmit(tmp);
3208
  }
3209
  modLog_transmit("\n");
3210
#endif // pebble
3211
#endif
3212
}
3213
3214
#if defined(modMicrosecondsInstrumentation) || defined(modMicroseconds)
3215
  typedef txU4 txMicroseconds;
3216
#else
3217
  typedef txU8 txMicroseconds;
3218
#endif
3219
3220
#define mxProfilerSampleCount 8
3221
3222
typedef struct sxProfiler txProfiler;
3223
struct sxProfiler {
3224
  txMicroseconds when;
3225
  txMicroseconds former;
3226
//  txMicroseconds start;
3227
  txMicroseconds stop;
3228
  txU4 interval;
3229
  txSize recordCount;
3230
  txByte* records;
3231
  txSize sampleIndex;
3232
  txSize sampleSize;
3233
  txID* samples;
3234
  txU4 deltas[mxProfilerSampleCount];
3235
};
3236
3237
static void fxEchoUnsigned(txMachine* the, txUnsigned value, txInteger radix);
3238
static txID fxFrameToProfilerID(txMachine* the, txSlot* frame);
3239
static txMicroseconds fxGetMicroSeconds();
3240
static void fxSendProfilerRecord(txMachine* the, txSlot* frame, txID id, txSlot* code);
3241
static void fxSendProfilerSamples(txMachine* the, txProfiler* profiler);
3242
static void fxSendProfilerTime(txMachine* the, txString name, txMicroseconds when);
3243
3244
void fxCheckProfiler(txMachine* the, txSlot* frame)
3245
{
3246
  txProfiler* profiler = the->profiler;
3247
  if (!profiler)
3248
    return;
3249
  txMicroseconds when = profiler->when;
3250
  txMicroseconds time = fxGetMicroSeconds();
3251
  if (when <= time) {
3252
    txSize sampleIndex = profiler->sampleIndex;
3253
    txSize sampleSize = profiler->sampleSize;
3254
    txID* samples = profiler->samples + (sampleIndex * sampleSize);
3255
    txU4 interval = profiler->interval;
3256
    profiler->deltas[sampleIndex] = (txU4)(time - profiler->former);
3257
    profiler->former = time;
3258
    profiler->when = time + interval - (time % interval);
3259
    if (!frame) {
3260
      frame = the->frame;
3261
      if (frame)
3262
        *samples++ = 1;
3263
    }
3264
    while (frame) {
3265
      txID id = fxFrameToProfilerID(the, frame);
3266
      if (id)
3267
        *samples++ = id;
3268
      frame = frame->next;
3269
    }
3270
    *samples++ = 0;
3271
    sampleIndex++;
3272
    if (sampleIndex == mxProfilerSampleCount) {
3273
      fxSendProfilerSamples(the, profiler);
3274
      sampleIndex = 0;
3275
    }
3276
    profiler->sampleIndex = sampleIndex;
3277
  }
3278
}
3279
3280
void fxCreateProfiler(txMachine* the)
3281
{
3282
  txProfiler* profiler = the->profiler = c_malloc(sizeof(txProfiler));
3283
  if (profiler == C_NULL)
3284
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3285
  profiler->interval = 1250;
3286
  profiler->former = fxGetMicroSeconds();
3287
  profiler->when = profiler->former + profiler->interval;
3288
  
3289
  profiler->recordCount = 128;
3290
  profiler->records = c_calloc(1, profiler->recordCount);
3291
  if (profiler->records == C_NULL)
3292
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3293
3294
  profiler->sampleIndex = 0;
3295
  profiler->sampleSize = (the->stackTop - the->stackBottom) >> 3;
3296
  profiler->samples = (txID*)c_malloc((size_t)(mxProfilerSampleCount * profiler->sampleSize * sizeof(txID)));
3297
  if (profiler->samples == C_NULL)
3298
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3299
3300
  fxSendProfilerTime(the, "start", profiler->former);
3301
  fxSendProfilerRecord(the, C_NULL, 0, C_NULL);
3302
  fxSendProfilerRecord(the, C_NULL, 1, C_NULL);
3303
  profiler->records[0] = 0x03;
3304
}
3305
3306
void fxDeleteProfiler(txMachine* the, void* stream)
3307
{
3308
  txProfiler* profiler = the->profiler;
3309
  fxSendProfilerTime(the, "stop", fxGetMicroSeconds());
3310
  c_free(profiler->samples);
3311
  c_free(profiler->records);
3312
  c_free(profiler);
3313
  the->profiler = C_NULL;
3314
}
3315
3316
#ifdef mxDebug
3317
void fxEchoUnsigned(txMachine* the, txUnsigned value, txInteger radix)
3318
{
3319
  char buffer[256];
3320
  char *p = &buffer[sizeof(buffer) - 1];
3321
  *p-- = 0;
3322
  do {
3323
    *p-- = c_read8(gxHexaDigits + (value % radix));
3324
    value /= radix;
3325
  } while (value);
3326
  fxEcho(the, p + 1);
3327
}
3328
#endif
3329
3330
txID fxFrameToProfilerID(txMachine* the, txSlot* frame)
3331
{
3332
  txProfiler* profiler = the->profiler;
3333
  txSlot* function = frame + 2;
3334
  txSlot* code = C_NULL;
3335
  txID id = XS_NO_ID;
3336
  if (function->kind == XS_REFERENCE_KIND) {
3337
    function = function->value.reference;
3338
    if (mxIsFunction(function)) {
3339
      code = mxFunctionInstanceCode(function);
3340
      id = mxFunctionInstanceHome(function)->ID;
3341
    }
3342
  }
3343
#if mxHostFunctionPrimitive
3344
  else if (function->kind == XS_HOST_FUNCTION_KIND)
3345
    id = function->value.hostFunction.profileID;
3346
#endif
3347
  if (id != XS_NO_ID) {   
3348
    txInteger recordIndex = id >> 3;
3349
    txInteger recordMask = 1 << (id & 0x07);
3350
    txInteger recordCount = profiler->recordCount;
3351
    if (recordIndex >= recordCount) {
3352
      while (recordIndex >= recordCount)
3353
        recordCount += 128;
3354
      profiler->records = c_realloc(profiler->records, recordCount);
3355
      if (profiler->records == C_NULL)
3356
        fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3357
      c_memset(profiler->records + profiler->recordCount, 0, (recordCount - profiler->recordCount));
3358
      profiler->recordCount = recordCount;
3359
    }
3360
    else if (profiler->records[recordIndex] & recordMask)
3361
      return id;
3362
    profiler->records[recordIndex] |= recordMask;
3363
    fxSendProfilerRecord(the, frame, id, code);
3364
    return id;
3365
  }
3366
  return 0;
3367
}
3368
3369
txMicroseconds fxGetMicroSeconds()
3370
{
3371
#if defined(modMicrosecondsInstrumentation)
3372
  return modMicrosecondsInstrumentation();
3373
#elif defined(modMicroseconds)
3374
  return modMicroseconds();
3375
#else
3376
  c_timeval tv;
3377
  c_gettimeofday(&tv, NULL);
3378
  return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
3379
#endif
3380
}
3381
3382
void fxResumeProfiler(txMachine* the)
3383
{
3384
  txProfiler* profiler = the->profiler;
3385
  if (!profiler)
3386
    return;
3387
  txMicroseconds delta = fxGetMicroSeconds();
3388
  fxSendProfilerTime(the, "resume", delta);
3389
  delta -= profiler->stop;
3390
  profiler->when += delta;
3391
  profiler->former += delta;
3392
}
3393
3394
void fxSendProfilerRecord(txMachine* the, txSlot* frame, txID id, txSlot* code)
3395
{
3396
#ifdef mxDebug
3397
  if (fxIsConnected(the)) {
3398
    fxEchoStart(the);
3399
    if (id == 0) {
3400
      fxEcho(the, "<pr name=\"(host)\" value=\"0\"");
3401
    }
3402
    else if (id == 1) {
3403
      fxEcho(the, "<pr name=\"(gc)\" value=\"1\"");
3404
    }
3405
    else {
3406
      fxEcho(the, "<pr name=\"");
3407
      fxEchoFrameName(the, frame);
3408
      fxEcho(the, "\" value=\"");
3409
      fxEchoInteger(the, id);
3410
      fxEcho(the, "\"");
3411
    }
3412
    if (code) {
3413
      if ((code->kind == XS_CODE_KIND) || (code->kind == XS_CODE_X_KIND)) {
3414
        txByte* p = code->value.code.address + 2;
3415
        if (*p == XS_CODE_FILE) {
3416
          txID file;
3417
          txS2 line;
3418
          p++;
3419
          mxDecodeID(p, file);
3420
          p++;
3421
          mxDecode2(p, line);
3422
          fxEchoPathLine(the, fxGetKeyName(the, file), line);
3423
        }
3424
      }
3425
    }
3426
    fxEcho(the, "/>");
3427
    fxEchoStop(the);
3428
  }
3429
#endif
3430
}
3431
3432
void fxSendProfilerSamples(txMachine* the, txProfiler* profiler)
3433
{
3434
#ifdef mxDebug
3435
  if (fxIsConnected(the)) {
3436
    txID* samples = profiler->samples;
3437
    txSize sampleSize = profiler->sampleSize;
3438
    txSize sampleIndex = 0;
3439
    txID* ids;
3440
    txID id;
3441
    fxEchoStart(the);
3442
    fxEcho(the, "<ps>");
3443
    for (;;) {
3444
      fxEchoUnsigned(the, profiler->deltas[sampleIndex], 36);
3445
      ids = samples;
3446
      while ((id = *ids++)) {
3447
        fxEcho(the, ",");
3448
        fxEchoUnsigned(the, id, 36);
3449
      }
3450
      sampleIndex++;
3451
      if (sampleIndex < mxProfilerSampleCount) 
3452
        fxEcho(the, ",0.");
3453
      else {
3454
        fxEcho(the, ",0</ps>");
3455
        break;
3456
      }
3457
      samples += sampleSize;
3458
    }
3459
    fxEchoStop(the);
3460
  }
3461
#endif
3462
}
3463
3464
void fxSendProfilerTime(txMachine* the, txString name, txMicroseconds when)
3465
{
3466
#ifdef mxDebug
3467
  if (fxIsConnected(the)) {
3468
    int shift;
3469
    fxEchoStart(the);
3470
    fxEcho(the, "<pt name=\"");
3471
    fxEchoString(the, name);
3472
    fxEcho(the, "\" value=\"@");
3473
    shift = (8 * sizeof(when)) - 4;
3474
    while (shift >= 0) {
3475
      fxEchoCharacter(the, c_read8(gxHexaDigits + ((when >> shift) & 0x0F)));
3476
      shift -= 4;
3477
    }
3478
    fxEcho(the, "\"/>");
3479
    fxEchoStop(the);
3480
  }
3481
#endif
3482
}
3483
3484
void fxSuspendProfiler(txMachine* the)
3485
{
3486
  txProfiler* profiler = the->profiler;
3487
  if (!profiler)
3488
    return;
3489
  profiler->stop = fxGetMicroSeconds();
3490
  fxSendProfilerTime(the, "suspend", profiler->stop);
3491
}
3492
3493
#endif /* mxInstrument */