Coverage Report

Created: 2025-09-04 06:38

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