Coverage Report

Created: 2025-02-15 06:24

/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
1.61k
{
614
1.61k
  txSlot* frame;
615
1.61k
  if (!fxIsConnected(the))
616
1.61k
    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.66M
{
1226
2.66M
  if (the->debugEval)
1227
0
    return;
1228
2.66M
  if (fxIsConnected(the) && (the->breakOnExceptionsFlag))
1229
0
    fxDebugLoop(the, path, line, message);
1230
2.66M
  else {
1231
2.66M
    txSlot* frame = the->frame;
1232
7.52M
    while (frame && !path) {
1233
4.85M
      txSlot* environment = mxFrameToEnvironment(frame);
1234
4.85M
      if (environment->ID != XS_NO_ID) {
1235
2.65M
        path = fxGetKeyName(the, environment->ID);
1236
2.65M
        line = environment->value.environment.line;
1237
2.65M
      }
1238
4.85M
      frame = frame->next;
1239
4.85M
    }
1240
2.66M
    fxReportException(the, path, line, "%s", message);
1241
2.66M
  }
1242
2.66M
}
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
      switch (internal->value.error.which) {
1377
0
      case XS_UNKNOWN_ERROR: fxEcho(the, "Error"); break;
1378
0
      case XS_EVAL_ERROR: fxEcho(the, "EvalError"); break;
1379
0
      case XS_RANGE_ERROR: fxEcho(the, "RangeError"); break;
1380
0
      case XS_REFERENCE_ERROR: fxEcho(the, "ReferenceError"); break;
1381
0
      case XS_SYNTAX_ERROR: fxEcho(the, "SyntaxError"); break;
1382
0
      case XS_TYPE_ERROR: fxEcho(the, "TypeError"); break;
1383
0
      case XS_URI_ERROR: fxEcho(the, "URIError"); break;
1384
0
      case XS_AGGREGATE_ERROR: fxEcho(the, "AggregateError"); break;
1385
0
      case XS_SUPPRESSED_ERROR: fxEcho(the, "SuppressedError"); break;
1386
0
      }
1387
0
      fxEcho(the, ": ");
1388
0
      internal = internal->next;
1389
0
      if (internal && ((internal->kind == XS_STRING_KIND) || (internal->kind == XS_STRING_X_KIND))) {
1390
0
        fxEchoString(the, internal->value.string);
1391
0
      }
1392
0
    }
1393
0
    else {
1394
0
      fxEcho(the, "(");
1395
0
      if (instance->flag & XS_CAN_CALL_FLAG)
1396
0
        fxEcho(the, mxFunctionString.value.string);
1397
0
      else
1398
0
        fxEcho(the, mxObjectString.value.string);
1399
0
      fxEcho(the, ")");
1400
0
    }
1401
0
    } break;
1402
0
  case XS_UNDEFINED_KIND:
1403
0
    fxEcho(the, "undefined");
1404
0
    break;
1405
0
  case XS_NULL_KIND:
1406
0
    fxEcho(the, "null");
1407
0
    break;
1408
0
  case XS_BOOLEAN_KIND:
1409
0
    if (exception->value.boolean)
1410
0
      fxEcho(the, "true");
1411
0
    else
1412
0
      fxEcho(the, "false");
1413
0
    break;
1414
0
  case XS_INTEGER_KIND:
1415
0
    fxEchoInteger(the, exception->value.integer);
1416
0
    break;
1417
0
  case XS_NUMBER_KIND:
1418
0
    fxEchoNumber(the, exception->value.number);
1419
0
    break;
1420
0
  case XS_STRING_KIND:
1421
0
  case XS_STRING_X_KIND:
1422
0
    fxEchoString(the, exception->value.string);
1423
0
    break;
1424
0
  case XS_SYMBOL_KIND:
1425
0
    fxEcho(the, "Symbol(");
1426
0
    fxEchoString(the, fxGetKeyString(the, exception->value.symbol, C_NULL));
1427
0
    fxEcho(the, ")\"/>");
1428
0
    break;
1429
0
  case XS_BIGINT_KIND:
1430
0
  case XS_BIGINT_X_KIND:
1431
0
    fxEchoBigInt(the, &exception->value.bigint);
1432
0
    break;
1433
0
  }
1434
0
}
1435
1436
void fxEchoFlags(txMachine* the, txString state, txFlag flag)
1437
0
{
1438
0
  fxEcho(the, " flags=\"");
1439
0
  fxEcho(the, state);
1440
0
  if (flag & XS_DONT_DELETE_FLAG)
1441
0
    fxEcho(the, "C");
1442
0
  else
1443
0
    fxEcho(the, "c");
1444
0
  if (flag & XS_DONT_ENUM_FLAG)
1445
0
    fxEcho(the, "E");
1446
0
  else
1447
0
    fxEcho(the, "e");
1448
0
  if (flag & XS_DONT_SET_FLAG)
1449
0
    fxEcho(the, "W");
1450
0
  else
1451
0
    fxEcho(the, "w");
1452
0
  if (flag & XS_INSPECTOR_FLAG)
1453
0
    fxEcho(the, "I");
1454
0
  else if (flag & XS_MARK_FLAG)
1455
0
    fxEcho(the, "M");
1456
0
  else
1457
0
    fxEcho(the, "_");
1458
0
  fxEcho(the, "\"");
1459
0
}
1460
1461
void fxEchoFormat(txMachine* the, txString theFormat, c_va_list theArguments)
1462
0
{
1463
0
  char *p, c;
1464
1465
0
  p = theFormat;
1466
0
  while ((c = c_read8(p++))) {
1467
0
    if (c != '%')
1468
0
      fxEchoCharacter(the, c);
1469
0
    else {
1470
0
      if (c_strncmp(p, "c", 1) == 0) {
1471
0
        fxEchoCharacter(the, c_va_arg(theArguments, int));
1472
0
        p++;
1473
0
      }
1474
0
      else if (c_strncmp(p, "hd", 2) == 0) {
1475
0
        fxEchoInteger(the, c_va_arg(theArguments, int));
1476
0
        p += 2;
1477
0
      }
1478
0
      else if (c_strncmp(p, "d", 1) == 0) {
1479
0
        fxEchoInteger(the, c_va_arg(theArguments, int));
1480
0
        p++;
1481
0
      }
1482
0
      else if (c_strncmp(p, "ld", 2) == 0) {
1483
0
        fxEchoInteger(the, c_va_arg(theArguments, long));
1484
0
        p += 2;
1485
0
      }
1486
0
      else if (c_strncmp(p, "g", 1) == 0) {
1487
0
        fxEchoNumber(the, c_va_arg(theArguments, double));
1488
0
        p++;
1489
0
      }
1490
0
      else if (c_strncmp(p, "s", 1) == 0) {
1491
0
        char *s = c_va_arg(theArguments, char *);
1492
0
        fxEchoString(the, s);
1493
0
        p++;
1494
0
      }
1495
0
      else {
1496
0
        fxEchoCharacter(the, c);
1497
0
        p++;
1498
0
      }
1499
0
    }
1500
0
  }
1501
0
}
1502
1503
void fxEchoFrameName(txMachine* the, txSlot* theFrame)
1504
0
{
1505
0
  char buffer[128] = "";
1506
0
  fxBufferFrameName(the, buffer, sizeof(buffer), theFrame, "");
1507
0
  fxEcho(the, buffer);
1508
0
}
1509
1510
void fxEchoFramePathLine(txMachine* the, txSlot* theFrame)
1511
0
{
1512
0
  if (theFrame) {
1513
0
    txSlot* environment = mxFrameToEnvironment(theFrame);
1514
0
    if (environment->ID != XS_NO_ID)
1515
0
      fxEchoPathLine(the, fxGetKeyName(the, environment->ID), environment->value.environment.line);
1516
0
  }
1517
0
}
1518
1519
void fxEchoInteger(txMachine* the, txInteger theInteger)
1520
0
{
1521
0
  char aBuffer[256];
1522
1523
0
  fxIntegerToString(the, theInteger, aBuffer, sizeof(aBuffer));
1524
0
  fxEcho(the, aBuffer);
1525
0
}
1526
1527
void fxEchoInstance(txMachine* the, txSlot* theInstance, txInspectorNameList* theList)
1528
0
{
1529
0
  txSlot* aParent;
1530
0
  txSlot* aProperty;
1531
0
  txSlot* aSlot;
1532
0
  txInteger anIndex;
1533
1534
#if mxAliasInstance
1535
  if (theInstance->ID) {
1536
    txSlot* aliasInstance = the->aliasArray[theInstance->ID];
1537
    if (aliasInstance)
1538
      theInstance = aliasInstance;
1539
  }
1540
#endif
1541
0
  aParent = fxGetPrototype(the, theInstance);
1542
0
  if (aParent)
1543
0
    fxEchoPropertyInstance(the, theList, "(..)", -1, C_NULL, XS_NO_ID, theInstance->flag & XS_MARK_FLAG, aParent);
1544
0
  aProperty = theInstance->next;
1545
0
  if (aProperty && (aProperty->flag & XS_INTERNAL_FLAG) && (aProperty->ID == XS_ARRAY_BEHAVIOR)) {
1546
0
    fxEchoProperty(the, aProperty, theList, "(array)", -1, C_NULL);
1547
0
  }
1548
0
  else if (aProperty && (aProperty->flag & XS_INTERNAL_FLAG)) {
1549
0
    switch (aProperty->kind) {
1550
0
    case XS_CALLBACK_KIND:
1551
0
    case XS_CALLBACK_X_KIND:
1552
0
    case XS_CODE_KIND:
1553
0
    case XS_CODE_X_KIND:
1554
0
      if (aProperty->value.code.closures)
1555
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);
1556
0
      fxEchoProperty(the, aProperty, theList, "(function)", -1, C_NULL);
1557
0
      aProperty = aProperty->next;
1558
0
      if ((aProperty->kind == XS_HOME_KIND) && (aProperty->value.home.object))
1559
0
        fxEchoPropertyInstance(the, theList, "(home)", -1, C_NULL, XS_NO_ID, aProperty->flag, aProperty->value.home.object);
1560
0
      aProperty = aProperty->next;
1561
0
      break;
1562
0
    case XS_ARRAY_BUFFER_KIND:
1563
0
      fxEchoArrayBuffer(the, theInstance, theList);
1564
0
      aProperty = aProperty->next;
1565
0
      fxEchoProperty(the, aProperty, theList, "(buffer)", -1, C_NULL);
1566
0
      aProperty = aProperty->next;
1567
0
      break;
1568
0
    case XS_STRING_KIND:
1569
0
    case XS_STRING_X_KIND:
1570
0
      fxEchoProperty(the, aProperty, theList, "(string)", -1, C_NULL);
1571
0
      aProperty = aProperty->next;
1572
0
      break;
1573
0
    case XS_BOOLEAN_KIND:
1574
0
      fxEchoProperty(the, aProperty, theList, "(boolean)", -1, C_NULL);
1575
0
      aProperty = aProperty->next;
1576
0
      break;
1577
0
    case XS_NUMBER_KIND:
1578
0
      fxEchoProperty(the, aProperty, theList, "(number)", -1, C_NULL);
1579
0
      aProperty = aProperty->next;
1580
0
      break;
1581
0
    case XS_BIGINT_KIND:
1582
0
    case XS_BIGINT_X_KIND:
1583
0
      fxEchoProperty(the, aProperty, theList, "(bigint)", -1, C_NULL);
1584
0
      aProperty = aProperty->next;
1585
0
      break;
1586
0
    case XS_DATA_VIEW_KIND:
1587
0
      fxEchoProperty(the, aProperty, theList, "(view)", -1, C_NULL);
1588
0
      aProperty = aProperty->next;
1589
0
      fxEchoProperty(the, aProperty, theList, "(data)", -1, C_NULL);
1590
0
      aProperty = aProperty->next;
1591
0
      break;
1592
0
    case XS_DATE_KIND:
1593
0
      fxEchoProperty(the, aProperty, theList, "(date)", -1, C_NULL);
1594
0
      aProperty = aProperty->next;
1595
0
      break;
1596
0
    case XS_REGEXP_KIND:
1597
0
      fxEchoProperty(the, aProperty, theList, "(regexp)", -1, C_NULL);
1598
0
      aProperty = aProperty->next;
1599
0
      break;
1600
0
    case XS_HOST_KIND:
1601
0
            fxEchoProperty(the, aProperty, theList, "(host)", -1, C_NULL);
1602
0
      if (aProperty->value.host.data)
1603
0
        fxEchoPropertyHost(the, theList, theInstance, aProperty);
1604
0
      aProperty = aProperty->next;
1605
0
      break;
1606
0
    case XS_GLOBAL_KIND:
1607
0
      aProperty = aProperty->next;
1608
0
      break;
1609
0
    case XS_PROMISE_KIND:
1610
0
            fxEchoProperty(the, aProperty, theList, "(promise)", -1, C_NULL);
1611
0
      aProperty = aProperty->next;
1612
0
      anIndex = 0;
1613
0
      aSlot = aProperty->value.reference->next;
1614
0
      if (aSlot) {
1615
0
        fxEchoProperty(the, aSlot, theList, "(then)", -1, C_NULL);
1616
0
        anIndex++;
1617
0
        aSlot = aSlot->next;
1618
0
      }
1619
0
      while (aSlot) {
1620
0
        fxEchoProperty(the, aSlot, theList, "(", anIndex, ")");
1621
0
        anIndex++;
1622
0
        aSlot = aSlot->next;
1623
0
      }
1624
0
      aProperty = aProperty->next;
1625
0
            fxEchoProperty(the, aProperty, theList, "(value)", -1, C_NULL);
1626
0
      aProperty = aProperty->next;
1627
0
      break;
1628
0
    case XS_MAP_KIND:
1629
0
      aProperty = aProperty->next;
1630
0
      anIndex = 0;
1631
0
      aSlot = aProperty->value.list.first;
1632
0
      while (aSlot) {
1633
0
        if (!(aSlot->flag & XS_DONT_ENUM_FLAG)) {
1634
0
          fxEchoProperty(the, aSlot, theList, "(", anIndex, ".0)");
1635
0
          fxEchoProperty(the, aSlot->next, theList, "(", anIndex, ".1)");
1636
0
        }
1637
0
        anIndex++;
1638
0
        aSlot = aSlot->next->next;
1639
0
      }
1640
0
      aProperty = aProperty->next;
1641
0
      break;
1642
0
    case XS_MODULE_KIND:
1643
0
      aProperty = aProperty->next;
1644
0
      fxEchoProperty(the, aProperty, theList, "(export)", -1, C_NULL);
1645
0
      aProperty = aProperty->next;
1646
0
      break;
1647
0
#if mxModuleStuff
1648
0
    case XS_MODULE_STUFF_KIND:
1649
0
      aProperty = aProperty->next;
1650
0
      fxEchoProperty(the, aProperty, theList, "(namespace)", -1, C_NULL);
1651
0
      aProperty = aProperty->next;
1652
0
      fxEchoProperty(the, aProperty, theList, "(imports)", -1, C_NULL);
1653
0
      aProperty = aProperty->next;
1654
0
      fxEchoProperty(the, aProperty, theList, "(source)", -1, C_NULL);
1655
0
      aProperty = aProperty->next;
1656
0
      fxEchoProperty(the, aProperty, theList, "(handler)", -1, C_NULL);
1657
0
      aProperty = aProperty->next;
1658
0
      fxEchoProperty(the, aProperty, theList, "(importHook)", -1, C_NULL);
1659
0
      aProperty = aProperty->next;
1660
0
      fxEchoProperty(the, aProperty, theList, "(importMetaHook)", -1, C_NULL);
1661
0
      aProperty = aProperty->next;
1662
0
      fxEchoProperty(the, aProperty, theList, "(importNowHook)", -1, C_NULL);
1663
0
      aProperty = aProperty->next;
1664
0
      break;
1665
0
#endif
1666
0
    case XS_PROGRAM_KIND:
1667
0
      aSlot = aProperty->value.module.realm;
1668
0
      fxEchoProperty(the, mxRealmGlobal(aSlot), theList, "(globals)", -1, C_NULL);
1669
0
      fxEchoProperty(the, mxOwnModules(aSlot), theList, "(modules)", -1, C_NULL);
1670
0
      break;
1671
0
    case XS_SET_KIND:
1672
0
      aProperty = aProperty->next;
1673
0
      anIndex = 0;
1674
0
      aSlot = aProperty->value.list.first;
1675
0
      while (aSlot) {
1676
0
        if (!(aSlot->flag & XS_DONT_ENUM_FLAG))
1677
0
          fxEchoProperty(the, aSlot, theList, "(", anIndex, ")");
1678
0
        anIndex++;
1679
0
        aSlot = aSlot->next;
1680
0
      }
1681
0
      aProperty = aProperty->next;
1682
0
      break;
1683
0
    case XS_TYPED_ARRAY_KIND:
1684
0
      fxEchoTypedArray(the, theInstance, theList);
1685
0
      aProperty = aProperty->next;
1686
0
      fxEchoProperty(the, aProperty, theList, "(view)", -1, C_NULL);
1687
0
      aProperty = aProperty->next;
1688
0
      fxEchoProperty(the, aProperty, theList, "(buffer)", -1, C_NULL);
1689
0
      aProperty = aProperty->next;
1690
0
      break;
1691
0
    case XS_PROXY_KIND:
1692
0
      if (aProperty->value.proxy.target)
1693
0
        fxEchoPropertyInstance(the, theList, "(target)", -1, C_NULL, XS_NO_ID, aProperty->flag, aProperty->value.proxy.target);
1694
0
      if (aProperty->value.proxy.handler)
1695
0
        fxEchoPropertyInstance(the, theList, "(handler)", -1, C_NULL, XS_NO_ID, aProperty->flag, aProperty->value.proxy.handler);
1696
0
      aProperty = aProperty->next;
1697
0
      break;
1698
0
    }
1699
0
  }
