void CacheIRSpewer::valueProperty(LockGuard<Mutex>&, const char* name, const Value& v) { MOZ_ASSERT(enabled()); JSONPrinter& j = json.ref(); j.beginObjectProperty(name); const char* type = InformalValueTypeName(v); if (v.isInt32()) type = "int32"; j.property("type", type); if (v.isInt32()) { j.property("value", v.toInt32()); } else if (v.isDouble()) { j.floatProperty("value", v.toDouble(), 3); } else if (v.isString() || v.isSymbol()) { JSString* str = v.isString() ? v.toString() : v.toSymbol()->description(); if (str && str->isLinear()) { j.beginStringProperty("value"); QuoteString(output, &str->asLinear()); j.endStringProperty(); } } else if (v.isObject()) { j.formatProperty("value", "%p (shape: %p)", &v.toObject(), v.toObject().maybeShape()); } j.endObject(); }
/* * The function tries to scan the whole rope tree using the marking stack as * temporary storage. If that becomes full, the unscanned ropes are added to * the delayed marking list. When the function returns, the marking stack is * at the same depth as it was on entry. This way we avoid using tags when * pushing ropes to the stack as ropes never leaks to other users of the * stack. This also assumes that a rope can only point to other ropes or * linear strings, it cannot refer to GC things of other types. */ static void ScanRope(GCMarker *gcmarker, JSRope *rope) { ptrdiff_t savedPos = gcmarker->stack.position(); for (;;) { JS_ASSERT(GetGCThingTraceKind(rope) == JSTRACE_STRING); JS_ASSERT(rope->JSString::isRope()); JS_COMPARTMENT_ASSERT_STR(gcmarker->runtime, rope); JS_ASSERT(rope->isMarked()); JSRope *next = NULL; JSString *right = rope->rightChild(); if (right->markIfUnmarked()) { if (right->isLinear()) ScanLinearString(gcmarker, &right->asLinear()); else next = &right->asRope(); } JSString *left = rope->leftChild(); if (left->markIfUnmarked()) { if (left->isLinear()) { ScanLinearString(gcmarker, &left->asLinear()); } else { /* * When both children are ropes, set aside the right one to * scan it later. */ if (next && !gcmarker->stack.push(reinterpret_cast<uintptr_t>(next))) gcmarker->delayMarkingChildren(next); next = &left->asRope(); } } if (next) { rope = next; } else if (savedPos != gcmarker->stack.position()) { JS_ASSERT(savedPos < gcmarker->stack.position()); rope = reinterpret_cast<JSRope *>(gcmarker->stack.pop()); } else { break; } } JS_ASSERT(savedPos == gcmarker->stack.position()); }
bool GetPropIRGenerator::tryAttachStringChar(ValOperandId valId, ValOperandId indexId) { MOZ_ASSERT(idVal_.isInt32()); if (!val_.isString()) return false; JSString* str = val_.toString(); int32_t index = idVal_.toInt32(); if (size_t(index) >= str->length() || !str->isLinear() || str->asLinear().latin1OrTwoByteChar(index) >= StaticStrings::UNIT_STATIC_LIMIT) { return false; } StringOperandId strId = writer.guardIsString(valId); Int32OperandId int32IndexId = writer.guardIsInt32(indexId); writer.loadStringCharResult(strId, int32IndexId); writer.returnFromIC(); return true; }
JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing, JS::TraceKind kind, bool details) { const char* name = nullptr; /* silence uninitialized warning */ size_t n; if (bufsize == 0) return; switch (kind) { case JS::TraceKind::Object: { name = static_cast<JSObject*>(thing)->getClass()->name; break; } case JS::TraceKind::Script: name = "script"; break; case JS::TraceKind::String: name = ((JSString*)thing)->isDependent() ? "substring" : "string"; break; case JS::TraceKind::Symbol: name = "symbol"; break; case JS::TraceKind::BaseShape: name = "base_shape"; break; case JS::TraceKind::JitCode: name = "jitcode"; break; case JS::TraceKind::LazyScript: name = "lazyscript"; break; case JS::TraceKind::Shape: name = "shape"; break; case JS::TraceKind::ObjectGroup: name = "object_group"; break; default: name = "INVALID"; break; } n = strlen(name); if (n > bufsize - 1) n = bufsize - 1; js_memcpy(buf, name, n + 1); buf += n; bufsize -= n; *buf = '\0'; if (details && bufsize > 2) { switch (kind) { case JS::TraceKind::Object: { JSObject* obj = (JSObject*)thing; if (obj->is<JSFunction>()) { JSFunction* fun = &obj->as<JSFunction>(); if (fun->displayAtom()) { *buf++ = ' '; bufsize--; PutEscapedString(buf, bufsize, fun->displayAtom(), 0); } } else if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE) { JS_snprintf(buf, bufsize, " %p", obj->as<NativeObject>().getPrivate()); } else { JS_snprintf(buf, bufsize, " <no private>"); } break; } case JS::TraceKind::Script: { JSScript* script = static_cast<JSScript*>(thing); JS_snprintf(buf, bufsize, " %s:%" PRIuSIZE, script->filename(), script->lineno()); break; } case JS::TraceKind::String: { *buf++ = ' '; bufsize--; JSString* str = (JSString*)thing; if (str->isLinear()) { bool willFit = str->length() + strlen("<length > ") + CountDecimalDigits(str->length()) < bufsize; n = JS_snprintf(buf, bufsize, "<length %d%s> ", (int)str->length(), willFit ? "" : " (truncated)"); buf += n; bufsize -= n; PutEscapedString(buf, bufsize, &str->asLinear(), 0); } else { JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length()); } break; } case JS::TraceKind::Symbol: { JS::Symbol* sym = static_cast<JS::Symbol*>(thing); if (JSString* desc = sym->description()) { if (desc->isLinear()) { *buf++ = ' '; bufsize--; PutEscapedString(buf, bufsize, &desc->asLinear(), 0); } else { JS_snprintf(buf, bufsize, "<nonlinear desc>"); } } else { JS_snprintf(buf, bufsize, "<null>"); } break; } default: break; } } buf[bufsize - 1] = '\0'; }
void GCMarker::dumpConservativeRoots() { if (!conservativeDumpFileName) return; FILE *fp; if (!strcmp(conservativeDumpFileName, "stdout")) { fp = stdout; } else if (!strcmp(conservativeDumpFileName, "stderr")) { fp = stderr; } else if (!(fp = fopen(conservativeDumpFileName, "aw"))) { fprintf(stderr, "Warning: cannot open %s to dump the conservative roots\n", conservativeDumpFileName); return; } conservativeStats.dump(fp); for (void **thingp = conservativeRoots.begin(); thingp != conservativeRoots.end(); ++thingp) { void *thing = thingp; fprintf(fp, " %p: ", thing); switch (GetGCThingTraceKind(thing)) { default: JS_NOT_REACHED("Unknown trace kind"); case JSTRACE_OBJECT: { JSObject *obj = (JSObject *) thing; fprintf(fp, "object %s", obj->getClass()->name); break; } case JSTRACE_SHAPE: { fprintf(fp, "shape"); break; } case JSTRACE_STRING: { JSString *str = (JSString *) thing; if (str->isLinear()) { char buf[50]; PutEscapedString(buf, sizeof buf, &str->asLinear(), '"'); fprintf(fp, "string %s", buf); } else { fprintf(fp, "rope: length %d", (int)str->length()); } break; } # if JS_HAS_XML_SUPPORT case JSTRACE_XML: { JSXML *xml = (JSXML *) thing; fprintf(fp, "xml %u", (unsigned)xml->xml_class); break; } # endif } fputc('\n', fp); } fputc('\n', fp); if (fp != stdout && fp != stderr) fclose(fp); }
JS_GetTraceThingInfo(char *buf, size_t bufsize, JSTracer *trc, void *thing, JSGCTraceKind kind, bool details) { const char *name = nullptr; /* silence uninitialized warning */ size_t n; if (bufsize == 0) return; switch (kind) { case JSTRACE_OBJECT: { name = static_cast<JSObject *>(thing)->getClass()->name; break; } case JSTRACE_STRING: name = ((JSString *)thing)->isDependent() ? "substring" : "string"; break; case JSTRACE_SCRIPT: name = "script"; break; case JSTRACE_LAZY_SCRIPT: name = "lazyscript"; break; case JSTRACE_JITCODE: name = "jitcode"; break; case JSTRACE_SHAPE: name = "shape"; break; case JSTRACE_BASE_SHAPE: name = "base_shape"; break; case JSTRACE_TYPE_OBJECT: name = "type_object"; break; } n = strlen(name); if (n > bufsize - 1) n = bufsize - 1; js_memcpy(buf, name, n + 1); buf += n; bufsize -= n; *buf = '\0'; if (details && bufsize > 2) { switch (kind) { case JSTRACE_OBJECT: { JSObject *obj = (JSObject *)thing; if (obj->is<JSFunction>()) { JSFunction *fun = &obj->as<JSFunction>(); if (fun->displayAtom()) { *buf++ = ' '; bufsize--; PutEscapedString(buf, bufsize, fun->displayAtom(), 0); } } else if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE) { JS_snprintf(buf, bufsize, " %p", obj->getPrivate()); } else { JS_snprintf(buf, bufsize, " <no private>"); } break; } case JSTRACE_STRING: { *buf++ = ' '; bufsize--; JSString *str = (JSString *)thing; if (str->isLinear()) { bool willFit = str->length() + strlen("<length > ") + CountDecimalDigits(str->length()) < bufsize; n = JS_snprintf(buf, bufsize, "<length %d%s> ", (int)str->length(), willFit ? "" : " (truncated)"); buf += n; bufsize -= n; PutEscapedString(buf, bufsize, &str->asLinear(), 0); } else JS_snprintf(buf, bufsize, "<rope: length %d>", (int)str->length()); break; } case JSTRACE_SCRIPT: { JSScript *script = static_cast<JSScript *>(thing); JS_snprintf(buf, bufsize, " %s:%u", script->filename(), unsigned(script->lineno())); break; } case JSTRACE_LAZY_SCRIPT: case JSTRACE_JITCODE: case JSTRACE_SHAPE: case JSTRACE_BASE_SHAPE: case JSTRACE_TYPE_OBJECT: break; } } buf[bufsize - 1] = '\0'; }
JS_PUBLIC_API void JS_GetTraceThingInfo(char* buf, size_t bufsize, JSTracer* trc, void* thing, JS::TraceKind kind, bool details) { const char* name = nullptr; /* silence uninitialized warning */ size_t n; if (bufsize == 0) { return; } switch (kind) { case JS::TraceKind::BaseShape: name = "base_shape"; break; case JS::TraceKind::JitCode: name = "jitcode"; break; case JS::TraceKind::LazyScript: name = "lazyscript"; break; case JS::TraceKind::Null: name = "null_pointer"; break; case JS::TraceKind::Object: { name = static_cast<JSObject*>(thing)->getClass()->name; break; } case JS::TraceKind::ObjectGroup: name = "object_group"; break; case JS::TraceKind::RegExpShared: name = "reg_exp_shared"; break; case JS::TraceKind::Scope: name = "scope"; break; case JS::TraceKind::Script: name = "script"; break; case JS::TraceKind::Shape: name = "shape"; break; case JS::TraceKind::String: name = ((JSString*)thing)->isDependent() ? "substring" : "string"; break; case JS::TraceKind::Symbol: name = "symbol"; break; #ifdef ENABLE_BIGINT case JS::TraceKind::BigInt: name = "BigInt"; break; #endif default: name = "INVALID"; break; } n = strlen(name); if (n > bufsize - 1) { n = bufsize - 1; } js_memcpy(buf, name, n + 1); buf += n; bufsize -= n; *buf = '\0'; if (details && bufsize > 2) { switch (kind) { case JS::TraceKind::Object: { JSObject* obj = (JSObject*)thing; if (obj->is<JSFunction>()) { JSFunction* fun = &obj->as<JSFunction>(); if (fun->displayAtom()) { *buf++ = ' '; bufsize--; PutEscapedString(buf, bufsize, fun->displayAtom(), 0); } } else if (obj->getClass()->flags & JSCLASS_HAS_PRIVATE) { snprintf(buf, bufsize, " %p", obj->as<NativeObject>().getPrivate()); } else { snprintf(buf, bufsize, " <no private>"); } break; } case JS::TraceKind::Script: { JSScript* script = static_cast<JSScript*>(thing); snprintf(buf, bufsize, " %s:%u", script->filename(), script->lineno()); break; } case JS::TraceKind::LazyScript: { LazyScript* script = static_cast<LazyScript*>(thing); snprintf(buf, bufsize, " %s:%u", script->filename(), script->lineno()); break; } case JS::TraceKind::String: { *buf++ = ' '; bufsize--; JSString* str = (JSString*)thing; if (str->isLinear()) { const char* header = StringKindHeader(str); bool willFit = str->length() + strlen("<length > ") + strlen(header) + CountDecimalDigits(str->length()) < bufsize; n = snprintf(buf, bufsize, "<%slength %zu%s> ", header, str->length(), willFit ? "" : " (truncated)"); buf += n; bufsize -= n; PutEscapedString(buf, bufsize, &str->asLinear(), 0); } else { snprintf(buf, bufsize, "<rope: length %zu>", str->length()); } break; } case JS::TraceKind::Symbol: { JS::Symbol* sym = static_cast<JS::Symbol*>(thing); if (JSString* desc = sym->description()) { if (desc->isLinear()) { *buf++ = ' '; bufsize--; PutEscapedString(buf, bufsize, &desc->asLinear(), 0); } else { snprintf(buf, bufsize, "<nonlinear desc>"); } } else { snprintf(buf, bufsize, "<null>"); } break; } case JS::TraceKind::Scope: { js::Scope* scope = static_cast<js::Scope*>(thing); snprintf(buf, bufsize, " %s", js::ScopeKindString(scope->kind())); break; } default: break; } } buf[bufsize - 1] = '\0'; }