Coverage Report

Created: 2026-08-14 06:15

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
0
{
610
0
  txSlot* frame;
611
0
  if (!fxIsConnected(the))
612
0
    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
      /* fall through */
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
      /* fall through */
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
      /* fall through */
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
4.86k
{
1222
4.86k
  if (the->debugEval)
1223
0
    return;
1224
4.86k
  if (fxIsConnected(the) && (the->breakOnExceptionsFlag))
1225
0
    fxDebugLoop(the, path, line, message);
1226
4.86k
  else {
1227
4.86k
    txSlot* frame = the->frame;
1228
14.5k
    while (frame && !path) {
1229
9.72k
      txSlot* environment = mxFrameToEnvironment(frame);
1230
9.72k
      if (environment->ID != XS_NO_ID) {
1231
0
        path = fxGetKeyName(the, environment->ID);
1232
0
        line = environment->value.environment.line;
1233
0
      }
1234
9.72k
      frame = frame->next;
1235
9.72k
    }
1236
4.86k
    fxReportException(the, path, line, "%s", message);
1237
4.86k
  }
1238
4.86k
}
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
6.51k
{
2507
6.51k
  if (!fxIsConnected(the)) {
2508
6.51k
    fxConnect(the);
2509
6.51k
    if (!fxIsConnected(the))
2510
6.51k
      return;
2511
6.51k
  }
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
6.51k
{
2558
6.51k
  if (!fxIsConnected(the))
2559
6.51k
    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
0
{
2829
0
  c_va_list arguments;
2830
2831
0
  c_va_start(arguments, theFormat);
2832
0
  fxVReport(the, theFormat, arguments);
2833
0
  c_va_end(arguments);
2834
#ifndef mxNoConsole
2835
  c_va_start(arguments, theFormat);
2836
  c_vprintf(theFormat, arguments);
2837
  c_va_end(arguments);
2838
#elif pebble
2839
#ifdef mxDebug
2840
  if (!fxIsConnected(the)) {
2841
#endif
2842
    char buffer[128];
2843
    c_vsnprintf(buffer, sizeof(buffer), theFormat, arguments);
2844
    modLog_transmit(buffer);
2845
#ifdef mxDebug
2846
  }
2847
#endif
2848
#endif /* pebble */
2849
0
}
2850
2851
void fxReportException(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2852
4.86k
{
2853
4.86k
  c_va_list arguments;
2854
2855
4.86k
  c_va_start(arguments, theFormat);
2856
4.86k
  fxVReportException(the, thePath, theLine, theFormat, arguments);
2857
4.86k
  c_va_end(arguments);
2858
#ifndef mxNoConsole
2859
  if (thePath && theLine)
2860
#if mxWindows
2861
    printf("%s(%d): exception: ", thePath, (int)theLine);
2862
#else
2863
    c_printf("%s:%d: exception: ", thePath, (int)theLine);
2864
#endif
2865
  else
2866
    c_printf("# exception: ");
2867
  c_va_start(arguments, theFormat);
2868
  c_vprintf(theFormat, arguments);
2869
  c_va_end(arguments);
2870
  c_printf("!\n");
2871
#endif
2872
4.86k
}
2873
2874
void fxReportError(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2875
0
{
2876
0
  c_va_list arguments;
2877
2878
0
  c_va_start(arguments, theFormat);
2879
0
  fxVReportError(the, thePath, theLine, theFormat, arguments);
2880
0
  c_va_end(arguments);
2881
#ifndef mxNoConsole
2882
  if (thePath && theLine)
2883
#if mxWindows
2884
    printf("%s(%d): error: ", thePath, (int)theLine);
2885
#else
2886
    c_printf("%s:%d: error: ", thePath, (int)theLine);
2887
#endif
2888
  else
2889
    c_printf("# error: ");
2890
  c_va_start(arguments, theFormat);
2891
  c_vprintf(theFormat, arguments);
2892
  c_va_end(arguments);
2893
  c_printf("!\n");
2894
#endif
2895
0
}
2896
2897
void fxReportWarning(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2898
0
{
2899
0
  c_va_list arguments;
2900
2901
0
  c_va_start(arguments, theFormat);
2902
0
  fxVReportWarning(the, thePath, theLine, theFormat, arguments);
2903
0
  c_va_end(arguments);
2904
#ifndef mxNoConsole
2905
  if (thePath && theLine)
2906
#if mxWindows
2907
    printf("%s(%d): warning: ", thePath, (int)theLine);
2908
#else
2909
    c_printf("%s:%d: warning: ", thePath, (int)theLine);
2910
#endif
2911
  else
2912
    c_printf("# warning: ");
2913
  c_va_start(arguments, theFormat);
2914
  c_vprintf(theFormat, arguments);
2915
  c_va_end(arguments);
2916
  c_printf("!\n");
2917
#endif
2918
0
}
2919
2920
txID fxGenerateProfileID(void* console)
2921
3.87M
{
2922
3.87M
  txMachine* the = console;
2923
3.87M
  txID id = the->profileID;
2924
3.87M
  the->profileID++;
2925
3.87M
  return id;
2926
3.87M
}
2927
2928
void fxGenerateTag(void* console, txString buffer, txInteger bufferSize, txString path)
2929
0
{
2930
0
  txMachine* the = console;
2931
0
  if (path)
2932
0
    c_snprintf(buffer, bufferSize, "#%d@%s", (int)the->tag, path);
2933
0
  else
2934
0
    c_snprintf(buffer, bufferSize, "#%d", (int)the->tag);
2935
0
  the->tag++;
2936
0
}
2937
2938
void fxVReport(void* console, txString theFormat, c_va_list theArguments)
2939
0
{
2940
0
#ifdef mxDebug
2941
0
  txMachine* the = console;
2942
0
  if (fxIsConnected(the)) {
2943
0
    fxEchoStart(the);
2944
0
    fxEcho(the, "<log>");
2945
0
    fxEchoFormat(the, theFormat, theArguments);
2946
0
    fxEcho(the, "</log>");
2947
0
    fxEchoStop(the);
2948
0
  }
2949
#elif defined(nrf52) && defined(mxInstrument)
2950
  char buf[256];
2951
  vsnprintf(buf, 256, theFormat, theArguments);
2952
  modLog_transmit(buf);
2953
#elif defined(DEBUG_EFM)
2954
  memmove(_lastDebugStrBuffer, _debugStrBuffer, 256);
2955
  vsprintf(_debugStrBuffer, theFormat, theArguments);
2956
  _debugStrBuffer[255] = '\0';
2957
#endif
2958
0
}
2959
2960
void fxVReportException(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
2961
4.86k
{
2962
4.86k
#ifdef mxDebug
2963
4.86k
  txMachine* the = console;
2964
4.86k
  if (fxIsConnected(the)) {
2965
0
    fxEchoStart(the);
2966
0
    fxEcho(the, "<log");
2967
0
    fxEchoPathLine(the, thePath, theLine);
2968
0
    fxEcho(the, "># Exception: ");
2969
0
    fxEchoFormat(the, theFormat, theArguments);
2970
0
    fxEcho(the, "!\n</log>");
2971
0
    fxEchoStop(the);
2972
0
  }
2973
#elif defined(nrf52) && defined(mxInstrument)
2974
  char buf[256];
2975
  if (thePath && theLine)
2976
    c_snprintf(buf, 256, "%s:%d: exception: ", thePath, (int)theLine);
2977
  else
2978
    c_snprintf(buf, 256, "# exception: ");
2979
  modLog_transmit(buf);
2980
  c_snprintf(buf, 256, theFormat, theArguments);
2981
  modLog_transmit(buf);
2982
#elif defined(DEBUG_EFM)
2983
  if (thePath && theLine)
2984
    sprintf(_debugStrBuffer, "%s:%d: exception: ", thePath, (int)theLine);
2985
  else
2986
    sprintf(_debugStrBuffer, "# exception: ");
2987
  memmove(_lastDebugStrBuffer, _debugStrBuffer, 256);
2988
  vsprintf(_debugStrBuffer, theFormat, theArguments);
2989
  _debugStrBuffer[255] = '\0';
2990
#endif
2991
4.86k
}
2992
2993
void fxVReportError(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
2994
0
{
2995
0
#ifdef mxDebug
2996
0
  txMachine* the = console;
2997
0
  if (fxIsConnected(the)) {
2998
0
    fxEchoStart(the);
2999
0
    fxEcho(the, "<log");
3000
0
    fxEchoPathLine(the, thePath, theLine);
3001
0
    fxEcho(the, "># Error: ");
3002
0
    fxEchoFormat(the, theFormat, theArguments);
3003
0
    fxEcho(the, "!\n</log>");
3004
0
    fxEchoStop(the);
3005
0
  }
3006
#elif defined(nrf52) && defined(mxInstrument)
3007
  char buf[256];
3008
  if (thePath && theLine)
3009
    c_snprintf(buf, 256, "%s:%d: error: ", thePath, (int)theLine);
3010
  else
3011
    c_snprintf(buf, 256, "# error: ");
3012
  modLog_transmit(buf);
3013
  c_snprintf(buf, 256, theFormat, theArguments);
3014
  modLog_transmit(buf);
3015
#elif defined(DEBUG_EFM)
3016
  if (thePath && theLine)
3017
    sprintf(_debugStrBuffer, "%s:%d: error: ", thePath, (int)theLine);
3018
  else
3019
    sprintf(_debugStrBuffer, "# error: ");
3020
  vsprintf(_debugStrBuffer, theFormat, theArguments);
3021
  _debugStrBuffer[255] = '\0';
3022
#endif
3023
0
}
3024
3025
void fxVReportWarning(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
3026
0
{
3027
0
#ifdef mxDebug
3028
0
  txMachine* the = console;
3029
0
  if (fxIsConnected(the)) {
3030
0
    fxEchoStart(the);
3031
0
    fxEcho(the, "<log");
3032
0
    fxEchoPathLine(the, thePath, theLine);
3033
0
    fxEcho(the, "># Warning: ");
3034
0
    fxEchoFormat(the, theFormat, theArguments);
3035
0
    fxEcho(the, "!\n</log>");
3036
0
    fxEchoStop(the);
3037
0
  }
3038
0
#endif
3039
#if defined(DEBUG_EFM)
3040
  if (thePath && theLine)
3041
    sprintf(_debugStrBuffer, "%s:%d: warning: ", thePath, (int)theLine);
3042
  else
3043
    sprintf(_debugStrBuffer, "# warning: ");
3044
  vsprintf(_debugStrBuffer, theFormat, theArguments);
3045
  _debugStrBuffer[255] = '\0';
3046
#endif
3047
0
}
3048
3049
#ifdef mxInstrument 
3050
#if kCPUESP32C6 || kCPUESP32H2 || kCPUESP32P4 || kCPUESP32C5
3051
#define ICACHE_XS6STRING_ATTR
3052
#endif
3053
#define xsInstrumentCount 12
3054
static char* const xsInstrumentNames[xsInstrumentCount] ICACHE_XS6STRING_ATTR = {
3055
  "Chunk used",
3056
  "Chunk available",
3057
  "Slot used",
3058
  "Slot available",
3059
  "Stack used",
3060
  "Stack available",
3061
  "Garbage collections",
3062
  "Keys used",
3063
  "Modules loaded",
3064
  "Parser used",
3065
  "Floating Point",
3066
  "Promises settled"
3067
};
3068
static char* const xsInstrumentUnits[xsInstrumentCount] ICACHE_XS6STRING_ATTR = {
3069
  " / ",
3070
  " bytes",
3071
  " / ",
3072
  " bytes",
3073
  " / ",
3074
  " bytes",
3075
  " times",
3076
  " keys",
3077
  " modules",
3078
  " bytes",
3079
  " operations",
3080
  " promises",
3081
};
3082
3083
void fxDescribeInstrumentation(txMachine* the, txInteger count, txString* names, txString* units)
3084
{
3085
  txInteger i, j = 0;
3086
#ifdef mxDebug
3087
  if (fxIsConnected(the)) {
3088
    fxEchoStart(the);
3089
    fxEcho(the, "<instruments>");
3090
    for (i = 0; i < count; i++, j++) {
3091
      fxEcho(the, "<instrument name=\"");
3092
      fxEchoString(the, names[i]);
3093
      fxEcho(the, "\" value=\"");
3094
      fxEchoString(the, units[i]);
3095
      fxEcho(the, "\"/>");
3096
    }
3097
    for (i = 0; i < xsInstrumentCount; i++, j++) {
3098
      fxEcho(the, "<instrument name=\"");
3099
      fxEchoString(the, (txString) xsInstrumentNames[i]);
3100
      fxEcho(the, "\" value=\"");
3101
      fxEchoString(the, (txString) xsInstrumentUnits[i]);
3102
      fxEcho(the, "\"/>");
3103
    }
3104
    fxEcho(the, "</instruments>");
3105
    fxEchoStop(the);
3106
    //fxReceive(the);
3107
    return;
3108
  }
3109
#endif
3110
#ifndef mxNoConsole
3111
  j = 0;
3112
  c_printf("instruments key: ");
3113
  for (i = 0; i < count; i++, j++) {
3114
    if (j)
3115
      c_printf(",");
3116
    c_printf("%s", names[i]);
3117
  }
3118
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3119
    if (j)
3120
      c_printf(",");
3121
    c_printf("%s", xsInstrumentNames[i]);
3122
  }
3123
  c_printf("\n");
3124
#elif pebble
3125
  j = 0;
3126
  modLog_transmit("instruments key: ");
3127
  for (i = 0; i < count; i++, j++) {
3128
    if (!names[i])
3129
      break;
3130
    if (j)
3131
      modLog_transmit(",");
3132
    modLog_transmit(names[i]);
3133
  }
3134
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3135
    if (j)
3136
      modLog_transmit(",");
3137
    modLog_transmit(xsInstrumentNames[i]);
3138
  }
3139
  modLog_transmit("\n");
3140
#endif
3141
}
3142
3143
void fxSampleInstrumentation(txMachine* the, txInteger count, txInteger* values)
3144
{
3145
  txInteger xsInstrumentValues[xsInstrumentCount];
3146
  xsInstrumentValues[0] = the->currentChunksSize;
3147
  xsInstrumentValues[1] = the->maximumChunksSize;
3148
  xsInstrumentValues[2] = the->currentHeapCount * sizeof(txSlot);
3149
  xsInstrumentValues[3] = the->maximumHeapCount * sizeof(txSlot);
3150
  xsInstrumentValues[4] = (mxPtrDiff(the->stackTop - the->stackPeak)) * sizeof(txSlot);
3151
  xsInstrumentValues[5] = (mxPtrDiff(the->stackTop - the->stackBottom)) * sizeof(txSlot);
3152
  xsInstrumentValues[6] = the->garbageCollectionCount;
3153
  xsInstrumentValues[7] = the->keyIndex - the->keyOffset - the->keyholeCount;
3154
  xsInstrumentValues[8] = the->loadedModulesCount;
3155
  xsInstrumentValues[9] = the->peakParserSize;
3156
  xsInstrumentValues[10] = the->floatingPointOps;
3157
  xsInstrumentValues[11] = the->promisesSettledCount;
3158
3159
  txInteger i, j = 0;
3160
#ifdef mxDebug
3161
  if (fxIsConnected(the)) {
3162
    fxEchoStart(the);
3163
    fxEcho(the, "<samples>");
3164
    for (i = 0; i < count; i++, j++) {
3165
      if (j)
3166
        fxEcho(the, ",");
3167
      fxEchoInteger(the, values[i]);
3168
    }
3169
    for (i = 0; i < xsInstrumentCount; i++, j++) {
3170
      if (j)
3171
        fxEcho(the, ",");
3172
      fxEchoInteger(the, xsInstrumentValues[i]);
3173
    }
3174
    fxEcho(the, "</samples>");
3175
    fxEchoStop(the);
3176
    return;
3177
  }
3178
#endif
3179
#ifndef mxNoConsole
3180
  j = 0;
3181
  c_printf("instruments: ");
3182
  for (i = 0; i < count; i++, j++) {
3183
    if (j)
3184
      c_printf(",");
3185
    c_printf("%d", (int)values[i]);
3186
  }
3187
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3188
    if (j)
3189
      c_printf(",");
3190
    c_printf("%d", (int)xsInstrumentValues[i]);
3191
  }
3192
  c_printf("\n");
3193
#elif pebble
3194
  j = 0;
3195
  modLog_transmit("instruments: ");
3196
  for (i = 0; i < count; i++, j++) {
3197
    if (j)
3198
      modLog_transmit(",");
3199
    char tmp[10];
3200
    fxIntegerToString(the, (int)values[i], tmp, sizeof(tmp));
3201
    modLog_transmit(tmp);
3202
  }
3203
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3204
    if (j)
3205
      modLog_transmit(",");
3206
    char tmp[10];
3207
    fxIntegerToString(the, (int)xsInstrumentValues[i], tmp, sizeof(tmp));
3208
    modLog_transmit(tmp);
3209
  }
3210
  modLog_transmit("\n");
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 */