1700
0
  while (aProperty) {
1701
0
    if (aProperty->flag & XS_INTERNAL_FLAG) {
1702
0
      if (aProperty->kind == XS_ARRAY_KIND) {
1703
0
        txSlot* item = aProperty->value.array.address;
1704
0
        txIndex c = fxGetIndexSize(the, aProperty), i;
1705
0
        if (c > 1024)
1706
0
          c = 1024;
1707
0
        for (i = 0; i < c; i++) {
1708
0
          txIndex index = *((txIndex*)item);
1709
0
          fxEchoProperty(the, item, theList, "[", index, "]");
1710
0
          item++;
1711
0
        }
1712
0
      }
1713
0
      else if (aProperty->kind == XS_PRIVATE_KIND) {
1714
0
        txSlot* instanceInspector = fxToInstanceInspector(the, aProperty);
1715
0
        char buffer[128] = "(";
1716
0
        txSlot* check = aProperty->value.private.check;
1717
0
        txSlot* item = aProperty->value.private.first;
1718
0
        fxBufferFunctionName(the, &buffer[1], sizeof(buffer) - 1, check, ")");
1719
0
        fxEcho(the, "<property");
1720
0
        if (instanceInspector) {
1721
0
          if (instanceInspector->value.instanceInspector.link)
1722
0
            fxEchoFlags(the, " ", aProperty->flag);
1723
0
          else
1724
0
            fxEchoFlags(the, "-", aProperty->flag);
1725
0
        }
1726
0
        else
1727
0
          fxEchoFlags(the, "+", aProperty->flag);
1728
0
        fxEcho(the, " name=\"");
1729
0
        fxEchoString(the, buffer);
1730
0
        fxEcho(the, "\"");
1731
0
        if (instanceInspector) {
1732
0
          if (instanceInspector->value.instanceInspector.link) {
1733
0
            txInspectorNameLink* link = theList->first;
1734
0
            fxEcho(the, " value=\"");
1735
0
            while (link) {
1736
0
              fxEchoPropertyName(the, link->prefix, link->index, link->suffix, link->id);
1737
0
              if (link == instanceInspector->value.instanceInspector.link)
1738
0
                break;
1739
0
              fxEcho(the, ".");
1740
0
              link = link->next;
1741
0
            }
1742
0
            fxEcho(the, "\"/>");
1743
0
          }
1744
0
          else {
1745
0
            txInspectorNameLink link;
1746
0
            link.previous = theList->last;
1747
0
            link.next = C_NULL;
1748
0
            link.prefix = buffer;
1749
0
            link.index = 0;
1750
0
            link.suffix = C_NULL;
1751
0
            link.id = XS_NO_ID;
1752
0
            if (theList->first)
1753
0
              theList->last->next = &link;
1754
0
            else
1755
0
              theList->first = &link;
1756
0
            theList->last = &link;
1757
0
            instanceInspector->value.instanceInspector.link = &link;
1758
0
            fxEchoAddress(the, aProperty);
1759
0
            fxEcho(the, ">");
1760
0
            while (item) {
1761
0
              fxEchoProperty(the, item, theList, C_NULL, -1, C_NULL);
1762
0
              item = item->next;
1763
0
            }
1764
0
            fxEcho(the, "</property>");
1765
0
            instanceInspector->value.instanceInspector.link = C_NULL;
1766
0
            if (link.previous)
1767
0
              link.previous->next = C_NULL;
1768
0
            else
1769
0
              theList->first = C_NULL;
1770
0
            theList->last = link.previous;
1771
0
          }
1772
0
        }
1773
0
        else {
1774
0
          fxEchoAddress(the, aProperty);
1775
0
          fxEcho(the, "/>");
1776
0
        }
1777
0
      }
1778
0
    }
1779
0
    else {
1780
0
      fxEchoProperty(the, aProperty, theList, C_NULL, -1, C_NULL);
1781
0
    }
1782
0
    aProperty = aProperty->next;
1783
0
  }
