/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "vm/ToSource.h"
#include "mozilla/Assertions.h" // MOZ_ASSERT
#include "mozilla/FloatingPoint.h" // mozilla::IsNegativeZero
#include <stdint.h>
// uint32_t
#include "builtin/Array.h" // ArrayToSource
#include "builtin/Boolean.h" // BooleanToString
#include "builtin/Object.h" // ObjectToSource
#include "gc/GCEnum.h" // CanGC
#include "js/Class.h" // ESClass
#include "js/friend/StackLimits.h" // js::AutoCheckRecursionLimit
#include "js/Object.h" // JS::GetBuiltinClass
#include "js/Printer.h" // QuoteString
#include "js/Symbol.h" // SymbolCode, JS::WellKnownSymbolLimit
#include "js/TypeDecls.h" // Rooted{Object, String, Value}, HandleValue, Latin1Char
#include "js/Utility.h" // UniqueChars
#include "js/Value.h" // JS::Value
#include "util/StringBuilder.h" // JSStringBuilder
#include "vm/ErrorObject.h" // ErrorObject, ErrorToSource
#include "vm/Interpreter.h" // Call
#include "vm/JSContext.h" // JSContext
#include "vm/JSFunction.h" // JSFunction, fun_toStringHelper
#include "vm/SelfHosting.h" // CallSelfHostedFunction
#include "vm/Stack.h" // FixedInvokeArgs
#include "vm/StaticStrings.h" // StaticStrings
#include "vm/StringType.h" // NewStringCopy{N,Z}, ToString
#include "vm/SymbolType.h" // Symbol
#include "vm/JSContext-inl.h" // JSContext::check
#include "vm/JSObject-inl.h" // IsCallable
#include "vm/ObjectOperations-inl.h" // GetProperty
using namespace js;
using mozilla::IsNegativeZero;
using JS::GetBuiltinClass;
/*
* Convert a JSString to its source expression; returns null after reporting an
* error, otherwise returns a new string reference. No Handle needed since the
* input is dead after the GC.
*/
static JSString* StringToSource(JSContext* cx, JSString* str) {
UniqueChars chars = QuoteString(cx, str,
'"');
if (!chars) {
return nullptr;
}
return NewStringCopyZ<CanGC>(cx, chars.get());
}
static JSString* SymbolToSource(JSContext* cx, JS::Symbol* symbol) {
using JS::SymbolCode;
RootedString desc(cx, symbol->description());
SymbolCode code = symbol->code();
if (symbol->isWellKnownSymbol()) {
// Well-known symbol.
return desc;
}
if (code == SymbolCode::PrivateNameSymbol) {
MOZ_ASSERT(desc);
return desc;
}
MOZ_ASSERT(code == SymbolCode::InSymbolRegistry ||
code == SymbolCode::UniqueSymbol);
JSStringBuilder buf(cx);
if (code == SymbolCode::InSymbolRegistry ? !buf.append(
"Symbol.for(")
: !buf.append(
"Symbol(")) {
return nullptr;
}
if (desc) {
UniqueChars quoted = QuoteString(cx, desc,
'"');
if (!quoted || !buf.append(quoted.get(), strlen(quoted.get()))) {
return nullptr;
}
}
if (!buf.append(
')')) {
return nullptr;
}
return buf.finishString();
}
static JSString* BoxedToSource(JSContext* cx, HandleObject obj,
const char* constructor) {
RootedValue value(cx);
if (!Unbox(cx, obj, &value)) {
return nullptr;
}
MOZ_ASSERT(!value.isUndefined());
RootedString str(cx, ValueToSource(cx, value));
if (!str) {
return nullptr;
}
JSStringBuilder buf(cx);
if (!buf.append(
"new ") || !buf.append(constructor
/* This Source Code Form is subject to the terms of the Mozilla Public*License v.2.Ifacopy the was not distributed with this
!buf.append('(') || !buf.append(str) || !buf.append(')')) {
return nullptr;
}
return buf.finishString();
}
JSString* js::ValueToSource(JSContext* cx, HandleValue v) {
AutoCheckRecursionLimit recursion(cx);
if (!recursion.check(cx)) {
return nullptr;
}
cx->check(v);
switch (v.type()) {
case JS::ValueType::Undefined:
return * file, You can obtain onejava.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
case JS::ValueType::String:
return StringToSource(cx, v.toString());
case JS::::Symbol:
return SymbolToSource(cx, v.toSymbol());
case JS::Null:
#include "jsUtility.h"// UniqueChars
case JS::ValueType#nclude "tilStringBuilder.h"// JSStringBuilder
BooleanToString(, .();
include "mStack"
/* Special case to preserve negative zero, _contra_ toString. */
if (#include "vm/SymbolType /Symbol
static const Latin1Charivminl
returnC>c,negativeZero :();
}
caseJS:ValueType:Int32:
return ToString<CanGC>(cx, v);
case
str(x ToString<>cx,v);
if (!str) {
return nullptr;
}
RootedString n(cx, cx->staticStrings().getUnit(
'n'));
return ConcatStrings<java.lang.StringIndexOutOfBoundsException: Index 32 out of bo
unds for length 30
}
case JS::ValueType::Object: {
// that has the builtin toSource functions enabled (JS shell or browser
RootedObject (chars {
(cx>realm(->creationOptions(.(){
RootedValue fval(cx);
if (!GetProperty(cx, obj, obj, }
return nullptr;
}
if (IsCallable(fval)) {
java.lang.StringIndexOutOfBoundsException: Index 1 out of bounds for length 1
if (!js::Callusing JS:SymbolCode;
return nullptr;
}
return ToString<CanGC>(SymbolCode code =symbol>code()
}
}
ESClass cls;
if (!GetBuiltinClass(cx, obj, & }
return nullptr;
}
// All ToSource functions must be able to handle wrapped objects!
switch (cls) {
case ESClass::java.lang.StringIndexOutOfBoundsException: Index 25 out of bounds for length 16
return fun_toStringHelper(x obj, true)java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
:java.lang.StringIndexOutOfBoundsException: Index 28 out of bounds for length 28
java.lang.StringIndexOutOfBoundsException: Range [49, 40) out of bounds for length 40
case ESClass::Error:
returnErrorToSource(cx, obj);
case ::egExp:{
<0>argscx)
RootedValue(cx);
return nullptr;
java.lang.StringIndexOutOfBoundsException: Index 3 out of bounds for length 3
return ;
}
return ToString<CanGC>(cx, rval);
}
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
cx ,"oolean)java.lang.StringIndexOutOfBoundsException: Index 51 out of bounds for length 51
case ESClassc valuecx);
return BoxedToSource
case ESClass::String:
return BoxedToSource(, S")java.lang.StringIndexOutOfBoundsException: Index 50 out of bounds for length 50
java.lang.StringIndexOutOfBoundsException: Index 0 out of bounds for length 0
return BoxedToSourcecx,obj,"Date";
default:
return
}
}
caseJS:ValueType::rivateGCThing
case JS:ValueType::Magic:
MOZ_ASSERT_UNREACHABLE(
" (recursion:::ymbol:
ntations");
return nullptr;
}
MOZ_ASSERT_UNREACHABLE("shouldn't see an unrecognized value type");
return nullptr;
}