1784
0
}
1785
1786
void fxEchoModule(txMachine* the, txSlot* module, txInspectorNameList* list)
1787
0
{
1788
0
  txSlot* exports = mxModuleExports(module);
1789
0
  txSlot* instanceInspector = fxToInstanceInspector(the, module);
1790
0
  txSlot* slot;
1791
0
  fxEcho(the, "<node");
1792
0
  if (instanceInspector)
1793
0
    fxEchoFlags(the, "-", exports->flag);
1794
0
  else
1795
0
    fxEchoFlags(the, "+", exports->flag);
1796
0
  fxEcho(the, " name=\"");
1797
0
  slot = mxModuleInternal(module);
1798
0
  fxEcho(the, fxGetKeyName(the, slot->value.module.id));
1799
0
  fxEcho(the, "\"");
1800
0
  fxEchoAddress(the, module);
1801
0
  if (instanceInspector) {
1802
0
    fxEcho(the, ">");
1803
0
    fxEchoInstance(the, fxGetInstance(the, exports), list);
1804
0
    fxEcho(the, "</node>");
1805
0
  }
1806
0
  else
1807
0
    fxEcho(the, "/>");
1808
0
}
1809
1810
void fxEchoNumber(txMachine* the, txNumber theNumber)
1811
0
{
1812
0
  char aBuffer[256];
1813
1814
0
  fxNumberToString(the, theNumber, aBuffer, sizeof(aBuffer), 0, 0);
1815
0
  fxEcho(the, aBuffer);
1816
0
}
1817
1818
void fxEchoPathLine(txMachine* the, txString thePath, txInteger theLine)
1819
0
{
1820
0
  if (thePath && theLine) {
1821
0
    fxEcho(the, " path=\"");
1822
0
    fxEchoString(the, thePath);
1823
0
    fxEcho(the, "\"");
1824
0
    fxEcho(the, " line=\"");
1825
0
    fxEchoInteger(the, theLine);
1826
0
    fxEcho(the, "\"");
1827
0
  }
1828
0
}
1829
1830
void fxEchoProperty(txMachine* the, txSlot* theProperty, txInspectorNameList* theList, txString thePrefix, txIndex theIndex, txString theSuffix)
1831
0
{
1832
0
  txID ID = theProperty->ID;
1833
0
  txFlag flag = theProperty->flag;
1834
0
  txSlot* instance;
1835
0
  if ((theProperty->kind == XS_CLOSURE_KIND) || (theProperty->kind == XS_EXPORT_KIND)) {
1836
0
    theProperty = theProperty->value.closure;
1837
0
        if (!theProperty)
1838
0
            return;
1839
#if mxAliasInstance
1840
    if (theProperty->ID) {
1841
      txSlot* slot = the->aliasArray[theProperty->ID];
1842
      if (slot)
1843
        theProperty = slot;
1844
    }
1845
#endif
1846
0
  }
1847
0
  if (theProperty->kind == XS_REFERENCE_KIND) {
1848
0
    instance = fxGetInstance(the, theProperty);
1849
0
    if (instance)
1850
0
      fxEchoPropertyInstance(the, theList, thePrefix, theIndex, theSuffix, ID, flag, instance);
1851
0
  }
1852
0
  else if (theProperty->kind == XS_ACCESSOR_KIND) {
1853
0
    instance = theProperty->value.accessor.getter;
1854
0
    if (instance)
1855
0
      fxEchoPropertyInstance(the, theList, thePrefix, theIndex, theSuffix, ID, flag | XS_GETTER_FLAG, instance);
1856
0
    instance = theProperty->value.accessor.setter;
1857
0
    if (instance)
1858
0
      fxEchoPropertyInstance(the, theList, thePrefix, theIndex, theSuffix, ID, flag | XS_SETTER_FLAG, instance);
1859
0
  }
1860
0
  else {
1861
0
    fxEcho(the, "<property");
1862
0
    fxEchoFlags(the, " ", flag);
1863
0
    fxEcho(the, " name=\"");
1864
0
    fxEchoPropertyName(the, thePrefix, theIndex, theSuffix, ID);
1865
0
    fxEcho(the, "\"");
1866
  
1867
0
    switch (theProperty->kind) {
1868
0
    case XS_UNDEFINED_KIND:
1869
0
      fxEcho(the, " value=\"undefined\"/>");
1870
0
      break;
1871
0
    case XS_NULL_KIND:
1872
0
      fxEcho(the, " value=\"null\"/>");
1873
0
      break;
1874
0
    case XS_CALLBACK_KIND:
1875
0
    case XS_CALLBACK_X_KIND:
1876
0
      fxEcho(the, " value=\"(C code)\"/>");
1877
0
      break;
1878
0
    case XS_CODE_KIND:
1879
0
    case XS_CODE_X_KIND:
1880
0
      fxEcho(the, " value=\"");
1881
0
      {
1882
0
        txByte* p = theProperty->value.code.address + 2;
1883
0
        if (*p == XS_CODE_FILE) {
1884
0
          txID file;
1885
0
          txS2 line;
1886
0
          p++;
1887
0
          mxDecodeID(p, file);
1888
0
          p++;
1889
0
          mxDecode2(p, line);
1890
0
          fxEchoString(the, fxGetKeyName(the, file));
1891
0
          fxEcho(the, "\" line=\"");
1892
0
          fxEchoInteger(the, line);
1893
0
        }
1894
0
        else
1895
0
          fxEcho(the, "(XS code)");
1896
0
      }
1897
0
      fxEcho(the, "\"/>");
1898
0
      break;
1899
  #if mxHostFunctionPrimitive
1900
    case XS_HOST_FUNCTION_KIND:
1901
      fxEcho(the, " value=\"(host function)\"/>");
1902
      break;
1903
  #endif
1904
0
    case XS_ARRAY_KIND:
1905
0
      fxEcho(the, " value=\"");
1906
0
      fxEchoInteger(the, theProperty->value.array.length);
1907
0
      fxEcho(the, " items\"/>");
1908
0
      break;
1909
0
    case XS_BUFFER_INFO_KIND:
1910
0
      fxEcho(the, " value=\"");
1911
0
      fxEchoInteger(the, theProperty->value.bufferInfo.length);
1912
0
      if (theProperty->value.bufferInfo.maxLength >= 0) {
1913
0
        fxEcho(the, " bytes <= ");
1914
0
        fxEchoInteger(the, theProperty->value.bufferInfo.maxLength);
1915
0
      }
1916
0
      fxEcho(the, " bytes\"/>");
1917
0
      break;
1918
0
    case XS_STRING_KIND:
1919
0
    case XS_STRING_X_KIND:
1920
0
      fxEcho(the, " value=\"'");
1921
0
      fxEchoString(the, theProperty->value.string);
1922
0
      fxEcho(the, "'\"/>");
1923
0
      break;
1924
0
    case XS_BOOLEAN_KIND:
1925
0
      fxEcho(the, " value=\"");
1926
0
      if (theProperty->value.boolean)
1927
0
        fxEcho(the, "true");
1928
0
      else
1929
0
        fxEcho(the, "false");
1930
0
      fxEcho(the, "\"/>");
1931
0
      break;
1932
0
    case XS_INTEGER_KIND:
1933
0
      fxEcho(the, " value=\"");
1934
0
      fxEchoInteger(the, theProperty->value.integer);
1935
0
      fxEcho(the, "\"/>");
1936
0
      break;
1937
0
    case XS_NUMBER_KIND:
1938
0
      fxEcho(the, " value=\"");
1939
0
      fxEchoNumber(the, theProperty->value.number);
1940
0
      fxEcho(the, "\"/>");
1941
0
      break;
1942
0
    case XS_BIGINT_KIND:
1943
0
    case XS_BIGINT_X_KIND:
1944
0
      fxEcho(the, " value=\"");
1945
0
      fxEchoBigInt(the, &theProperty->value.bigint);
1946
0
      fxEcho(the, "\"/>");
1947
0
      break;
1948
0
    case XS_DATE_KIND:
1949
0
      fxEcho(the, " value=\"");
1950
0
      fxEchoNumber(the, theProperty->value.number);
1951
0
      fxEcho(the, "\"/>");
1952
0
      break;
1953
0
    case XS_REGEXP_KIND:
1954
0
      fxEcho(the, " value=\"\"/>");
1955
0
      break;
1956
0
    case XS_HOST_KIND:
1957
0
      if (theProperty->value.host.data) {
1958
0
        if (theProperty->flag & XS_HOST_CHUNK_FLAG)
1959
0
          fxEcho(the, " value=\"XS data\"/>");
1960
0
        else
1961
0
          fxEcho(the, " value=\"C data\"/>");
1962
0
      }
1963
0
      else
1964
0
          fxEcho(the, " value=\"NULL\"/>");
1965
0
      break;
1966
0
    case XS_PROMISE_KIND:
1967
0
      switch (theProperty->value.integer) {
1968
0
      case mxUndefinedStatus: fxEcho(the, " value=\"?\"/>"); break;
1969
0
      case mxPendingStatus: fxEcho(the, " value=\"pending\"/>"); break;
1970
0
      case mxFulfilledStatus: fxEcho(the, " value=\"fulfilled\"/>"); break;
1971
0
      case mxRejectedStatus: fxEcho(the, " value=\"rejected\"/>"); break;
1972
0
      }
1973
0
      break;
1974
0
    case XS_KEY_KIND:
1975
0
    case XS_KEY_X_KIND:
1976
0
      fxEcho(the, " value=\"'");
1977
0
      fxEchoString(the, theProperty->value.key.string);
1978
0
      fxEcho(the, "'\"/>");
1979
0
      break;
1980
0
    case XS_SYMBOL_KIND:
1981
0
      fxEcho(the, " value=\"Symbol(");
1982
0
      fxEchoString(the, fxGetKeyString(the, theProperty->value.symbol, C_NULL));
1983
0
      fxEcho(the, ")\"/>");
1984
0
      break;
1985
0
    case XS_DATA_VIEW_KIND:
1986
0
      fxEcho(the, " value=\"");
1987
0
      fxEchoInteger(the, theProperty->value.dataView.offset);
1988
0
      fxEcho(the, ", ");
1989
0
      fxEchoInteger(the, fxGetDataViewSize(the, theProperty, theProperty->next));
1990
0
      fxEcho(the, " bytes\"/>");
1991
0
      break;
1992
0
    default:
1993
0
      fxEcho(the, "/>");
1994
0
      break;
1995
0
    }
1996
0
  }
1997
0
}
1998
1999
void fxEchoPropertyHost(txMachine* the, txInspectorNameList* theList, txSlot* theInstance, txSlot* theHost)
2000
0
{
2001
0
  txSlot* instanceInspector = fxToInstanceInspector(the, theInstance);
2002
0
  if (instanceInspector) {
2003
0
    txSlot* hostInspectors = &mxHostInspectors;
2004
0
    txSlot* hostInspector;
2005
0
    txSlot* cache;
2006
0
    txSlot* cacheProperty;
2007
0
    hostInspector = hostInspectors->value.list.first;
2008
0
    while (hostInspector) {
2009
0
      if (hostInspector->value.hostInspector.instance == theInstance) {
2010
0
        break;
2011
0
      }
2012
0
      hostInspector = hostInspector->next;
2013
0
    }
2014
0
    if (!hostInspector) {
2015
0
      txSlot* aParent;
2016
0
      cache = fxNewInstance(the);
2017
0
      hostInspector = fxNewSlot(the);
2018
0
      hostInspector->kind = XS_HOST_INSPECTOR_KIND;
2019
0
      hostInspector->value.hostInspector.cache = cache;
2020
0
      hostInspector->value.hostInspector.instance = theInstance;
2021
0
      if (hostInspectors->value.list.first) 
2022
0
        hostInspectors->value.list.last->next = hostInspector;
2023
0
      else
2024
0
        hostInspectors->value.list.first = hostInspector;
2025
0
      hostInspectors->value.list.last = hostInspector;
2026
0
      mxPop();
2027
      
2028
0
      aParent = theInstance;
2029
0
      while (aParent && (aParent->next->kind == XS_HOST_KIND)) {
2030
0
        txSlot* aParentProperty = aParent->next;
2031
0
        while (aParentProperty) {
2032
0
          if ((aParentProperty->kind == XS_ACCESSOR_KIND) && (aParentProperty->value.accessor.getter)) {
2033
0
            cacheProperty = mxBehaviorGetProperty(the, cache, aParentProperty->ID, 0, XS_ANY);
2034
0
            if (!cacheProperty) {
2035
0
              txSlot* aFunction = aParentProperty->value.accessor.getter;
2036
0
              if (mxIsFunction(aFunction)) {
2037
0
                fxBeginHost(the);
2038
0
                the->frame->flag &= ~(XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG);
2039
                /* THIS */
2040
0
                mxPushReference(theInstance);
2041
                /* FUNCTION */
2042
0
                mxPushReference(aFunction);
2043
0
                mxCall();
2044
0
                mxRunCount(0);
2045
0
                cacheProperty = mxBehaviorSetProperty(the, cache, aParentProperty->ID, 0, XS_ANY);
2046
0
                cacheProperty->flag |= XS_INSPECTOR_FLAG;
2047
0
                cacheProperty->kind = the->stack->kind;
2048
0
                cacheProperty->value = the->stack->value;
2049
0
                mxPop();
2050
0
                fxEndHost(the);
2051
0
              }
2052
0
            }
2053
0
          }
2054
0
          aParentProperty = aParentProperty->next;
2055
0
        }
2056
0
        aParent = fxGetPrototype(the, aParent);
2057
0
      }
2058
0
    }
2059
0
    cache = hostInspector->value.hostInspector.cache;
2060
0
    cacheProperty = cache->next;
2061
0
    while (cacheProperty) {
2062
0
      if (cacheProperty->ID)
2063
0
        fxEchoProperty(the, cacheProperty, theList, C_NULL, -1, C_NULL);
2064
0
      cacheProperty = cacheProperty->next;
2065
0
    }
2066
0
  }
2067
0
}
2068
2069
2070
void fxEchoPropertyInstance(txMachine* the, txInspectorNameList* theList, txString thePrefix, txIndex theIndex, txString theSuffix, txID theID, txFlag theFlag, txSlot* theInstance)
2071
0
{
2072
0
  txSlot* instanceInspector = fxToInstanceInspector(the, theInstance);
2073
0
  char buffer[128];
2074
0
  txString p = buffer;
2075
0
  txString q = p + sizeof(buffer);
2076
2077
0
  if (theFlag & XS_GETTER_FLAG) {
2078
0
    c_strcpy(p, "get ");
2079
0
    p += 4;
2080
0
  }
2081
0
  else if (theFlag & XS_SETTER_FLAG) {
2082
0
    c_strcpy(p, "set ");
2083
0
    p += 4;
2084
0
  }
2085
0
  if (thePrefix) {
2086
0
    c_strcpy(p, thePrefix);
2087
0
    p += mxStringLength(thePrefix);
2088
0
    if (theSuffix) {
2089
0
      fxIndexToString(the, theIndex, p, mxPtrDiff(q - p - 1)); // assume mxStringLength(theSuffix) == 1;
2090
0
      c_strcat(p, theSuffix);
2091
0
    }
2092
0
  }
2093
0
  else
2094
0
    fxIDToString(the, theID, p, mxPtrDiff(q - p));
2095
2096
0
  fxEcho(the, "<property");
2097
0
  if (instanceInspector) {
2098
0
    if (instanceInspector->value.instanceInspector.link)
2099
0
      fxEchoFlags(the, " ", theFlag);
2100
0
    else
2101
0
      fxEchoFlags(the, "-", theFlag);
2102
0
  }
2103
0
  else
2104
0
    fxEchoFlags(the, "+", theFlag);
2105
0
  fxEcho(the, " name=\"");
2106
0
  if (theFlag & XS_GETTER_FLAG)
2107
0
    fxEcho(the, "get ");
2108
0
  else if (theFlag & XS_SETTER_FLAG)
2109
0
    fxEcho(the, "set ");
2110
0
  fxEchoPropertyName(the, thePrefix, theIndex, theSuffix, theID);
2111
0
  fxEcho(the, "\"");
2112
  
2113
0
  if (instanceInspector) {
2114
0
    if (instanceInspector->value.instanceInspector.link) {
2115
0
      txInspectorNameLink* link = theList->first;
2116
0
      fxEcho(the, " value=\"");
2117
0
      while (link) {
2118
0
        fxEchoPropertyName(the, link->prefix, link->index, link->suffix, link->id);
2119
0
        if (link == instanceInspector->value.instanceInspector.link)
2120
0
          break;
2121
0
        fxEcho(the, ".");
2122
0
        link = link->next;
2123
0
      }
2124
0
      fxEcho(the, "\"/>");
2125
0
    }
2126
0
    else {
2127
0
      txInspectorNameLink link;
2128
0
      link.previous = theList->last;
2129
0
      link.next = C_NULL;
2130
0
      link.prefix = thePrefix;
2131
0
      link.index = theIndex;
2132
0
      link.suffix = theSuffix;
2133
0
      link.id = theID;
2134
0
      if (theList->first)
2135
0
        theList->last->next = &link;
2136
0
      else
2137
0
        theList->first = &link;
2138
0
      theList->last = &link;
2139
0
      instanceInspector->value.instanceInspector.link = &link;
2140
      
2141
0
      fxEchoAddress(the, theInstance);
2142
0
      fxEcho(the, ">");
2143
0
      fxEchoInstance(the, theInstance, theList);
2144
0
      fxEcho(the, "</property>");
2145
      
2146
0
      instanceInspector->value.instanceInspector.link = C_NULL;
2147
0
      if (link.previous)
2148
0
        link.previous->next = C_NULL;
2149
0
      else
2150
0
        theList->first = C_NULL;
2151
0
      theList->last = link.previous;
2152
0
    }
2153
0
  }
2154
0
  else {
2155
0
    fxEchoAddress(the, theInstance);
2156
0
    fxEcho(the, "/>");
2157
0
  }
2158
0
}
2159
2160
void fxEchoPropertyName(txMachine* the, txString thePrefix, txIndex theIndex, txString theSuffix, txID theID)
2161
0
{
2162
0
  if (thePrefix) {
2163
0
    fxEchoString(the, thePrefix);
2164
0
    if (theSuffix) {
2165
0
      fxIndexToString(the, theIndex, the->nameBuffer, sizeof(the->nameBuffer));
2166
0
      fxEchoString(the, the->nameBuffer);
2167
0
      fxEchoString(the, theSuffix);
2168
0
    }
2169
0
  }
2170
0
  else {
2171
0
    if (theID != XS_NO_ID) {
2172
0
      txBoolean adorn;
2173
0
      txString string = fxGetKeyString(the, theID, &adorn);
2174
0
      if (adorn) {
2175
0
        fxEcho(the, "Symbol(");
2176
0
        fxEchoString(the, string);
2177
0
        fxEcho(the, ")");
2178
0
      }
2179
0
      else
2180
0
        fxEchoString(the, string);
2181
0
    }
2182
0
    else
2183
0
      fxEcho(the, "?");
2184
0
  }
2185
0
}
2186
2187
void fxEchoStart(txMachine* the)
2188
0
{
2189
0
  the->echoOffset = 0;
2190
0
  fxEcho(the, "\15\12<xsbug>");
2191
0
}
2192
2193
void fxEchoStop(txMachine* the)
2194
0
{
2195
0
  fxEcho(the, "</xsbug>\15\12");
2196
0
  fxSend(the, 0);
2197
0
  the->echoOffset = 0;
2198
0
}
2199
2200
void fxEchoString(txMachine* the, txString theString)
2201
0
{
2202
0
  static const txByte gxEscape[256] ICACHE_FLASH_ATTR = {
2203
  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
2204
0
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x                    */
2205
0
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 1x                    */
2206
0
     1,1,0,1,1,1,0,1,1,1,1,1,1,1,1,1, /* 2x   !"#$%&'()*+,-./  */
2207
0
     1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1, /* 3x  0123456789:;<=>?  */
2208
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 4x  @ABCDEFGHIJKLMNO  */
2209
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 5X  PQRSTUVWXYZ[\]^_  */
2210
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 6x  `abcdefghijklmno  */
2211
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,   /* 7X  pqrstuvwxyz{|}~   */
2212
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 8X                    */
2213
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 9X                    */
2214
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* AX                    */
2215
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* BX                    */
2216
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* CX                    */
2217
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* FX                    */
2218
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* EX                    */
2219
0
     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1  /* FX                    */
2220
0
  };
2221
0
  txU1 tmp;
2222
0
  txU1* src;
2223
0
  txU1* dst;
2224
0
  txU1* start;
2225
0
  txU1* stop;
2226
2227
0
  src = (txU1*)theString;
2228
0
  dst = (txU1*)the->echoBuffer + the->echoOffset;
2229
0
  start = (txU1*)the->echoBuffer;
2230
0
  stop = (txU1*)the->echoBuffer + sizeof(the->echoBuffer) - 1;
2231
0
  while ((tmp = c_read8(src))) {
2232
0
    src++;
2233
0
    if (dst + 6 > stop) {
2234
0
      the->echoOffset = mxPtrDiff(dst - start);
2235
0
      fxSend(the, 1);
2236
0
      dst = start;
2237
0
    }
2238
0
#if mxCESU8
2239
0
    if (tmp & 0x80) {
2240
0
      txInteger character;
2241
0
      src = (txU1*)fxCESU8Decode((txString)src - 1, &character);
2242
0
      if (character > 128) {
2243
0
        dst = (txU1*)fxUTF8Encode((txString)dst, character);
2244
0
        continue;
2245
0
      }
2246
0
      tmp = (txU1)character;
2247
0
    }
2248
0
#endif
2249
0
    if (c_read8(gxEscape + tmp))
2250
0
      *dst++ = tmp;
2251
0
    else {
2252
0
      *(dst++) = '&';
2253
0
      *(dst++) = '#';
2254
0
      if (tmp >= 100) {
2255
0
        *(dst++) = '0' + (tmp / 100);
2256
0
        tmp %= 100;
2257
0
        *(dst++) = '0' + (tmp / 10);
2258
0
        tmp %= 10;
2259
0
        *(dst++) = '0' + tmp;
2260
0
      }
2261
0
      else if (tmp >= 10) {
2262
0
        *(dst++) = '0' + (tmp / 10);
2263
0
        tmp %= 10;
2264
0
        *(dst++) = '0' + tmp;
2265
0
      }
2266
0
      else {
2267
0
        *(dst++) = '0' + tmp;
2268
0
      }
2269
0
      *(dst++) = ';';
2270
0
    }
2271
0
  }
2272
0
  the->echoOffset = mxPtrDiff(dst - start);
2273
0
}
2274
2275
void fxEchoTypedArray(txMachine* the, txSlot* theInstance, txInspectorNameList* theList)
2276
0
{
2277
0
  txSlot* dispatch = theInstance->next;
2278
0
  txSlot* view = dispatch->next;
2279
0
  txSlot* buffer = view->next;
2280
0
  txU2 shift = dispatch->value.typedArray.dispatch->shift;
2281
0
  txInteger size = fxGetDataViewSize(the, view, buffer) >> shift;
2282
0
  fxEcho(the, "<property");
2283
0
  fxEchoFlags(the, " ", dispatch->flag);
2284
0
  fxEcho(the, " name=\"(");
2285
0
  fxIDToString(the, dispatch->value.typedArray.dispatch->constructorID, the->nameBuffer, sizeof(the->nameBuffer));
2286
0
  fxEchoString(the, the->nameBuffer);
2287
0
  fxEcho(the, ")\"");
2288
0
  fxEcho(the, " value=\"");
2289
0
  fxEchoInteger(the, size);
2290
0
  fxEcho(the, " items\"/>");
2291
0
  if (size > 0) {
2292
0
    txInteger index = 0;
2293
0
    if (size > 1024)
2294
0
      size = 1024;
2295
0
    mxPushUndefined();
2296
0
    while (index < size) {
2297
0
      (*dispatch->value.typedArray.dispatch->getter)(the, buffer->value.reference->next, view->value.dataView.offset + (index << shift), the->stack, EndianNative);
2298
0
      fxEchoProperty(the, the->stack, theList, "[", index, "]");
2299
0
      index++;
2300
0
    }
2301
0
    mxPop();
2302
0
  }
2303
0
}
2304
2305
txSlot* fxFindFrame(txMachine* the)
2306
0
{
2307
0
  txSlot* frame = the->frame;
2308
0
  while (frame) {
2309
0
    if (frame->flag & XS_DEBUG_FLAG)
2310
0
      break;
2311
0
    frame = frame->next;
2312
0
  }
2313
0
  return frame;
2314
0
}
2315
2316
txSlot* fxFindRealm(txMachine* the)
2317
0
{
2318
0
  txSlot* frame = fxFindFrame(the);
2319
0
  txSlot* realm = C_NULL;
2320
0
  if (frame && (!(frame->flag & XS_C_FLAG))) {
2321
0
    txSlot* function = frame + 3;
2322
0
    if (mxIsReference(function)) {
2323
0
            txSlot* instance = function->value.reference;
2324
0
            txSlot* home = mxFunctionInstanceHome(instance);
2325
0
      txSlot* module = home->value.home.module;
2326
0
            if (module)
2327
0
                realm = mxModuleInstanceInternal(module)->value.module.realm;
2328
0
    }
2329
0
  }
2330
0
  if (!realm)
2331
0
    realm = mxModuleInstanceInternal(mxProgram.value.reference)->value.module.realm;
2332
0
  return realm;
2333
0
}
2334
2335
void fxGo(txMachine* the)
2336
0
{
2337
0
  txSlot* aSlot = the->frame;
2338
0
  while (aSlot) {
2339
0
    aSlot->flag &= ~(XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG);
2340
0
    aSlot = aSlot->next;
2341
0
  }
2342
0
}
2343
2344
void fxIndexToString(txMachine* the, txIndex theIndex, txString theBuffer, txSize theSize)
2345
0
{
2346
0
  c_snprintf(theBuffer, theSize, "%u", theIndex);
2347
0
}
2348
2349
void fxListFrames(txMachine* the)
2350
0
{
2351
0
  txSlot* aFrame;
2352
2353
0
  fxEcho(the, "<frames>");
2354
0
  aFrame = the->frame;
2355
0
  while (aFrame) {
2356
0
    fxEcho(the, "<frame");
2357
0
    fxEcho(the, " name=\"");
2358
0
    fxEchoFrameName(the, aFrame);
2359
0
    fxEcho(the, "\"");
2360
0
    fxEchoAddress(the, aFrame);
2361
0
    fxEchoFramePathLine(the, aFrame);
2362
0
    fxEcho(the, "/>");
2363
0
    aFrame = aFrame->next;
2364
0
  }
2365
0
  fxEcho(the, "</frames>");
2366
0
}
2367
2368
void fxListGlobal(txMachine* the)
2369
0
{
2370
0
  txInspectorNameList aList = { C_NULL, C_NULL };
2371
0
  txSlot* realm = fxFindRealm(the);
2372
0
  txSlot* global = mxRealmGlobal(realm)->value.reference;
2373
0
  txSlot* slot = fxGetPrototype(the, global);
2374
0
  fxEcho(the, "<global>");
2375
0
  if (slot != mxObjectPrototype.value.reference) {
2376
0
    fxEchoPropertyInstance(the, &aList, "(..)", -1, C_NULL, XS_NO_ID, global->flag & XS_MARK_FLAG, slot);
2377
0
  }
2378
0
  slot = global->next;
2379
0
  while (slot->flag & XS_INTERNAL_FLAG) {
2380
0
    slot = slot->next;
2381
0
  }
2382
0
  while (slot) {
2383
0
    fxEchoProperty(the, slot, &aList, C_NULL, -1, C_NULL);
2384
0
    slot = slot->next;
2385
0
  }
2386
0
  global = mxRealmClosures(realm)->value.reference;
2387
0
  slot = global->next;
2388
0
  while (slot) {
2389
0
    fxEchoProperty(the, slot, &aList, C_NULL, -1, C_NULL);
2390
0
    slot = slot->next;
2391
0
  }
2392
0
  fxEcho(the, "</global>");
2393
0
}
2394
2395
void fxListLocal(txMachine* the)
2396
0
{
2397
0
  txInspectorNameList aList = { C_NULL, C_NULL };
2398
0
  txSlot* frame = fxFindFrame(the);
2399
0
  txSlot* scope = C_NULL;
2400
0
  if (!frame) // @@
2401
0
    return;
2402
0
  fxEcho(the, "<local");
2403
0
  fxEcho(the, " name=\"");
2404
0
  fxEchoFrameName(the, frame);
2405
0
  fxEcho(the, "\"");
2406
0
  fxEchoAddress(the, frame);
2407
0
  fxEchoFramePathLine(the, frame);
2408
0
  fxEcho(the, ">");
2409
0
  fxEchoProperty(the, frame + 1, &aList, "(return)", -1, C_NULL);
2410
0
  fxEchoProperty(the, frame + 2, &aList, "new.target", -1, C_NULL);
2411
0
  fxEchoProperty(the, frame + 3, &aList, "(function)", -1, C_NULL);
2412
0
  fxEchoProperty(the, frame + 4, &aList, "this", -1, C_NULL);
2413
0
  if (frame == the->frame)
2414
0
    scope = the->scope;
2415
0
  else {
2416
0
    txSlot* current = the->frame;
2417
0
    while (current->next != frame)
2418
0
      current = current->next;
2419
0
    if (current)
2420
0
      scope = current->value.frame.scope;
2421
0
  }
2422
0
  if (frame->flag & XS_C_FLAG) {
2423
0
    txInteger aCount, anIndex;
2424
0
    aCount = (frame - 1)->value.integer;
2425
0
    for (anIndex = 0; anIndex < aCount; anIndex++) {
2426
0
      fxEchoProperty(the, (frame - 2 - anIndex), &aList, "arg(", anIndex, ")");
2427
0
    }
2428
0
    if (scope) {
2429
0
      aCount = scope->value.environment.variable.count;
2430
0
      for (anIndex = 0; anIndex < aCount; anIndex++) {
2431
0
        fxEchoProperty(the, (scope - 1 - anIndex), &aList, "var(", anIndex, ")");
2432
0
      }
2433
0
    }
2434
0
  }
2435
0
  else {
2436
0
    if (scope) {
2437
0
      txSlot* aSlot = mxFrameToEnvironment(frame);
2438
0
      txID id;
2439
0
      while (aSlot > scope) {
2440
0
        aSlot--;
2441
0
        id = aSlot->ID;
2442
0
        if ((0 < id) && (id < the->keyCount)) {
2443
0
          txSlot* key;
2444
0
          if (id < the->keyOffset)
2445
0
            key = the->keyArrayHost[id];
2446
0
          else
2447
0
            key = the->keyArray[id - the->keyOffset];
2448
0
          if (key) {
2449
0
            txKind kind = mxGetKeySlotKind(key);
2450
0
            if ((kind == XS_KEY_KIND) || (kind == XS_KEY_X_KIND)) {
2451
0
               if (key->value.key.string[0] != '#')
2452
0
                fxEchoProperty(the, aSlot, &aList, C_NULL, -1, C_NULL);
2453
0
            }
2454
0
            else
2455
0
              fxEchoProperty(the, aSlot, &aList, C_NULL, -1, C_NULL);
2456
0
          }
2457
0
        }
2458
0
      }
2459
0
    }
2460
0
  }
2461
0
  fxEcho(the, "</local>");
2462
0
}
2463
2464
void fxListModules(txMachine* the)
2465
0
{
2466
0
  txInspectorNameList aList = { C_NULL, C_NULL };
2467
0
  txSlot* realm = fxFindRealm(the);
2468
0
  txSlot* moduleMap = mxModuleMap(realm);
2469
0
  txSlot* instance = fxGetInstance(the, moduleMap);
2470
0
  txSlot* instanceInspector = fxToInstanceInspector(the, instance);
2471
0
  txSlot* modules = mxOwnModules(realm)->value.reference;
2472
0
  txSlot* module;
2473
0
  fxEcho(the, "<grammar>");
2474
0
  if (instance->next) {
2475
0
    fxEcho(the, "<node");
2476
0
    if (instanceInspector)
2477
0
      fxEchoFlags(the, "-", moduleMap->flag);
2478
0
    else
2479
0
      fxEchoFlags(the, "+", moduleMap->flag);
2480
0
    fxEcho(the, " name=\"(map)\"");
2481
0
    fxEchoAddress(the, instance);
2482
0
    if (instanceInspector) {
2483
0
      fxEcho(the, ">");
2484
0
      fxEchoInstance(the, instance, &aList);
2485
0
      fxEcho(the, "</node>");
2486
0
    }
2487
0
    else
2488
0
      fxEcho(the, "/>");
2489
0
  }
2490
0
  module = modules->next;
2491
0
  while (module) {
2492
0
        if (mxIsReference(module))
2493
0
            fxEchoModule(the, module, &aList);
2494
0
    module = module->next;
2495
0
  }
2496
0
  modules = modules->value.instance.prototype;
2497
0
  if (modules) {
2498
0
    module = modules->next;
2499
0
    while (module) {
2500
0
      if (mxIsReference(module))
2501
0
        fxEchoModule(the, module, &aList);
2502
0
      module = module->next;
2503
0
    }
2504
0
  }
2505
0
  fxEcho(the, "</grammar>");
2506
0
}
2507
2508
void fxLogin(txMachine* the)
2509
28.0k
{
2510
28.0k
  if (!fxIsConnected(the)) {
2511
28.0k
    fxConnect(the);
2512
28.0k
    if (!fxIsConnected(the))
2513
28.0k
      return;
2514
28.0k
  }
2515
0
  fxEchoStart(the);
2516
0
  fxEcho(the, "<login name=\"");
2517
0
  if (the->name)
2518
0
    fxEchoString(the, the->name);
2519
0
  else
2520
0
    fxEchoString(the, "xslib");
2521
0
  fxEcho(the, "\" value=\"");
2522
0
  fxEcho(the, "XS ");
2523
0
  fxEchoInteger(the, XS_MAJOR_VERSION);
2524
0
  fxEcho(the, ".");
2525
0
  fxEchoInteger(the, XS_MINOR_VERSION);
2526
0
  fxEcho(the, ".");
2527
0
  fxEchoInteger(the, XS_PATCH_VERSION);
2528
0
  fxEcho(the, " ");
2529
0
  fxEchoInteger(the, (txInteger)(sizeof(txSlot*)*8));
2530
0
  fxEcho(the, "-bit ");
2531
#if mxBigEndian
2532
  fxEcho(the, "BE ");
2533
#else
2534
0
  fxEcho(the, "LE ");
2535
0
#endif
2536
0
  fxEchoInteger(the, (txInteger)(sizeof(txID)*8));
2537
0
  fxEcho(the, "-bit ID\" flags=\"e");
2538
0
  fxEcho(the, "\"/>");
2539
0
  fxEchoStop(the);
2540
#if mxAliasInstance
2541
  {
2542
    txSlot* slot = &mxGlobal;
2543
    if (mxIsReference(slot)) {
2544
      slot = slot->value.reference->value.instance.prototype;
2545
      if (slot != mxObjectPrototype.value.reference)
2546
        fxToggle(the, slot);
2547
    }
2548
    slot = &mxCompartmentGlobal;
2549
    if (mxIsReference(slot)) {
2550
      slot = slot->value.reference->value.instance.prototype;
2551
      if (slot != mxObjectPrototype.value.reference)
2552
        fxToggle(the, slot);
2553
    }
2554
  }
2555
#endif
2556
0
  fxDebugCommand(the);
2557
0
}
2558
2559
void fxLogout(txMachine* the)
2560
28.0k
{
2561
28.0k
  if (!fxIsConnected(the))
2562
28.0k
    return;
2563
0
  fxStopProfiling(the, C_NULL);
2564
0
  fxDisconnect(the);
2565
0
}
2566
2567
void fxSelect(txMachine* the, txSlot* slot)
2568
0
{
2569
0
  txSlot* frame = the->frame;
2570
0
  while (frame) {
2571
0
    if (frame == slot)
2572
0
      frame->flag |= XS_DEBUG_FLAG;
2573
0
    else
2574
0
      frame->flag &= ~XS_DEBUG_FLAG;
2575
0
    frame = frame->next;
2576
0
  }
2577
0
}
2578
2579
void fxSetBreakpoint(txMachine* the, txString thePath, txInteger theLine, size_t theID)
2580
0
{
2581
0
  txID path;
2582
0
  txSlot* breakpoint;
2583
2584
0
  if (!thePath)
2585
0
    return;
2586
0
  if ((theID == 0) && (theLine == 0)) { 
2587
0
    if (!c_strcmp(thePath, "exceptions")) {
2588
0
      the->breakOnExceptionsFlag = 1;
2589
0
      mxPushUndefined();
2590
0
      return;
2591
0
    } 
2592
0
    if (!c_strcmp(thePath, "start")) {
2593
0
      the->breakOnStartFlag = 1;
2594
0
      mxPushUndefined();
2595
0
      return;
2596
0
    } 
2597
0
  }
2598
0
  path = fxNewNameC(the, thePath);
2599
0
  if (!path)
2600
0
    return;
2601
0
  breakpoint = mxBreakpoints.value.list.first;
2602
0
  while (breakpoint) {
2603
0
    if ((breakpoint->ID == path) && (breakpoint->value.breakpoint.line == theLine)) {
2604
0
      break;
2605
0
    }
2606
0
    breakpoint = breakpoint->next;
2607
0
  }
2608
0
  if (!breakpoint) {
2609
0
    breakpoint = fxNewSlot(the);
2610
0
    breakpoint->next = mxBreakpoints.value.list.first;
2611
0
    breakpoint->ID = path;
2612
0
    breakpoint->kind = XS_BREAKPOINT_KIND;
2613
0
    breakpoint->value.breakpoint.line = theLine;
2614
0
    mxBreakpoints.value.list.first = breakpoint;
2615
0
  }
2616
0
  if (theID == 0) {
2617
0
    mxPushUndefined();
2618
0
    breakpoint->value.breakpoint.info = C_NULL;
2619
0
  }
2620
0
  else {
2621
0
    txSlot* instance = fxNewInstance(the);
2622
0
    txSlot* property = fxLastProperty(the, instance);
2623
0
    property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG);
2624
0
    property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG);
2625
0
    property = fxNextUndefinedProperty(the, property, XS_NO_ID, XS_INTERNAL_FLAG);
2626
0
    breakpoint->value.breakpoint.info = instance;
2627
0
  }
2628
0
}
2629
2630
void fxSetBreakpointCondition(txMachine* the, txSlot* reference, txString it)
2631
0
{
2632
0
  txSlot* instance = fxToInstance(the, reference);
2633
0
  txSlot* property = instance->next;
2634
0
  fxDebugEvalBuffer(the, it, property);
2635
0
}
2636
2637
void fxSetBreakpointHitCount(txMachine* the, txSlot* reference, txString it)
2638
0
{
2639
0
  txSlot* instance = fxToInstance(the, reference);
2640
0
  txSlot* property = instance->next->next;
2641
0
  char c = *it;
2642
0
  txID op = XS_CODE_MORE_EQUAL;
2643
0
  txInteger count = 0;
2644
0
  if (c == '%') {
2645
0
    it++;
2646
0
    op = XS_CODE_MODULO;
2647
0
  }
2648
0
  else if (c == '<') {
2649
0
    it++;
2650
0
    if (*it == '=') {
2651
0
      it++;
2652
0
      op = XS_CODE_LESS_EQUAL;
2653
0
    }
2654
0
    else
2655
0
      op = XS_CODE_LESS;
2656
0
  }
2657
0
  else if (*it == '=') {
2658
0
    op = XS_CODE_EQUAL;
2659
0
    it++;
2660
0
  }
2661
0
  else if (*it == '>') {
2662
0
    it++;
2663
0
    if (*it == '=') {
2664
0
      it++;
2665
0
      op = XS_CODE_MORE_EQUAL;
2666
0
    }
2667
0
    else
2668
0
      op = XS_CODE_MORE;
2669
0
  }
2670
0
  it = fxSkipSpaces(it);
2671
0
  while ((c = *it++)) {
2672
0
    if (('0' <= c) && (c <= '9'))
2673
0
      count = (count * 10) + (c - '0');
2674
0
    else
2675
0
      break;
2676
0
  }
2677
0
  property->ID = op;
2678
0
  property->kind = XS_DATA_VIEW_KIND;
2679
0
  property->value.dataView.offset = 0;
2680
0
  property->value.dataView.size = count;
2681
0
}
2682
2683
void fxSetBreakpointTrace(txMachine* the, txSlot* reference, txString it)
2684
0
{
2685
0
  txSlot* instance = fxToInstance(the, reference);
2686
0
  txSlot* property = instance->next->next->next;
2687
0
  fxDebugEvalBuffer(the, it, property);
2688
0
}
2689
2690
void fxStep(txMachine* the)
2691
0
{
2692
0
  txSlot* aSlot = the->frame;
2693
0
  if (aSlot) {
2694
0
    while (aSlot) {
2695
0
      aSlot->flag &= ~XS_STEP_INTO_FLAG;
2696
0
      aSlot->flag |= XS_STEP_OVER_FLAG;
2697
0
      aSlot = aSlot->next;
2698
0
    }
2699
0
  }
2700
0
  else {
2701
0
    the->breakOnStartFlag = 1;
2702
0
  }
2703
0
}
2704
2705
void fxStepInside(txMachine* the)
2706
0
{
2707
0
  txSlot* aSlot = the->frame;
2708
0
  while (aSlot) {
2709
0
    aSlot->flag |= XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG;
2710
0
    aSlot = aSlot->next;
2711
0
  }
2712
0
}
2713
2714
void fxStepOutside(txMachine* the)
2715
0
{
2716
0
  txSlot* aSlot = the->frame;
2717
0
  if (aSlot) {
2718
0
    aSlot->flag &= ~(XS_STEP_INTO_FLAG | XS_STEP_OVER_FLAG);
2719
0
    aSlot = aSlot->next;
2720
0
    while (aSlot) {
2721
0
      aSlot->flag &= ~XS_STEP_INTO_FLAG;
2722
0
      aSlot->flag |= XS_STEP_OVER_FLAG;
2723
0
      aSlot = aSlot->next;
2724
0
    }
2725
0
  }
2726
0
}
2727
2728
txSlot* fxToInstanceInspector(txMachine* the, txSlot* slot)
2729
0
{
2730
0
  txSlot* instanceInspector = mxInstanceInspectors.value.list.first;
2731
0
  while (instanceInspector) {
2732
0
    if (instanceInspector->value.instanceInspector.slot == slot)
2733
0
      return instanceInspector;
2734
0
    if (instanceInspector->value.instanceInspector.slot > slot)
2735
0
      break;
2736
0
    instanceInspector = instanceInspector->next;
2737
0
  }
2738
0
  return C_NULL;
2739
0
}
2740
2741
void fxToggle(txMachine* the, txSlot* slot)
2742
0
{
2743
0
  txSlot** instanceInspectorAddress = &(mxInstanceInspectors.value.list.first);
2744
0
  txSlot* instanceInspector;
2745
0
  while ((instanceInspector = *instanceInspectorAddress)) {
2746
0
    if (instanceInspector->value.instanceInspector.slot == slot) {
2747
0
      *instanceInspectorAddress = instanceInspector->next;
2748
0
      return;
2749
0
    }
2750
0
    if (instanceInspector->value.instanceInspector.slot > slot)
2751
0
      break;
2752
0
    instanceInspectorAddress = &(instanceInspector->next);
2753
0
  }
2754
0
  instanceInspector = fxNewSlot(the);
2755
0
  instanceInspector->next = *instanceInspectorAddress;
2756
0
  instanceInspector->kind = XS_INSTANCE_INSPECTOR_KIND;
2757
0
  instanceInspector->value.instanceInspector.slot = slot;
2758
0
  instanceInspector->value.instanceInspector.link = C_NULL;
2759
0
  *instanceInspectorAddress = instanceInspector;
2760
0
}
2761
2762
#endif
2763
2764
void fxBubble(txMachine* the, txInteger flags, void* message, txInteger length, txString conversation)
2765
0
{
2766
0
#ifdef mxDebug
2767
0
  if (fxIsConnected(the)) {
2768
0
    txString path = C_NULL;
2769
0
    txInteger line = 0;
2770
0
    txSlot* frame = the->frame;
2771
0
    while (frame && !path) {
2772
0
      txSlot* environment = mxFrameToEnvironment(frame);
2773
0
      if (environment->ID != XS_NO_ID) {
2774
0
        path = fxGetKeyName(the, environment->ID);
2775
0
        line = environment->value.environment.line;
2776
0
      }
2777
0
      frame = frame->next;
2778
0
    }
2779
0
    fxEchoStart(the);
2780
0
    fxEcho(the, "<bubble name=\"");
2781
0
    if (conversation)
2782
0
      fxEchoString(the, conversation);
2783
0
    fxEcho(the, "\" value=\"");
2784
0
    fxEchoInteger(the, flags);
2785
0
    fxEcho(the, "\"");
2786
0
    fxEchoPathLine(the, path, line);
2787
0
    fxEcho(the, ">");
2788
0
    if (flags & XS_BUBBLE_BINARY) {
2789
0
      txU1* bytes = message;
2790
0
      txInteger byteLength = length;
2791
0
      while (byteLength) {
2792
0
        txU1 byte = c_read8(bytes);
2793
0
        fxEchoCharacter(the, gxHexaDigits[(byte & 0xF0) >> 4]);
2794
0
        fxEchoCharacter(the, gxHexaDigits[(byte & 0x0F)]);  
2795
0
        bytes++;
2796
0
        byteLength--;
2797
0
      }
2798
0
    }
2799
0
    else
2800
0
      fxEchoString(the, message);
2801
0
    fxEcho(the, "</bubble>");
2802
0
    fxEchoStop(the);
2803
0
  }
2804
#elif defined(mxInstrument)
2805
  if (!(flags & XS_BUBBLE_BINARY)) {
2806
    if (conversation)
2807
      fxReport(the, "%s: %s\n", conversation, message);
2808
    else
2809
      fxReport(the, "%s\n", message);
2810
  }
2811
#endif
2812
0
}
2813
2814
void fxFileEvalString(txMachine* the, txString string, txString tag)
2815
0
{
2816
0
  #ifdef mxDebug
2817
0
  if (fxIsConnected(the)) {
2818
0
    fxEchoStart(the);
2819
0
    fxEcho(the, "<eval path=\"");
2820
0
    fxEchoString(the, tag);
2821
0
    fxEcho(the, "\"");
2822
0
    fxEcho(the, ">");
2823
0
    fxEchoString(the, string);
2824
0
    fxEcho(the, "</eval>");
2825
0
    fxEchoStop(the);
2826
0
  }
2827
0
#endif
2828
0
}
2829
2830
void fxReport(txMachine* the, txString theFormat, ...)
2831
35
{
2832
35
  c_va_list arguments;
2833
2834
35
  c_va_start(arguments, theFormat);
2835
35
  fxVReport(the, theFormat, arguments);
2836
35
  c_va_end(arguments);
2837
#ifndef mxNoConsole
2838
  c_va_start(arguments, theFormat);
2839
  c_vprintf(theFormat, arguments);
2840
  c_va_end(arguments);
2841
#endif
2842
35
}
2843
2844
void fxReportException(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2845
2.66M
{
2846
2.66M
  c_va_list arguments;
2847
2848
2.66M
  c_va_start(arguments, theFormat);
2849
2.66M
  fxVReportException(the, thePath, theLine, theFormat, arguments);
2850
2.66M
  c_va_end(arguments);
2851
#ifndef mxNoConsole
2852
  if (thePath && theLine)
2853
#if mxWindows
2854
    printf("%s(%d): exception: ", thePath, (int)theLine);
2855
#else
2856
    c_printf("%s:%d: exception: ", thePath, (int)theLine);
2857
#endif
2858
  else
2859
    c_printf("# exception: ");
2860
  c_va_start(arguments, theFormat);
2861
  c_vprintf(theFormat, arguments);
2862
  c_va_end(arguments);
2863
  c_printf("!\n");
2864
#endif
2865
2.66M
}
2866
2867
void fxReportError(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2868
0
{
2869
0
  c_va_list arguments;
2870
2871
0
  c_va_start(arguments, theFormat);
2872
0
  fxVReportError(the, thePath, theLine, theFormat, arguments);
2873
0
  c_va_end(arguments);
2874
#ifndef mxNoConsole
2875
  if (thePath && theLine)
2876
#if mxWindows
2877
    printf("%s(%d): error: ", thePath, (int)theLine);
2878
#else
2879
    c_printf("%s:%d: error: ", thePath, (int)theLine);
2880
#endif
2881
  else
2882
    c_printf("# error: ");
2883
  c_va_start(arguments, theFormat);
2884
  c_vprintf(theFormat, arguments);
2885
  c_va_end(arguments);
2886
  c_printf("!\n");
2887
#endif
2888
0
}
2889
2890
void fxReportWarning(txMachine* the, txString thePath, txInteger theLine, txString theFormat, ...)
2891
0
{
2892
0
  c_va_list arguments;
2893
2894
0
  c_va_start(arguments, theFormat);
2895
0
  fxVReportWarning(the, thePath, theLine, theFormat, arguments);
2896
0
  c_va_end(arguments);
2897
#ifndef mxNoConsole
2898
  if (thePath && theLine)
2899
#if mxWindows
2900
    printf("%s(%d): warning: ", thePath, (int)theLine);
2901
#else
2902
    c_printf("%s:%d: warning: ", thePath, (int)theLine);
2903
#endif
2904
  else
2905
    c_printf("# warning: ");
2906
  c_va_start(arguments, theFormat);
2907
  c_vprintf(theFormat, arguments);
2908
  c_va_end(arguments);
2909
  c_printf("!\n");
2910
#endif
2911
0
}
2912
2913
txID fxGenerateProfileID(void* console)
2914
17.5M
{
2915
17.5M
  txMachine* the = console;
2916
17.5M
  txID id = the->profileID;
2917
17.5M
  the->profileID++;
2918
17.5M
  return id;
2919
17.5M
}
2920
2921
void fxGenerateTag(void* console, txString buffer, txInteger bufferSize, txString path)
2922
2.26M
{
2923
2.26M
  txMachine* the = console;
2924
2.26M
  if (path)
2925
369
    c_snprintf(buffer, bufferSize, "#%d@%s", the->tag, path);
2926
2.25M
  else
2927
2.25M
    c_snprintf(buffer, bufferSize, "#%d", the->tag);
2928
2.26M
  the->tag++;
2929
2.26M
}
2930
2931
void fxVReport(void* console, txString theFormat, c_va_list theArguments)
2932
35
{
2933
35
#ifdef mxDebug
2934
35
  txMachine* the = console;
2935
35
  if (fxIsConnected(the)) {
2936
0
    fxEchoStart(the);
2937
0
    fxEcho(the, "<log>");
2938
0
    fxEchoFormat(the, theFormat, theArguments);
2939
0
    fxEcho(the, "</log>");
2940
0
    fxEchoStop(the);
2941
0
  }
2942
#elif defined(nrf52) && defined(mxInstrument)
2943
  char buf[256];
2944
  vsnprintf(buf, 256, theFormat, theArguments);
2945
  modLog_transmit(buf);
2946
#elif defined(DEBUG_EFM)
2947
  memmove(_lastDebugStrBuffer, _debugStrBuffer, 256);
2948
  vsprintf(_debugStrBuffer, theFormat, theArguments);
2949
  _debugStrBuffer[255] = '\0';
2950
#endif
2951
35
}
2952
2953
void fxVReportException(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
2954
2.66M
{
2955
2.66M
#ifdef mxDebug
2956
2.66M
  txMachine* the = console;
2957
2.66M
  if (fxIsConnected(the)) {
2958
0
    fxEchoStart(the);
2959
0
    fxEcho(the, "<log");
2960
0
    fxEchoPathLine(the, thePath, theLine);
2961
0
    fxEcho(the, "># Exception: ");
2962
0
    fxEchoFormat(the, theFormat, theArguments);
2963
0
    fxEcho(the, "!\n</log>");
2964
0
    fxEchoStop(the);
2965
0
  }
2966
#elif defined(nrf52) && defined(mxInstrument)
2967
  char buf[256];
2968
  if (thePath && theLine)
2969
    c_snprintf(buf, 256, "%s:%d: exception: ", thePath, (int)theLine);
2970
  else
2971
    c_snprintf(buf, 256, "# exception: ");
2972
  modLog_transmit(buf);
2973
  c_snprintf(buf, 256, theFormat, theArguments);
2974
  modLog_transmit(buf);
2975
#elif defined(DEBUG_EFM)
2976
  if (thePath && theLine)
2977
    sprintf(_debugStrBuffer, "%s:%d: exception: ", thePath, (int)theLine);
2978
  else
2979
    sprintf(_debugStrBuffer, "# exception: ");
2980
  memmove(_lastDebugStrBuffer, _debugStrBuffer, 256);
2981
  vsprintf(_debugStrBuffer, theFormat, theArguments);
2982
  _debugStrBuffer[255] = '\0';
2983
#endif
2984
2.66M
}
2985
2986
void fxVReportError(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
2987
570k
{
2988
570k
#ifdef mxDebug
2989
570k
  txMachine* the = console;
2990
570k
  if (fxIsConnected(the)) {
2991
0
    fxEchoStart(the);
2992
0
    fxEcho(the, "<log");
2993
0
    fxEchoPathLine(the, thePath, theLine);
2994
0
    fxEcho(the, "># Error: ");
2995
0
    fxEchoFormat(the, theFormat, theArguments);
2996
0
    fxEcho(the, "!\n</log>");
2997
0
    fxEchoStop(the);
2998
0
  }
2999
#elif defined(nrf52) && defined(mxInstrument)
3000
  char buf[256];
3001
  if (thePath && theLine)
3002
    c_snprintf(buf, 256, "%s:%d: error: ", thePath, (int)theLine);
3003
  else
3004
    c_snprintf(buf, 256, "# error: ");
3005
  modLog_transmit(buf);
3006
  c_snprintf(buf, 256, theFormat, theArguments);
3007
  modLog_transmit(buf);
3008
#elif defined(DEBUG_EFM)
3009
  if (thePath && theLine)
3010
    sprintf(_debugStrBuffer, "%s:%d: error: ", thePath, (int)theLine);
3011
  else
3012
    sprintf(_debugStrBuffer, "# error: ");
3013
  vsprintf(_debugStrBuffer, theFormat, theArguments);
3014
  _debugStrBuffer[255] = '\0';
3015
#endif
3016
570k
}
3017
3018
void fxVReportWarning(void* console, txString thePath, txInteger theLine, txString theFormat, c_va_list theArguments)
3019
0
{
3020
0
#ifdef mxDebug
3021
0
  txMachine* the = console;
3022
0
  if (fxIsConnected(the)) {
3023
0
    fxEchoStart(the);
3024
0
    fxEcho(the, "<log");
3025
0
    fxEchoPathLine(the, thePath, theLine);
3026
0
    fxEcho(the, "># Warning: ");
3027
0
    fxEchoFormat(the, theFormat, theArguments);
3028
0
    fxEcho(the, "!\n</log>");
3029
0
    fxEchoStop(the);
3030
0
  }
3031
0
#endif
3032
#if defined(DEBUG_EFM)
3033
  if (thePath && theLine)
3034
    sprintf(_debugStrBuffer, "%s:%d: warning: ", thePath, (int)theLine);
3035
  else
3036
    sprintf(_debugStrBuffer, "# warning: ");
3037
  vsprintf(_debugStrBuffer, theFormat, theArguments);
3038
  _debugStrBuffer[255] = '\0';
3039
#endif
3040
0
}
3041
3042
#ifdef mxInstrument 
3043
#if kCPUESP32C6 || kCPUESP32H2
3044
#define ICACHE_XS6STRING_ATTR
3045
#endif
3046
#define xsInstrumentCount 12
3047
static char* const xsInstrumentNames[xsInstrumentCount] ICACHE_XS6STRING_ATTR = {
3048
  "Chunk used",
3049
  "Chunk available",
3050
  "Slot used",
3051
  "Slot available",
3052
  "Stack used",
3053
  "Stack available",
3054
  "Garbage collections",
3055
  "Keys used",
3056
  "Modules loaded",
3057
  "Parser used",
3058
  "Floating Point",
3059
  "Promises settled"
3060
};
3061
static char* const xsInstrumentUnits[xsInstrumentCount] ICACHE_XS6STRING_ATTR = {
3062
  " / ",
3063
  " bytes",
3064
  " / ",
3065
  " bytes",
3066
  " / ",
3067
  " bytes",
3068
  " times",
3069
  " keys",
3070
  " modules",
3071
  " bytes",
3072
  " operations",
3073
  " promises",
3074
};
3075
3076
void fxDescribeInstrumentation(txMachine* the, txInteger count, txString* names, txString* units)
3077
{
3078
  txInteger i, j = 0;
3079
#ifdef mxDebug
3080
  if (fxIsConnected(the)) {
3081
    fxEchoStart(the);
3082
    fxEcho(the, "<instruments>");
3083
    for (i = 0; i < count; i++, j++) {
3084
      fxEcho(the, "<instrument name=\"");
3085
      fxEchoString(the, names[i]);
3086
      fxEcho(the, "\" value=\"");
3087
      fxEchoString(the, units[i]);
3088
      fxEcho(the, "\"/>");
3089
    }
3090
    for (i = 0; i < xsInstrumentCount; i++, j++) {
3091
      fxEcho(the, "<instrument name=\"");
3092
      fxEchoString(the, (txString) xsInstrumentNames[i]);
3093
      fxEcho(the, "\" value=\"");
3094
      fxEchoString(the, (txString) xsInstrumentUnits[i]);
3095
      fxEcho(the, "\"/>");
3096
    }
3097
    fxEcho(the, "</instruments>");
3098
    fxEchoStop(the);
3099
    //fxReceive(the);
3100
    return;
3101
  }
3102
#endif
3103
#ifndef mxNoConsole
3104
  j = 0;
3105
  c_printf("instruments key: ");
3106
  for (i = 0; i < count; i++, j++) {
3107
    if (j)
3108
      c_printf(",");
3109
    c_printf("%s", names[i]);
3110
  }
3111
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3112
    if (j)
3113
      c_printf(",");
3114
    c_printf("%s", xsInstrumentNames[i]);
3115
  }
3116
  c_printf("\n");
3117
#endif
3118
}
3119
3120
void fxSampleInstrumentation(txMachine* the, txInteger count, txInteger* values)
3121
{
3122
  txInteger xsInstrumentValues[xsInstrumentCount];
3123
  xsInstrumentValues[0] = the->currentChunksSize;
3124
  xsInstrumentValues[1] = the->maximumChunksSize;
3125
  xsInstrumentValues[2] = the->currentHeapCount * sizeof(txSlot);
3126
  xsInstrumentValues[3] = the->maximumHeapCount * sizeof(txSlot);
3127
  xsInstrumentValues[4] = (mxPtrDiff(the->stackTop - the->stackPeak)) * sizeof(txSlot);
3128
  xsInstrumentValues[5] = (mxPtrDiff(the->stackTop - the->stackBottom)) * sizeof(txSlot);
3129
  xsInstrumentValues[6] = the->garbageCollectionCount;
3130
  xsInstrumentValues[7] = the->keyIndex - the->keyOffset - the->keyholeCount;
3131
  xsInstrumentValues[8] = the->loadedModulesCount;
3132
  xsInstrumentValues[9] = the->peakParserSize;
3133
  xsInstrumentValues[10] = the->floatingPointOps;
3134
  xsInstrumentValues[11] = the->promisesSettledCount;
3135
3136
  txInteger i, j = 0;
3137
#ifdef mxDebug
3138
  if (fxIsConnected(the)) {
3139
    fxEchoStart(the);
3140
    fxEcho(the, "<samples>");
3141
    for (i = 0; i < count; i++, j++) {
3142
      if (j)
3143
        fxEcho(the, ",");
3144
      fxEchoInteger(the, values[i]);
3145
    }
3146
    for (i = 0; i < xsInstrumentCount; i++, j++) {
3147
      if (j)
3148
        fxEcho(the, ",");
3149
      fxEchoInteger(the, xsInstrumentValues[i]);
3150
    }
3151
    fxEcho(the, "</samples>");
3152
    fxEchoStop(the);
3153
    return;
3154
  }
3155
#endif
3156
#ifndef mxNoConsole
3157
  j = 0;
3158
  c_printf("instruments: ");
3159
  for (i = 0; i < count; i++, j++) {
3160
    if (j)
3161
      c_printf(",");
3162
    c_printf("%d", values[i]);
3163
  }
3164
  for (i = 0; i < xsInstrumentCount; i++, j++) {
3165
    if (j)
3166
      c_printf(",");
3167
    c_printf("%d", xsInstrumentValues[i]);
3168
  }
3169
  c_printf("\n");
3170
#endif
3171
}
3172
3173
#if defined(modMicrosecondsInstrumentation) || defined(modMicroseconds)
3174
  typedef txU4 txMicroseconds;
3175
#else
3176
  typedef txU8 txMicroseconds;
3177
#endif
3178
3179
#define mxProfilerSampleCount 8
3180
3181
typedef struct sxProfiler txProfiler;
3182
struct sxProfiler {
3183
  txMicroseconds when;
3184
  txMicroseconds former;
3185
//  txMicroseconds start;
3186
  txMicroseconds stop;
3187
  txU4 interval;
3188
  txSize recordCount;
3189
  txByte* records;
3190
  txSize sampleIndex;
3191
  txSize sampleSize;
3192
  txID* samples;
3193
  txU4 deltas[mxProfilerSampleCount];
3194
};
3195
3196
static void fxEchoUnsigned(txMachine* the, txUnsigned value, txInteger radix);
3197
static txID fxFrameToProfilerID(txMachine* the, txSlot* frame);
3198
static txMicroseconds fxGetMicroSeconds();
3199
static void fxSendProfilerRecord(txMachine* the, txSlot* frame, txID id, txSlot* code);
3200
static void fxSendProfilerSamples(txMachine* the, txProfiler* profiler);
3201
static void fxSendProfilerTime(txMachine* the, txString name, txMicroseconds when);
3202
3203
void fxCheckProfiler(txMachine* the, txSlot* frame)
3204
{
3205
  txProfiler* profiler = the->profiler;
3206
  if (!profiler)
3207
    return;
3208
  txMicroseconds when = profiler->when;
3209
  txMicroseconds time = fxGetMicroSeconds();
3210
  if (when <= time) {
3211
    txSize sampleIndex = profiler->sampleIndex;
3212
    txSize sampleSize = profiler->sampleSize;
3213
    txID* samples = profiler->samples + (sampleIndex * sampleSize);
3214
    txU4 interval = profiler->interval;
3215
    profiler->deltas[sampleIndex] = (txU4)(time - profiler->former);
3216
    profiler->former = time;
3217
    profiler->when = time + interval - (time % interval);
3218
    if (!frame) {
3219
      frame = the->frame;
3220
      if (frame)
3221
        *samples++ = 1;
3222
    }
3223
    while (frame) {
3224
      txID id = fxFrameToProfilerID(the, frame);
3225
      if (id)
3226
        *samples++ = id;
3227
      frame = frame->next;
3228
    }
3229
    *samples++ = 0;
3230
    sampleIndex++;
3231
    if (sampleIndex == mxProfilerSampleCount) {
3232
      fxSendProfilerSamples(the, profiler);
3233
      sampleIndex = 0;
3234
    }
3235
    profiler->sampleIndex = sampleIndex;
3236
  }
3237
}
3238
3239
void fxCreateProfiler(txMachine* the)
3240
{
3241
  txProfiler* profiler = the->profiler = c_malloc(sizeof(txProfiler));
3242
  if (profiler == C_NULL)
3243
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3244
  profiler->interval = 1250;
3245
  profiler->former = fxGetMicroSeconds();
3246
  profiler->when = profiler->former + profiler->interval;
3247
  
3248
  profiler->recordCount = 128;
3249
  profiler->records = c_calloc(1, profiler->recordCount);
3250
  if (profiler->records == C_NULL)
3251
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3252
3253
  profiler->sampleIndex = 0;
3254
  profiler->sampleSize = (the->stackTop - the->stackBottom) >> 3;
3255
  profiler->samples = (txID*)c_malloc((size_t)(mxProfilerSampleCount * profiler->sampleSize * sizeof(txID)));
3256
  if (profiler->samples == C_NULL)
3257
    fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3258
3259
  fxSendProfilerTime(the, "start", profiler->former);
3260
  fxSendProfilerRecord(the, C_NULL, 0, C_NULL);
3261
  fxSendProfilerRecord(the, C_NULL, 1, C_NULL);
3262
  profiler->records[0] = 0x03;
3263
}
3264
3265
void fxDeleteProfiler(txMachine* the, void* stream)
3266
{
3267
  txProfiler* profiler = the->profiler;
3268
  fxSendProfilerTime(the, "stop", fxGetMicroSeconds());
3269
  c_free(profiler->samples);
3270
  c_free(profiler->records);
3271
  c_free(profiler);
3272
  the->profiler = C_NULL;
3273
}
3274
3275
#ifdef mxDebug
3276
void fxEchoUnsigned(txMachine* the, txUnsigned value, txInteger radix)
3277
{
3278
  char buffer[256];
3279
  char *p = &buffer[sizeof(buffer) - 1];
3280
  *p-- = 0;
3281
  do {
3282
    *p-- = c_read8(gxHexaDigits + (value % radix));
3283
    value /= radix;
3284
  } while (value);
3285
  fxEcho(the, p + 1);
3286
}
3287
#endif
3288
3289
txID fxFrameToProfilerID(txMachine* the, txSlot* frame)
3290
{
3291
  txProfiler* profiler = the->profiler;
3292
  txSlot* function = frame + 3;
3293
  txSlot* code = C_NULL;
3294
  txID id = XS_NO_ID;
3295
  if (function->kind == XS_REFERENCE_KIND) {
3296
    function = function->value.reference;
3297
    if (mxIsFunction(function)) {
3298
      code = mxFunctionInstanceCode(function);
3299
      id = mxFunctionInstanceHome(function)->ID;
3300
    }
3301
  }
3302
#if mxHostFunctionPrimitive
3303
  else if (function->kind == XS_HOST_FUNCTION_KIND)
3304
    id = function->value.hostFunction.profileID;
3305
#endif
3306
  if (id != XS_NO_ID) {   
3307
    txInteger recordIndex = id >> 3;
3308
    txInteger recordMask = 1 << (id & 0x07);
3309
    txInteger recordCount = profiler->recordCount;
3310
    if (recordIndex >= recordCount) {
3311
      while (recordIndex >= recordCount)
3312
        recordCount += 128;
3313
      profiler->records = c_realloc(profiler->records, recordCount);
3314
      if (profiler->records == C_NULL)
3315
        fxAbort(the, XS_NOT_ENOUGH_MEMORY_EXIT);
3316
      c_memset(profiler->records + profiler->recordCount, 0, (recordCount - profiler->recordCount));
3317
      profiler->recordCount = recordCount;
3318
    }
3319
    else if (profiler->records[recordIndex] & recordMask)
3320
      return id;
3321
    profiler->records[recordIndex] |= recordMask;
3322
    fxSendProfilerRecord(the, frame, id, code);
3323
    return id;
3324
  }
3325
  return 0;
3326
}
3327
3328
txMicroseconds fxGetMicroSeconds()
3329
{
3330
#if defined(modMicrosecondsInstrumentation)
3331
  return modMicrosecondsInstrumentation();
3332
#elif defined(modMicroseconds)
3333
  return modMicroseconds();
3334
#else
3335
  c_timeval tv;
3336
  c_gettimeofday(&tv, NULL);
3337
  return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
3338
#endif
3339
}
3340
3341
void fxResumeProfiler(txMachine* the)
3342
{
3343
  txProfiler* profiler = the->profiler;
3344
  if (!profiler)
3345
    return;
3346
  txMicroseconds delta = fxGetMicroSeconds();
3347
  fxSendProfilerTime(the, "resume", delta);
3348
  delta -= profiler->stop;
3349
  profiler->when += delta;
3350
  profiler->former += delta;
3351
}
3352
3353
void fxSendProfilerRecord(txMachine* the, txSlot* frame, txID id, txSlot* code)
3354
{
3355
#ifdef mxDebug
3356
  if (fxIsConnected(the)) {
3357
    fxEchoStart(the);
3358
    if (id == 0) {
3359
      fxEcho(the, "<pr name=\"(host)\" value=\"0\"");
3360
    }
3361
    else if (id == 1) {
3362
      fxEcho(the, "<pr name=\"(gc)\" value=\"1\"");
3363
    }
3364
    else {
3365
      fxEcho(the, "<pr name=\"");
3366
      fxEchoFrameName(the, frame);
3367
      fxEcho(the, "\" value=\"");
3368
      fxEchoInteger(the, id);
3369
      fxEcho(the, "\"");
3370
    }
3371
    if (code) {
3372
      if ((code->kind == XS_CODE_KIND) || (code->kind == XS_CODE_X_KIND)) {
3373
        txByte* p = code->value.code.address + 2;
3374
        if (*p == XS_CODE_FILE) {
3375
          txID file;
3376
          txS2 line;
3377
          p++;
3378
          mxDecodeID(p, file);
3379
          p++;
3380
          mxDecode2(p, line);
3381
          fxEchoPathLine(the, fxGetKeyName(the, file), line);
3382
        }
3383
      }
3384
    }
3385
    fxEcho(the, "/>");
3386
    fxEchoStop(the);
3387
  }
3388
#endif
3389
}
3390
3391
void fxSendProfilerSamples(txMachine* the, txProfiler* profiler)
3392
{
3393
#ifdef mxDebug
3394
  if (fxIsConnected(the)) {
3395
    txID* samples = profiler->samples;
3396
    txSize sampleSize = profiler->sampleSize;
3397
    txSize sampleIndex = 0;
3398
    txID* ids;
3399
    txID id;
3400
    fxEchoStart(the);
3401
    fxEcho(the, "<ps>");
3402
    for (;;) {
3403
      fxEchoUnsigned(the, profiler->deltas[sampleIndex], 36);
3404
      ids = samples;
3405
      while ((id = *ids++)) {
3406
        fxEcho(the, ",");
3407
        fxEchoUnsigned(the, id, 36);
3408
      }
3409
      sampleIndex++;
3410
      if (sampleIndex < mxProfilerSampleCount) 
3411
        fxEcho(the, ",0.");
3412
      else {
3413
        fxEcho(the, ",0</ps>");
3414
        break;
3415
      }
3416
      samples += sampleSize;
3417
    }
3418
    fxEchoStop(the);
3419
  }
3420
#endif
3421
}
3422
3423
void fxSendProfilerTime(txMachine* the, txString name, txMicroseconds when)
3424
{
3425
#ifdef mxDebug
3426
  if (fxIsConnected(the)) {
3427
    int shift;
3428
    fxEchoStart(the);
3429
    fxEcho(the, "<pt name=\"");
3430
    fxEchoString(the, name);
3431
    fxEcho(the, "\" value=\"@");
3432
    shift = (8 * sizeof(when)) - 4;
3433
    while (shift >= 0) {
3434
      fxEchoCharacter(the, c_read8(gxHexaDigits + ((when >> shift) & 0x0F)));
3435
      shift -= 4;
3436
    }
3437
    fxEcho(the, "\"/>");
3438
    fxEchoStop(the);
3439
  }
3440
#endif
3441
}
3442
3443
void fxSuspendProfiler(txMachine* the)
3444
{
3445
  txProfiler* profiler = the->profiler;
3446
  if (!profiler)
3447
    return;
3448
  profiler->stop = fxGetMicroSeconds();
3449
  fxSendProfilerTime(the, "suspend", profiler->stop);
3450
}
3451
3452
#endif /* mxInstrument */