/* 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/SelfHosting.h"
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
# include
"builtin/AsyncDisposableStackObject.h"
# include
"builtin/DisposableStackObject.h"
#endif
#include "mozilla/BinarySearch.h"
#include "mozilla/Maybe.h"
#include "mozilla/ScopeExit.h" // mozilla::MakeScopeExit
#include "mozilla/Utf8.h" // mozilla::Utf8Unit
#include <algorithm>
#include <iterator>
#include "jsfriendapi.h"
#include "selfhosted.out.h"
#include "builtin/Array.h"
#include "builtin/BigInt.h"
#ifdef JS_HAS_INTL_API
# include
"builtin/intl/Segmenter.h"
#endif
#include "builtin/MapObject.h"
#include "builtin/Math.h"
#include "builtin/Number.h"
#include "builtin/Object.h"
#include "builtin/Promise.h"
#include "builtin/Reflect.h"
#include "builtin/RegExp.h"
#include "builtin/SelfHostingDefines.h"
#include "builtin/String.h"
#include "builtin/WeakMapObject.h"
#include "frontend/BytecodeCompiler.h" // CompileGlobalScriptToStencil
#include "frontend/CompilationStencil.h" // js::frontend::CompilationStencil
#include "frontend/FrontendContext.h" // AutoReportFrontendContext
#include "frontend/StencilXdr.h" // js::EncodeStencil, js::DecodeStencil
#include "jit/AtomicOperations.h"
#include "jit/BaselineJIT.h"
#include "jit/InlinableNatives.h"
#include "jit/TrampolineNatives.h"
#include "js/CompilationAndEvaluation.h"
#include "js/Conversions.h"
#include "js/ErrorReport.h" // JS::PrintError
#include "js/experimental/JSStencil.h"
#include "js/experimental/TypedData.h" // JS_GetArrayBufferViewType
#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
#include "js/HashTable.h"
#include "js/Printer.h"
#include "js/PropertySpec.h"
#include "js/ScalarType.h" // js::Scalar::Type
#include "js/SourceText.h" // JS::SourceText
#include "js/TracingAPI.h"
#include "js/Transcoding.h"
#include "js/Warnings.h" // JS::{,Set}WarningReporter
#include "js/Wrapper.h"
#include "vm/ArgumentsObject.h"
#include "vm/AsyncFunction.h"
#include "vm/AsyncIteration.h"
#include "vm/BigIntType.h"
#include "vm/Compression.h"
#include "vm/DateObject.h"
#include "vm/ErrorReporting.h" // js::MaybePrintAndClearPendingException
#include "vm/Float16.h"
#include "vm/FrameIter.h" // js::ScriptFrameIter
#include "vm/GeneratorObject.h"
#include "vm/Interpreter.h"
#include "vm/Iteration.h"
#include "vm/JSAtomUtils.h" // Atomize
#include "vm/JSContext.h"
#include "vm/JSFunction.h"
#include "vm/JSObject.h"
#include "vm/Logging.h"
#include "vm/PlainObject.h" // js::PlainObject
#include "vm/Realm.h"
#include "vm/RegExpObject.h"
#include "vm/StringType.h"
#include "vm/ToSource.h" // js::ValueToSource
#include "vm/TypedArrayObject.h"
#include "vm/Uint8Clamped.h"
#include "vm/WrapperObject.h"
#include "gc/WeakMap-inl.h"
#include "vm/Compartment-inl.h"
#include "vm/JSAtomUtils-inl.h" // PrimitiveValueToId
#include "vm/JSFunction-inl.h"
#include "vm/JSObject-inl.h"
#include "vm/NativeObject-inl.h"
#include "vm/TypedArrayObject-inl.h"
using
namespace js;
using
namespace js::selfhosted;
using JS::CompileOptions;
static bool intrinsic_ToObject(JSContext* cx,
unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
JSObject* obj = ToObject(cx, args[
0 ]);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
static bool intrinsic_IsObject(JSContext* cx,
unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
Value val = args[
0 ];
bool isObject = val.isObject();
args.rval().setBoolean(isObject);
return true;
}
static bool intrinsic_IsArray(JSContext* cx,
unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() ==
1 );
RootedValue val(cx, args[
0 ]);
if (val.isObject()) {
RootedObject obj(cx, &val.toObject());
bool isArray =
false ;
if (!IsArray(cx, obj, &isArray)) {
return false ;
}
args.rval().setBoolean(isArray);
}
else {
args.rval().setBoolean(
false );
}
return true;
}
static bool intrinsic_IsCrossRealmArrayConstructor(JSContext* cx,
unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() ==
1 );
MOZ_ASSERT(args[
0 ].isObject());
bool result =
false ;
if (!IsCrossRealmArrayConstructor(cx, &args[
0 ].toObject(), &result)) 
;{
return false ;
}
args.rval().setBoolean(result);
return true;
}
static bool intrinsic_ToLength(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
// Inline fast path for the common case.
if (args[0 ].isInt32()) {
int32_t i = args[0 ].toInt32();
args.rval().setInt32(i < 0 ? 0 : i);
return true;
}
uint64_t length = 0 ;
if (!ToLength(cx, args[0 ], &length)) {
return false ;
}
args.rval().setNumber(double (length));
return true;
}
static bool intrinsic_ToInteger(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
double result;
if (!ToInteger(cx, args[0 ], &result)) {
return false ;
}
args.rval().setNumber(result);
return true;
}
static bool intrinsic_ToSource(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
JSString* str = ValueToSource(cx, args[0 ]);
if (!str) {
return false ;
}
args.rval().setString(str);
return true;
}
static bool intrinsic_ToPropertyKey(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
RootedId id(cx);
if (!ToPropertyKey(cx, args[0 ], &id)) {
return false ;
}
args.rval().set(IdToValue(id));
return true;
}
static bool intrinsic_IsCallable(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
args.rval().setBoolean(IsCallable(args[0 ]));
return true;
}
static bool intrinsic_IsConstructor(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
args.rval().setBoolean(IsConstructor(args[0 ]));
return true;
}
template <typename T>
static bool intrinsic_IsInstanceOfBuiltin(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
args.rval().setBoolean(args[0 ].toObject().is<T>());
return true;
}
template <typename T>
static bool intrinsic_GuardToBuiltin(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
if (args[0 ].toObject().is<T>()) {
args.rval().setObject(args[0 ].toObject());
return true;
}
args.rval().setNull();
return true;
}
template <typename T>
static bool intrinsic_IsWrappedInstanceOfBuiltin(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
JSObject* obj = &args[0 ].toObject();
if (!obj->is<WrapperObject>()) {
args.rval().setBoolean(false );
return true;
}
JSObject* unwrapped = CheckedUnwrapDynamic(obj, cx);
if (!unwrapped) {
ReportAccessDenied(cx);
return false ;
}
args.rval().setBoolean(unwrapped->is<T>());
return true;
}
template <typename T>
static bool intrinsic_IsPossiblyWrappedInstanceOfBuiltin(JSContext* cx,
unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
JSObject* obj = CheckedUnwrapDynamic(&args[0 ].toObject(), cx);
if (!obj) {
ReportAccessDenied(cx);
return false ;
}
args.rval().setBoolean(obj->is<T>());
return true;
}
static bool intrinsic_SubstringKernel(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args[0 ].isString());
MOZ_RELEASE_ASSERT(args[1 ].isInt32());
MOZ_RELEASE_ASSERT(args[2 ].isInt32());
RootedString str(cx, args[0 ].toString());
int32_t begin = args[1 ].toInt32();
int32_t length = args[2 ].toInt32();
JSString* substr = SubstringKernel(cx, str, begin, length);
if (!substr) {
return false ;
}
args.rval().setString(substr);
return true;
}
static bool PrepareErrorArguments(JSContext* cx, JSExnType type,
const CallArgs& args,
UniqueChars (&errorArgs)[3 ]) {
#ifdef DEBUG
MOZ_ASSERT(args[0 ].isInt32());
uint32_t errorNumber = args[0 ].toInt32();
const JSErrorFormatString* efs = GetErrorMessage(nullptr, errorNumber);
MOZ_ASSERT(efs->argCount == args.length() - 1 );
MOZ_ASSERT(efs->exnType == type,
"error-throwing intrinsic and error number are inconsistent" );
#endif
for (unsigned i = 1 ; i < 4 && i < args.length(); i++) {
HandleValue val = args[i];
if (val.isInt32() || val.isString()) {
JSString* str = ToString<CanGC>(cx, val);
if (!str) {
return false ;
}
errorArgs[i - 1 ] = QuoteString(cx, str);
} else {
errorArgs[i - 1 ] =
DecompileValueGenerator(cx, JSDVG_SEARCH_STACK, val, nullptr);
}
if (!errorArgs[i - 1 ]) {
return false ;
}
}
return true;
}
static void ThrowErrorWithType(JSContext* cx, JSExnType type,
const CallArgs& args) {
MOZ_RELEASE_ASSERT(args[0 ].isInt32());
uint32_t errorNumber = args[0 ].toInt32();
UniqueChars errorArgs[3 ];
if (!PrepareErrorArguments(cx, type, args, errorArgs)) {
return ;
}
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr, errorNumber,
errorArgs[0 ].get(), errorArgs[1 ].get(),
errorArgs[2 ].get());
}
static bool intrinsic_ThrowRangeError(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() >= 1 );
ThrowErrorWithType(cx, JSEXN_RANGEERR, args);
return false ;
}
static bool intrinsic_ThrowTypeError(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() >= 1 );
ThrowErrorWithType(cx, JSEXN_TYPEERR, args);
return false ;
}
static bool intrinsic_ThrowAggregateError(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() >= 1 );
ThrowErrorWithType(cx, JSEXN_AGGREGATEERR, args);
return false ;
}
static bool intrinsic_ThrowInternalError(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() >= 1 );
ThrowErrorWithType(cx, JSEXN_INTERNALERR, args);
return false ;
}
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
static bool intrinsic_CreateSuppressedError(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
JS::Handle<JS::Value> error = args[0 ];
JS::Handle<JS::Value> suppressed = args[1 ];
ErrorObject* suppressedError = CreateSuppressedError(cx, error, suppressed);
if (!suppressedError) {
return false ;
}
args.rval().setObject(*suppressedError);
return true;
}
#endif
/**
* Handles an assertion failure in self - hosted code just like an assertion
* failure in C + + code . Information about the failure can be provided in
* args [ 0 ] .
*/
static bool intrinsic_AssertionFailed(JSContext* cx, unsigned argc, Value* vp) {
#ifdef DEBUG
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() > 0 ) {
// try to dump the informative string
JSString* str = ToString<CanGC>(cx, args[0 ]);
if (str) {
js::Fprinter out(stderr);
out.put("Self-hosted JavaScript assertion info: " );
str->dumpCharsNoQuote(out);
out.putChar('\n' );
}
}
#endif
MOZ_ASSERT(false );
return false ;
}
/**
* Dumps a message to stderr , after stringifying it . Doesn ' t append a newline .
*/
static bool intrinsic_DumpMessage(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
#ifdef DEBUG
if (args.length() > 0 ) {
// try to dump the informative string
js::Fprinter out(stderr);
JSString* str = ToString<CanGC>(cx, args[0 ]);
if (str) {
str->dumpCharsNoQuote(out);
out.putChar('\n' );
} else {
cx->recoverFromOutOfMemory();
}
}
#endif
args.rval().setUndefined();
return true;
}
/*
* Used to decompile values in the nearest non - builtin stack frame , falling
* back to decompiling in the current frame . Helpful for printing higher - order
* function arguments .
*
* The user must supply the argument number of the value in question ; it
* _ cannot_ be automatically determined .
*/
static bool intrinsic_DecompileArg(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_RELEASE_ASSERT(args[0 ].isInt32());
HandleValue value = args[1 ];
JSString* str = DecompileArgument(cx, args[0 ].toInt32(), value);
if (!str) {
return false ;
}
args.rval().setString(str);
return true;
}
static bool intrinsic_DefineDataProperty(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
// When DefineDataProperty is called with 3 arguments, it's compiled to
// JSOp::InitElem in the bytecode emitter so we shouldn't get here.
MOZ_ASSERT(args.length() == 4 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_RELEASE_ASSERT(args[3 ].isInt32());
RootedObject obj(cx, &args[0 ].toObject());
RootedId id(cx);
if (!ToPropertyKey(cx, args[1 ], &id)) {
return false ;
}
RootedValue value(cx, args[2 ]);
JS::PropertyAttributes attrs;
unsigned attributes = args[3 ].toInt32();
MOZ_ASSERT(bool (attributes & ATTR_ENUMERABLE) !=
bool (attributes & ATTR_NONENUMERABLE),
"DefineDataProperty must receive either ATTR_ENUMERABLE xor "
"ATTR_NONENUMERABLE" );
if (attributes & ATTR_ENUMERABLE) {
attrs += JS::PropertyAttribute::Enumerable;
}
MOZ_ASSERT(bool (attributes & ATTR_CONFIGURABLE) !=
bool (attributes & ATTR_NONCONFIGURABLE),
"DefineDataProperty must receive either ATTR_CONFIGURABLE xor "
"ATTR_NONCONFIGURABLE" );
if (attributes & ATTR_CONFIGURABLE) {
attrs += JS::PropertyAttribute::Configurable;
}
MOZ_ASSERT(
bool (attributes & ATTR_WRITABLE) != bool (attributes & ATTR_NONWRITABLE),
"DefineDataProperty must receive either ATTR_WRITABLE xor "
"ATTR_NONWRITABLE" );
if (attributes & ATTR_WRITABLE) {
attrs += JS::PropertyAttribute::Writable;
}
Rooted<PropertyDescriptor> desc(cx, PropertyDescriptor::Data(value, attrs));
if (!DefineProperty(cx, obj, id, desc)) {
return false ;
}
args.rval().setUndefined();
return true;
}
static bool intrinsic_DefineProperty(JSContext* cx, unsigned argc, Value* vp) {
// _DefineProperty(object, propertyKey, attributes,
// valueOrGetter, setter, strict)
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 6 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_ASSERT(args[1 ].isString() || args[1 ].isNumber() || args[1 ].isSymbol());
MOZ_RELEASE_ASSERT(args[2 ].isInt32());
MOZ_ASSERT(args[5 ].isBoolean());
RootedObject obj(cx, &args[0 ].toObject());
RootedId id(cx);
if (!PrimitiveValueToId<CanGC>(cx, args[1 ], &id)) {
return false ;
}
Rooted<PropertyDescriptor> desc(cx, PropertyDescriptor::Empty());
unsigned attributes = args[2 ].toInt32();
if (attributes & (ATTR_ENUMERABLE | ATTR_NONENUMERABLE)) {
desc.setEnumerable(attributes & ATTR_ENUMERABLE);
}
if (attributes & (ATTR_CONFIGURABLE | ATTR_NONCONFIGURABLE)) {
desc.setConfigurable(attributes & ATTR_CONFIGURABLE);
}
if (attributes & (ATTR_WRITABLE | ATTR_NONWRITABLE)) {
desc.setWritable(attributes & ATTR_WRITABLE);
}
// When args[4] is |null|, the data descriptor has a value component.
if ((attributes & DATA_DESCRIPTOR_KIND) && args[4 ].isNull()) {
desc.setValue(args[3 ]);
}
if (attributes & ACCESSOR_DESCRIPTOR_KIND) {
Value getter = args[3 ];
if (getter.isObject()) {
desc.setGetter(&getter.toObject());
} else if (getter.isUndefined()) {
desc.setGetter(nullptr);
} else {
MOZ_ASSERT(getter.isNull());
}
Value setter = args[4 ];
if (setter.isObject()) {
desc.setSetter(&setter.toObject());
} else if (setter.isUndefined()) {
desc.setSetter(nullptr);
} else {
MOZ_ASSERT(setter.isNull());
}
}
desc.assertValid();
ObjectOpResult result;
if (!DefineProperty(cx, obj, id, desc, result)) {
return false ;
}
bool strict = args[5 ].toBoolean();
if (strict && !result.ok()) {
// We need to tell our caller Object.defineProperty,
// that this operation failed, without actually throwing
// for web-compatibility reasons.
if (result.failureCode() == JSMSG_CANT_DEFINE_WINDOW_NC) {
args.rval().setBoolean(false );
return true;
}
return result.reportError(cx, obj, id);
}
args.rval().setBoolean(result.ok());
return true;
}
static bool intrinsic_UnsafeSetReservedSlot(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_RELEASE_ASSERT(args[1 ].isInt32());
MOZ_ASSERT(args[1 ].toInt32() >= 0 );
uint32_t slot = uint32_t(args[1 ].toInt32());
args[0 ].toObject().as<NativeObject>().setReservedSlot(slot, args[2 ]);
args.rval().setUndefined();
return true;
}
static bool intrinsic_UnsafeGetReservedSlot(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_RELEASE_ASSERT(args[1 ].isInt32());
MOZ_ASSERT(args[1 ].toInt32() >= 0 );
uint32_t slot = uint32_t(args[1 ].toInt32());
args.rval().set(args[0 ].toObject().as<NativeObject>().getReservedSlot(slot));
return true;
}
static bool intrinsic_UnsafeGetObjectFromReservedSlot(JSContext* cx,
unsigned argc,
Value* vp) {
if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) {
return false ;
}
MOZ_ASSERT(vp->isObject());
return true;
}
static bool intrinsic_UnsafeGetInt32FromReservedSlot(JSContext* cx,
unsigned argc, Value* vp) {
if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) {
return false ;
}
MOZ_ASSERT(vp->isInt32());
return true;
}
static bool intrinsic_UnsafeGetStringFromReservedSlot(JSContext* cx,
unsigned argc,
Value* vp) {
if (!intrinsic_UnsafeGetReservedSlot(cx, argc, vp)) {
return false ;
}
MOZ_ASSERT(vp->isString());
return true;
}
static bool intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
args.rval().setBoolean(IsPackedArray(&args[0 ].toObject()));
return true;
}
bool js::intrinsic_NewArrayIterator(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* obj = NewArrayIterator(cx);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
static bool intrinsic_ArrayIteratorPrototypeOptimizable(JSContext* cx,
unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
bool optimized = HasOptimizableArrayIteratorPrototype(cx);
args.rval().setBoolean(optimized);
return true;
}
static bool intrinsic_GetNextMapEntryForIterator(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_ASSERT(args[0 ].toObject().is<MapIteratorObject>());
MOZ_ASSERT(args[1 ].isObject());
MapIteratorObject* mapIterator = &args[0 ].toObject().as<MapIteratorObject>();
ArrayObject* result = &args[1 ].toObject().as<ArrayObject>();
args.rval().setBoolean(MapIteratorObject::next(mapIterator, result));
return true;
}
static bool intrinsic_CreateMapIterationResultPair(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* result = MapIteratorObject::createResultPair(cx);
if (!result) {
return false ;
}
args.rval().setObject(*result);
return true;
}
static bool intrinsic_GetNextSetEntryForIterator(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_ASSERT(args[0 ].toObject().is<SetIteratorObject>());
MOZ_ASSERT(args[1 ].isObject());
SetIteratorObject* setIterator = &args[0 ].toObject().as<SetIteratorObject>();
ArrayObject* result = &args[1 ].toObject().as<ArrayObject>();
args.rval().setBoolean(SetIteratorObject::next(setIterator, result));
return true;
}
static bool intrinsic_CreateSetIterationResult(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* result = SetIteratorObject::createResult(cx);
if (!result) {
return false ;
}
args.rval().setObject(*result);
return true;
}
bool js::intrinsic_NewStringIterator(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* obj = NewStringIterator(cx);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
bool js::intrinsic_NewRegExpStringIterator(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* obj = NewRegExpStringIterator(cx);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
js::PropertyName* js::GetClonedSelfHostedFunctionName(const JSFunction* fun) {
if (!fun->isExtended()) {
return nullptr;
}
Value name = fun->getExtendedSlot(LAZY_FUNCTION_NAME_SLOT);
if (!name.isString()) {
return nullptr;
}
return name.toString()->asAtom().asPropertyName();
}
bool js::IsExtendedUnclonedSelfHostedFunctionName(JSAtom* name) {
if (name->length() < 2 ) {
return false ;
}
return name->latin1OrTwoByteChar(0 ) ==
ExtendedUnclonedSelfHostedFunctionNamePrefix;
}
void js::SetClonedSelfHostedFunctionName(JSFunction* fun,
js::PropertyName* name) {
fun->setExtendedSlot(LAZY_FUNCTION_NAME_SLOT, StringValue(name));
}
static bool intrinsic_GeneratorObjectIsClosed(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
GeneratorObject* genObj = &args[0 ].toObject().as<GeneratorObject>();
args.rval().setBoolean(genObj->isClosed());
return true;
}
static bool intrinsic_IsSuspendedGenerator(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
if (!args[0 ].isObject() || !args[0 ].toObject().is<GeneratorObject>()) {
args.rval().setBoolean(false );
return true;
}
GeneratorObject& genObj = args[0 ].toObject().as<GeneratorObject>();
MOZ_ASSERT_IF(genObj.isSuspended(), !genObj.isClosed());
args.rval().setBoolean(genObj.isSuspended());
return true;
}
static bool intrinsic_GeneratorIsRunning(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
GeneratorObject* genObj = &args[0 ].toObject().as<GeneratorObject>();
args.rval().setBoolean(genObj->isRunning());
return true;
}
static bool intrinsic_GeneratorSetClosed(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
GeneratorObject* genObj = &args[0 ].toObject().as<GeneratorObject>();
genObj->setClosed(cx);
return true;
}
static bool intrinsic_IsTypedArrayConstructor(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
args.rval().setBoolean(js::IsTypedArrayConstructor(&args[0 ].toObject()));
return true;
}
// Return the value of [[ArrayLength]] internal slot of the TypedArray
static bool intrinsic_TypedArrayLength(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].toObject().is<TypedArrayObject>());
auto * tarr = &args[0 ].toObject().as<TypedArrayObject>();
mozilla::Maybe<size_t> length = tarr->length();
if (!length) {
// Return zero for detached buffers to match JIT code.
if (tarr->hasDetachedBuffer()) {
args.rval().setInt32(0 );
return true;
}
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_RESIZED_BOUNDS);
return false ;
}
args.rval().setNumber(*length);
return true;
}
static bool intrinsic_PossiblyWrappedTypedArrayLength(JSContext* cx,
unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
TypedArrayObject* obj = args[0 ].toObject().maybeUnwrapAs<TypedArrayObject>();
if (!obj) {
ReportAccessDenied(cx);
return false ;
}
mozilla::Maybe<size_t> length = obj->length();
if (!length) {
// Return zero for detached buffers to match JIT code.
if (obj->hasDetachedBuffer()) {
args.rval().setInt32(0 );
return true;
}
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_TYPED_ARRAY_RESIZED_BOUNDS);
return false ;
}
args.rval().setNumber(*length);
return true;
}
static bool intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer(JSContext* cx,
unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
TypedArrayObject* obj = args[0 ].toObject().maybeUnwrapAs<TypedArrayObject>();
if (!obj) {
ReportAccessDenied(cx);
return false ;
}
bool detached = obj->hasDetachedBuffer();
args.rval().setBoolean(detached);
return true;
}
static bool intrinsic_PossiblyWrappedTypedArrayHasImmutableBuffer(JSContext* cx,
unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
auto * obj = args[0 ].toObject().maybeUnwrapAs<TypedArrayObject>();
if (!obj) {
ReportAccessDenied(cx);
return false ;
}
bool immutable = obj->is<ImmutableTypedArrayObject>();
args.rval().setBoolean(immutable);
return true;
}
static bool intrinsic_TypedArrayInitFromPackedArray(JSContext* cx,
unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_ASSERT(args[1 ].isObject());
Rooted<FixedLengthTypedArrayObject*> target(
cx, &args[0 ].toObject().as<FixedLengthTypedArrayObject>());
MOZ_ASSERT(!target->hasDetachedBuffer());
MOZ_ASSERT(!target->isSharedMemory());
Rooted<ArrayObject*> source(cx, &args[1 ].toObject().as<ArrayObject>());
MOZ_ASSERT(IsPackedArray(source));
MOZ_ASSERT(source->length() == target->length());
switch (target->type()) {
#define INIT_TYPED_ARRAY(_, T, N) \
case Scalar::N: { \
if (!ElementSpecific<T, UnsharedOps>::initFromIterablePackedArray( \
cx, target, source)) { \
return false ; \
} \
break ; \
}
JS_FOR_EACH_TYPED_ARRAY(INIT_TYPED_ARRAY)
#undef INIT_TYPED_ARRAY
default :
MOZ_CRASH(
"TypedArrayInitFromPackedArray with a typed array with bogus type" );
}
args.rval().setUndefined();
return true;
}
template <bool ForTest>
static bool intrinsic_RegExpBuiltinExec(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_ASSERT(args[0 ].toObject().is<RegExpObject>());
MOZ_ASSERT(args[1 ].isString());
Rooted<RegExpObject*> obj(cx, &args[0 ].toObject().as<RegExpObject>());
Rooted<JSString*> string(cx, args[1 ].toString());
return RegExpBuiltinExec(cx, obj, string, ForTest, args.rval());
}
template <bool ForTest>
static bool intrinsic_RegExpExec(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_ASSERT(args[1 ].isString());
Rooted<JSObject*> obj(cx, &args[0 ].toObject());
Rooted<JSString*> string(cx, args[1 ].toString());
return RegExpExec(cx, obj, string, ForTest, args.rval());
}
static bool intrinsic_RegExpCreate(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 || args.length() == 2 );
MOZ_ASSERT_IF(args.length() == 2 ,
args[1 ].isString() || args[1 ].isUndefined());
MOZ_ASSERT(!args.isConstructing());
return RegExpCreate(cx, args[0 ], args.get(1 ), args.rval(), nullptr);
}
static bool intrinsic_RegExpGetSubstitution(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 6 );
Rooted<ArrayObject*> matchResult(cx, &args[0 ].toObject().as<ArrayObject>());
Rooted<JSLinearString*> string(cx, args[1 ].toString()->ensureLinear(cx));
if (!string) {
return false ;
}
int32_t position = int32_t(args[2 ].toNumber());
MOZ_ASSERT(position >= 0 );
Rooted<JSLinearString*> replacement(cx, args[3 ].toString()->ensureLinear(cx));
if (!replacement) {
return false ;
}
int32_t firstDollarIndex = int32_t(args[4 ].toNumber());
MOZ_ASSERT(firstDollarIndex >= 0 );
RootedValue namedCaptures(cx, args[5 ]);
MOZ_ASSERT(namedCaptures.isUndefined() || namedCaptures.isObject());
return RegExpGetSubstitution(cx, matchResult, string, size_t(position),
replacement, size_t(firstDollarIndex),
namedCaptures, args.rval());
}
static bool intrinsic_RegExpHasCaptureGroups(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_ASSERT(args[1 ].isString());
Rooted<RegExpObject*> obj(cx, &args[0 ].toObject().as<RegExpObject>());
Rooted<JSString*> string(cx, args[1 ].toString());
bool result;
if (!RegExpHasCaptureGroups(cx, obj, string, &result)) {
return false ;
}
args.rval().setBoolean(result);
return true;
}
static bool intrinsic_StringReplaceString(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3 );
RootedString string(cx, args[0 ].toString());
RootedString pattern(cx, args[1 ].toString());
RootedString replacement(cx, args[2 ].toString());
JSString* result = str_replace_string_raw(cx, string, pattern, replacement);
if (!result) {
return false ;
}
args.rval().setString(result);
return true;
}
static bool intrinsic_StringReplaceAllString(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3 );
RootedString string(cx, args[0 ].toString());
RootedString pattern(cx, args[1 ].toString());
RootedString replacement(cx, args[2 ].toString());
JSString* result =
str_replaceAll_string_raw(cx, string, pattern, replacement);
if (!result) {
return false ;
}
args.rval().setString(result);
return true;
}
static bool intrinsic_StringSplitString(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
RootedString string(cx, args[0 ].toString());
RootedString sep(cx, args[1 ].toString());
JSObject* aobj = StringSplitString(cx, string, sep, INT32_MAX);
if (!aobj) {
return false ;
}
args.rval().setObject(*aobj);
return true;
}
static bool intrinsic_StringSplitStringLimit(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3 );
RootedString string(cx, args[0 ].toString());
RootedString sep(cx, args[1 ].toString());
// args[2] should be already in UInt32 range, but it could be double typed,
// because of Ion optimization.
uint32_t limit = uint32_t(args[2 ].toNumber());
MOZ_ASSERT(limit > 0 ,
"Zero limit case is already handled in self-hosted code." );
JSObject* aobj = StringSplitString(cx, string, sep, limit);
if (!aobj) {
return false ;
}
args.rval().setObject(*aobj);
return true;
}
bool CallSelfHostedNonGenericMethod(JSContext* cx, const CallArgs& args) {
// This function is called when a self-hosted method is invoked on a
// wrapper object, like a CrossCompartmentWrapper. The last argument is
// the name of the self-hosted function. The other arguments are the
// arguments to pass to this function.
MOZ_ASSERT(args.length() > 0 );
Rooted<PropertyName*> name(
cx, args[args.length() - 1 ].toString()->asAtom().asPropertyName());
InvokeArgs args2(cx);
if (!args2.init(cx, args.length() - 1 )) {
return false ;
}
for (size_t i = 0 ; i < args.length() - 1 ; i++) {
args2[i].set(args[i]);
}
return CallSelfHostedFunction(cx, name, args.thisv(), args2, args.rval());
}
#ifdef DEBUG
bool js::CallSelfHostedFunction(JSContext* cx, const char * name,
HandleValue thisv, const AnyInvokeArgs& args,
MutableHandleValue rval) {
JSAtom* funAtom = Atomize(cx, name, strlen(name));
if (!funAtom) {
return false ;
}
Rooted<PropertyName*> funName(cx, funAtom->asPropertyName());
return CallSelfHostedFunction(cx, funName, thisv, args, rval);
}
#endif
bool js::CallSelfHostedFunction(JSContext* cx, Handle<PropertyName*> name,
HandleValue thisv, const AnyInvokeArgs& args,
MutableHandleValue rval) {
RootedValue fun(cx);
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), name, &fun)) {
return false ;
}
MOZ_ASSERT(fun.toObject().is<JSFunction>());
return Call(cx, fun, thisv, args, rval);
}
template <typename T>
bool Is(HandleValue v) {
return v.isObject() && v.toObject().is<T>();
}
template <IsAcceptableThis Test>
static bool CallNonGenericSelfhostedMethod(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
return CallNonGenericMethod<Test, CallSelfHostedNonGenericMethod>(cx, args);
}
bool js::IsCallSelfHostedNonGenericMethod(NativeImpl impl) {
return impl == CallSelfHostedNonGenericMethod;
}
bool js::ReportIncompatibleSelfHostedMethod(
JSContext* cx, Handle<Value> thisValue,
IncompatibleContext incompatibleContext) {
// The contract for this function is the same as
// CallSelfHostedNonGenericMethod. The normal ReportIncompatible function
// doesn't work for selfhosted functions, because they always call the
// different CallXXXMethodIfWrapped methods, which would be reported as the
// called function instead.
// Lookup the selfhosted method that was invoked. But skip over
// internal self-hosted function frames, because those are never the
// actual self-hosted callee from external code. We can't just skip
// self-hosted things until we find a non-self-hosted one because of cases
// like array.sort(somethingSelfHosted), where we want to report the error
// in the somethingSelfHosted, not in the sort() call.
static const char * const internalNames[] = {
"EnsureTypedArrayWithArrayBuffer" ,
"RegExpSearchSlowPath" ,
"RegExpReplaceSlowPath" ,
"RegExpMatchSlowPath" ,
};
ScriptFrameIter iter(cx);
MOZ_ASSERT(iter.isFunctionFrame());
while (!iter.done()) {
MOZ_ASSERT(iter.callee(cx)->isSelfHostedOrIntrinsic());
UniqueChars funNameBytes;
const char * funName =
GetFunctionNameBytes(cx, iter.callee(cx), &funNameBytes);
if (!funName) {
return false ;
}
if (std::all_of(
std::begin(internalNames), std::end(internalNames),
[funName](auto * name) { return strcmp(funName, name) != 0 ; })) {
if (incompatibleContext == IncompatibleContext::RegExpExec) {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_REGEXP_METHOD, funName,
InformalValueTypeName(thisValue));
} else {
JS_ReportErrorNumberUTF8(cx, GetErrorMessage, nullptr,
JSMSG_INCOMPATIBLE_METHOD, funName, "method" ,
InformalValueTypeName(thisValue));
}
return false ;
}
++iter;
}
MOZ_ASSERT_UNREACHABLE("How did we not find a useful self-hosted frame?" );
return false ;
}
static bool intrinsic_ConstructFunction(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3 );
MOZ_ASSERT(IsConstructor(args[0 ]));
MOZ_ASSERT(IsConstructor(args[1 ]));
MOZ_ASSERT(args[2 ].toObject().is<ArrayObject>());
Rooted<ArrayObject*> argsList(cx, &args[2 ].toObject().as<ArrayObject>());
uint32_t len = argsList->length();
ConstructArgs constructArgs(cx);
if (!constructArgs.init(cx, len)) {
return false ;
}
for (uint32_t index = 0 ; index < len; index++) {
constructArgs[index].set(argsList->getDenseElement(index));
}
RootedObject res(cx);
if (!Construct(cx, args[0 ], constructArgs, args[1 ], &res)) {
return false ;
}
args.rval().setObject(*res);
return true;
}
static bool intrinsic_IsConstructing(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
ScriptFrameIter iter(cx);
bool isConstructing = iter.isConstructing();
args.rval().setBoolean(isConstructing);
return true;
}
static bool intrinsic_ConstructorForTypedArray(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
MOZ_ASSERT(args[0 ].isObject());
auto * object = UnwrapAndDowncastValue<TypedArrayObject>(cx, args[0 ]);
if (!object) {
return false ;
}
JSProtoKey protoKey = StandardProtoKeyOrNull(object);
MOZ_ASSERT(protoKey);
// While it may seem like an invariant that in any compartment,
// seeing a typed array object implies that the TypedArray constructor
// for that type is initialized on the compartment's global, this is not
// the case. When we construct a typed array given a cross-compartment
// ArrayBuffer, we put the constructed TypedArray in the same compartment
// as the ArrayBuffer. Since we use the prototype from the initial
// compartment, and never call the constructor in the ArrayBuffer's
// compartment from script, we are not guaranteed to have initialized
// the constructor.
JSObject* ctor = GlobalObject::getOrCreateConstructor(cx, protoKey);
if (!ctor) {
return false ;
}
args.rval().setObject(*ctor);
return true;
}
static bool intrinsic_PromiseResolve(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
RootedObject constructor(cx, &args[0 ].toObject());
JSObject* promise = js::PromiseResolve(cx, constructor, args[1 ]);
if (!promise) {
return false ;
}
args.rval().setObject(*promise);
return true;
}
static bool intrinsic_CopyDataPropertiesOrGetOwnKeys(JSContext* cx,
unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 3 );
MOZ_ASSERT(args[0 ].isObject());
MOZ_ASSERT(args[1 ].isObject());
MOZ_ASSERT(args[2 ].isObjectOrNull());
RootedObject target(cx, &args[0 ].toObject());
RootedObject from(cx, &args[1 ].toObject());
RootedObject excludedItems(cx, args[2 ].toObjectOrNull());
if (from->is<NativeObject>() && target->is<PlainObject>() &&
(!excludedItems || excludedItems->is<PlainObject>())) {
bool optimized;
if (!CopyDataPropertiesNative(
cx, target.as<PlainObject>(), from.as<NativeObject>(),
(excludedItems ? excludedItems.as<PlainObject>() : nullptr),
&optimized)) {
return false ;
}
if (optimized) {
args.rval().setNull();
return true;
}
}
return GetOwnPropertyKeys(
cx, from, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, args.rval());
}
static bool intrinsic_NewWrapForValidIterator(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* obj = NewWrapForValidIterator(cx);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
static bool intrinsic_NewIteratorHelper(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* obj = NewIteratorHelper(cx);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
static bool intrinsic_NewAsyncIteratorHelper(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* obj = NewAsyncIteratorHelper(cx);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
#ifdef NIGHTLY_BUILD
static bool intrinsic_NewIteratorRange(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JSObject* obj = NewIteratorRange(cx);
if (!obj) {
return false ;
}
args.rval().setObject(*obj);
return true;
}
#endif
static JSObject* NewIteratorRecord(JSContext* cx, HandleObject iterator,
HandleValue nextMethod) {
gc::AllocKind allocKind = gc::GetGCObjectKind(3 );
Rooted<PlainObject*> obj(
cx, NewPlainObjectWithProtoAndAllocKind(cx, nullptr, allocKind));
if (!obj) {
return nullptr;
}
RootedId propid(cx, NameToId(cx->names().iterator));
RootedValue value(cx, ObjectValue(*iterator));
if (!NativeDefineDataProperty(cx, obj, propid, value, JSPROP_ENUMERATE)) {
return nullptr;
}
propid = NameToId(cx->names().nextMethod);
value.set(nextMethod);
if (!NativeDefineDataProperty(cx, obj, propid, value, JSPROP_ENUMERATE)) {
return nullptr;
}
propid = NameToId(cx->names().done);
value.setBoolean(false );
if (!NativeDefineDataProperty(cx, obj, propid, value, JSPROP_ENUMERATE)) {
return nullptr;
}
return obj;
}
static bool intrinsic_CreateAsyncFromSyncIterator(JSContext* cx, unsigned argc,
Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2 );
RootedObject iterator(cx, &args[0 ].toObject());
RootedObject asyncIterator(
cx, CreateAsyncFromSyncIterator(cx, iterator, args[1 ]));
if (!asyncIterator) {
return false ;
}
RootedValue nextMethod(cx);
if (!GetProperty(cx, asyncIterator, asyncIterator, cx->names().next,
&nextMethod)) {
return false ;
}
RootedObject iteratorRecord(cx,
NewIteratorRecord(cx, asyncIterator, nextMethod));
if (!iteratorRecord) {
return false ;
}
args.rval().setObject(*iteratorRecord);
return true;
}
static bool intrinsic_NoPrivateGetter(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_PRIVATE_SETTER_ONLY);
args.rval().setUndefined();
return false ;
}
static bool intrinsic_newList(JSContext* cx, unsigned argc, js::Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0 );
ArrayObject* list = NewArrayWithNullProto(cx);
if (!list) {
return false ;
}
args.rval().setObject(*list);
return true;
}
static bool intrinsic_CanBeHeldWeakly(JSContext* cx, unsigned argc, Value* vp) {
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1 );
args.rval().setBoolean(CanBeHeldWeakly(args[0 ]));
return true;
}
static const JSFunctionSpec intrinsic_functions[] = {
// Intrinsic helper functions
JS_INLINABLE_FN("ArrayIteratorPrototypeOptimizable" ,
intrinsic_ArrayIteratorPrototypeOptimizable, 0 , 0 ,
IntrinsicArrayIteratorPrototypeOptimizable),
JS_FN("AssertionFailed" , intrinsic_AssertionFailed, 1 , 0 ),
JS_FN("CallArrayIteratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<ArrayIteratorObject>>, 2 , 0 ),
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
JS_FN("CallAsyncDisposableStackMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<AsyncDisposableStackObject>>, 2 , 0 ),
#endif
JS_FN("CallAsyncIteratorHelperMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<AsyncIteratorHelperObject>>, 2 , 0 ),
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
JS_FN("CallDisposableStackMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<DisposableStackObject>>, 2 , 0 ),
#endif
JS_FN("CallGeneratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<GeneratorObject>>, 2 , 0 ),
JS_FN("CallIteratorHelperMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<IteratorHelperObject>>, 2 , 0 ),
#ifdef NIGHTLY_BUILD
JS_FN("CallIteratorRangeMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<IteratorRangeObject>>, 2 , 0 ),
#endif
JS_FN("CallMapIteratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<MapIteratorObject>>, 2 , 0 ),
JS_FN("CallMapMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<MapObject>>, 2 , 0 ),
JS_FN("CallRegExpMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<RegExpObject>>, 2 , 0 ),
JS_FN("CallRegExpStringIteratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<RegExpStringIteratorObject>>, 2 , 0 ),
JS_FN("CallSetIteratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<SetIteratorObject>>, 2 , 0 ),
JS_FN("CallSetMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<SetObject>>, 2 , 0 ),
JS_FN("CallStringIteratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<StringIteratorObject>>, 2 , 0 ),
JS_FN("CallTypedArrayMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<TypedArrayObject>>, 2 , 0 ),
JS_FN("CallWeakMapMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<WeakMapObject>>, 2 , 0 ),
JS_FN("CallWrapForValidIteratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<WrapForValidIteratorObject>>, 2 , 0 ),
JS_FN("CanBeHeldWeakly" , intrinsic_CanBeHeldWeakly, 1 , 0 ),
JS_INLINABLE_FN("CanOptimizeArraySpecies" ,
intrinsic_CanOptimizeArraySpecies, 1 , 0 ,
IntrinsicCanOptimizeArraySpecies),
JS_FN("ConstructFunction" , intrinsic_ConstructFunction, 2 , 0 ),
JS_FN("ConstructorForTypedArray" , intrinsic_ConstructorForTypedArray, 1 , 0 ),
JS_FN("CopyDataPropertiesOrGetOwnKeys" ,
intrinsic_CopyDataPropertiesOrGetOwnKeys, 3 , 0 ),
JS_FN("CreateAsyncFromSyncIterator" , intrinsic_CreateAsyncFromSyncIterator,
2 , 0 ),
JS_FN("CreateMapIterationResultPair" ,
intrinsic_CreateMapIterationResultPair, 0 , 0 ),
JS_FN("CreateSetIterationResult" , intrinsic_CreateSetIterationResult, 0 , 0 ),
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
JS_FN("CreateSuppressedError" , intrinsic_CreateSuppressedError, 2 , 0 ),
#endif
JS_FN("DecompileArg" , intrinsic_DecompileArg, 2 , 0 ),
JS_FN("DefineDataProperty" , intrinsic_DefineDataProperty, 4 , 0 ),
JS_FN("DefineProperty" , intrinsic_DefineProperty, 6 , 0 ),
JS_FN("DumpMessage" , intrinsic_DumpMessage, 1 , 0 ),
JS_FN("FlatStringMatch" , FlatStringMatch, 2 , 0 ),
JS_FN("FlatStringSearch" , FlatStringSearch, 2 , 0 ),
JS_FN("GeneratorIsRunning" , intrinsic_GeneratorIsRunning, 1 , 0 ),
JS_FN("GeneratorObjectIsClosed" , intrinsic_GeneratorObjectIsClosed, 1 , 0 ),
JS_FN("GeneratorSetClosed" , intrinsic_GeneratorSetClosed, 1 , 0 ),
JS_FN("GetElemBaseForLambda" , intrinsic_GetElemBaseForLambda, 1 , 0 ),
JS_INLINABLE_FN("GetFirstDollarIndex" , GetFirstDollarIndex, 1 , 0 ,
GetFirstDollarIndex),
JS_INLINABLE_FN("GetNextMapEntryForIterator" ,
intrinsic_GetNextMapEntryForIterator, 2 , 0 ,
IntrinsicGetNextMapEntryForIterator),
JS_INLINABLE_FN("GetNextSetEntryForIterator" ,
intrinsic_GetNextSetEntryForIterator, 2 , 0 ,
IntrinsicGetNextSetEntryForIterator),
JS_FN("GetOwnPropertyDescriptorToArray" , GetOwnPropertyDescriptorToArray, 2 ,
0 ),
JS_FN("GetStringDataProperty" , intrinsic_GetStringDataProperty, 2 , 0 ),
JS_INLINABLE_FN("GuardToArrayBuffer" ,
intrinsic_GuardToBuiltin<ArrayBufferObject>, 1 , 0 ,
IntrinsicGuardToArrayBuffer),
JS_INLINABLE_FN("GuardToArrayIterator" ,
intrinsic_GuardToBuiltin<ArrayIteratorObject>, 1 , 0 ,
IntrinsicGuardToArrayIterator),
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
JS_INLINABLE_FN("GuardToAsyncDisposableStackHelper" ,
intrinsic_GuardToBuiltin<AsyncDisposableStackObject>, 1 , 0 ,
IntrinsicGuardToAsyncDisposableStack),
#endif
JS_INLINABLE_FN("GuardToAsyncIteratorHelper" ,
intrinsic_GuardToBuiltin<AsyncIteratorHelperObject>, 1 , 0 ,
IntrinsicGuardToAsyncIteratorHelper),
#ifdef ENABLE_EXPLICIT_RESOURCE_MANAGEMENT
JS_INLINABLE_FN("GuardToDisposableStackHelper" ,
intrinsic_GuardToBuiltin<DisposableStackObject>, 1 , 0 ,
IntrinsicGuardToDisposableStack),
#endif
JS_INLINABLE_FN("GuardToIteratorHelper" ,
intrinsic_GuardToBuiltin<IteratorHelperObject>, 1 , 0 ,
IntrinsicGuardToIteratorHelper),
#ifdef NIGHTLY_BUILD
JS_INLINABLE_FN("GuardToIteratorRange" ,
intrinsic_GuardToBuiltin<IteratorRangeObject>, 1 , 0 ,
IntrinsicGuardToIteratorRange),
#endif
JS_INLINABLE_FN("GuardToMapIterator" ,
intrinsic_GuardToBuiltin<MapIteratorObject>, 1 , 0 ,
IntrinsicGuardToMapIterator),
JS_INLINABLE_FN("GuardToMapObject" , intrinsic_GuardToBuiltin<MapObject>, 1 ,
0 , IntrinsicGuardToMapObject),
JS_INLINABLE_FN("GuardToRegExpStringIterator" ,
intrinsic_GuardToBuiltin<RegExpStringIteratorObject>, 1 , 0 ,
IntrinsicGuardToRegExpStringIterator),
JS_INLINABLE_FN("GuardToSetIterator" ,
intrinsic_GuardToBuiltin<SetIteratorObject>, 1 , 0 ,
IntrinsicGuardToSetIterator),
JS_INLINABLE_FN("GuardToSetObject" , intrinsic_GuardToBuiltin<SetObject>, 1 ,
0 , IntrinsicGuardToSetObject),
JS_INLINABLE_FN("GuardToSharedArrayBuffer" ,
intrinsic_GuardToBuiltin<SharedArrayBufferObject>, 1 , 0 ,
IntrinsicGuardToSharedArrayBuffer),
JS_INLINABLE_FN("GuardToStringIterator" ,
intrinsic_GuardToBuiltin<StringIteratorObject>, 1 , 0 ,
IntrinsicGuardToStringIterator),
JS_FN("GuardToWeakMapObject" , intrinsic_GuardToBuiltin<WeakMapObject>, 1 ,
0 ),
JS_INLINABLE_FN("GuardToWrapForValidIterator" ,
intrinsic_GuardToBuiltin<WrapForValidIteratorObject>, 1 , 0 ,
IntrinsicGuardToWrapForValidIterator),
JS_FN("IntrinsicAsyncGeneratorNext" , AsyncGeneratorNext, 1 , 0 ),
JS_FN("IntrinsicAsyncGeneratorReturn" , AsyncGeneratorReturn, 1 , 0 ),
JS_FN("IntrinsicAsyncGeneratorThrow" , AsyncGeneratorThrow, 1 , 0 ),
JS_INLINABLE_FN("IsArray" , intrinsic_IsArray, 1 , 0 , ArrayIsArray),
JS_FN("IsAsyncFunctionGeneratorObject" ,
intrinsic_IsInstanceOfBuiltin<AsyncFunctionGeneratorObject>, 1 , 0 ),
JS_FN("IsAsyncGeneratorObject" ,
intrinsic_IsInstanceOfBuiltin<AsyncGeneratorObject>, 1 , 0 ),
JS_INLINABLE_FN("IsCallable" , intrinsic_IsCallable, 1 , 0 ,
IntrinsicIsCallable),
JS_INLINABLE_FN("IsConstructing" , intrinsic_IsConstructing, 0 , 0 ,
IntrinsicIsConstructing),
JS_INLINABLE_FN("IsConstructor" , intrinsic_IsConstructor, 1 , 0 ,
IntrinsicIsConstructor),
JS_INLINABLE_FN("IsCrossRealmArrayConstructor" ,
intrinsic_IsCrossRealmArrayConstructor, 1 , 0 ,
IntrinsicIsCrossRealmArrayConstructor),
JS_FN("IsGeneratorObject" , intrinsic_IsInstanceOfBuiltin<GeneratorObject>,
1 , 0 ),
JS_INLINABLE_FN("IsObject" , intrinsic_IsObject, 1 , 0 , IntrinsicIsObject),
JS_INLINABLE_FN("IsOptimizableRegExpObject" , IsOptimizableRegExpObject, 1 ,
0 , IsOptimizableRegExpObject),
JS_INLINABLE_FN("IsPackedArray" , intrinsic_IsPackedArray, 1 , 0 ,
IntrinsicIsPackedArray),
JS_INLINABLE_FN("IsPossiblyWrappedRegExpObject" ,
intrinsic_IsPossiblyWrappedInstanceOfBuiltin<RegExpObject>,
1 , 0 , IsPossiblyWrappedRegExpObject),
JS_INLINABLE_FN(
"IsPossiblyWrappedTypedArray" ,
intrinsic_IsPossiblyWrappedInstanceOfBuiltin<TypedArrayObject>, 1 , 0 ,
IntrinsicIsPossiblyWrappedTypedArray),
JS_INLINABLE_FN("IsRegExpObject" ,
intrinsic_IsInstanceOfBuiltin<RegExpObject>, 1 , 0 ,
IsRegExpObject),
JS_INLINABLE_FN("IsRegExpPrototypeOptimizable" ,
IsRegExpPrototypeOptimizable, 0 , 0 ,
IsRegExpPrototypeOptimizable),
JS_INLINABLE_FN("IsSuspendedGenerator" , intrinsic_IsSuspendedGenerator, 1 ,
0 , IntrinsicIsSuspendedGenerator),
JS_INLINABLE_FN("IsTypedArray" ,
intrinsic_IsInstanceOfBuiltin<TypedArrayObject>, 1 , 0 ,
IntrinsicIsTypedArray),
JS_INLINABLE_FN("IsTypedArrayConstructor" ,
intrinsic_IsTypedArrayConstructor, 1 , 0 ,
IntrinsicIsTypedArrayConstructor),
JS_INLINABLE_FN("NewArrayIterator" , intrinsic_NewArrayIterator, 0 , 0 ,
IntrinsicNewArrayIterator),
JS_FN("NewAsyncIteratorHelper" , intrinsic_NewAsyncIteratorHelper, 0 , 0 ),
JS_FN("NewIteratorHelper" , intrinsic_NewIteratorHelper, 0 , 0 ),
#ifdef NIGHTLY_BUILD
JS_FN("NewIteratorRange" , intrinsic_NewIteratorRange, 0 , 0 ),
#endif
JS_INLINABLE_FN("NewRegExpStringIterator" ,
intrinsic_NewRegExpStringIterator, 0 , 0 ,
IntrinsicNewRegExpStringIterator),
JS_INLINABLE_FN("NewStringIterator" , intrinsic_NewStringIterator, 0 , 0 ,
IntrinsicNewStringIterator),
JS_FN("NewWrapForValidIterator" , intrinsic_NewWrapForValidIterator, 0 , 0 ),
JS_FN("NoPrivateGetter" , intrinsic_NoPrivateGetter, 1 , 0 ),
JS_FN("PossiblyWrappedTypedArrayHasDetachedBuffer" ,
intrinsic_PossiblyWrappedTypedArrayHasDetachedBuffer, 1 , 0 ),
JS_FN("PossiblyWrappedTypedArrayHasImmutableBuffer" ,
intrinsic_PossiblyWrappedTypedArrayHasImmutableBuffer, 1 , 0 ),
JS_INLINABLE_FN("PossiblyWrappedTypedArrayLength" ,
intrinsic_PossiblyWrappedTypedArrayLength, 1 , 0 ,
IntrinsicPossiblyWrappedTypedArrayLength),
JS_FN("PromiseResolve" , intrinsic_PromiseResolve, 2 , 0 ),
JS_INLINABLE_FN("RegExpBuiltinExec" , intrinsic_RegExpBuiltinExec<false >, 2 ,
0 , IntrinsicRegExpBuiltinExec),
JS_INLINABLE_FN("RegExpBuiltinExecForTest" ,
intrinsic_RegExpBuiltinExec<true>, 2 , 0 ,
IntrinsicRegExpBuiltinExecForTest),
JS_FN("RegExpConstructRaw" , regexp_construct_raw_flags, 2 , 0 ),
JS_FN("RegExpCreate" , intrinsic_RegExpCreate, 2 , 0 ),
JS_INLINABLE_FN("RegExpExec" , intrinsic_RegExpExec<false >, 2 , 0 ,
IntrinsicRegExpExec),
JS_INLINABLE_FN("RegExpExecForTest" , intrinsic_RegExpExec<true>, 2 , 0 ,
IntrinsicRegExpExecForTest),
JS_FN("RegExpGetSubstitution" , intrinsic_RegExpGetSubstitution, 5 , 0 ),
JS_INLINABLE_FN("RegExpHasCaptureGroups" , intrinsic_RegExpHasCaptureGroups,
2 , 0 , RegExpHasCaptureGroups),
JS_INLINABLE_FN("RegExpMatcher" , RegExpMatcher, 3 , 0 , RegExpMatcher),
JS_INLINABLE_FN("RegExpSearcher" , RegExpSearcher, 3 , 0 , RegExpSearcher),
JS_INLINABLE_FN("RegExpSearcherLastLimit" , RegExpSearcherLastLimit, 0 , 0 ,
RegExpSearcherLastLimit),
JS_INLINABLE_FN("SameValue" , js::obj_is, 2 , 0 , ObjectIs),
JS_FN("SetCopy" , SetObject::copy, 1 , 0 ),
JS_FN("StringReplaceAllString" , intrinsic_StringReplaceAllString, 3 , 0 ),
JS_INLINABLE_FN("StringReplaceString" , intrinsic_StringReplaceString, 3 , 0 ,
IntrinsicStringReplaceString),
JS_INLINABLE_FN("StringSplitString" , intrinsic_StringSplitString, 2 , 0 ,
IntrinsicStringSplitString),
JS_FN("StringSplitStringLimit" , intrinsic_StringSplitStringLimit, 3 , 0 ),
JS_INLINABLE_FN("SubstringKernel" , intrinsic_SubstringKernel, 3 , 0 ,
IntrinsicSubstringKernel),
JS_FN("ThrowAggregateError" , intrinsic_ThrowAggregateError, 4 , 0 ),
JS_FN("ThrowInternalError" , intrinsic_ThrowInternalError, 4 , 0 ),
JS_FN("ThrowRangeError" , intrinsic_ThrowRangeError, 4 , 0 ),
JS_FN("ThrowTypeError" , intrinsic_ThrowTypeError, 4 , 0 ),
JS_INLINABLE_FN("ToInteger" , intrinsic_ToInteger, 1 , 0 , IntrinsicToInteger),
JS_INLINABLE_FN("ToLength" , intrinsic_ToLength, 1 , 0 , IntrinsicToLength),
JS_INLINABLE_FN("ToObject" , intrinsic_ToObject, 1 , 0 , IntrinsicToObject),
JS_FN("ToPropertyKey" , intrinsic_ToPropertyKey, 1 , 0 ),
JS_FN("ToSource" , intrinsic_ToSource, 1 , 0 ),
JS_FN("TypedArrayInitFromPackedArray" ,
intrinsic_TypedArrayInitFromPackedArray, 2 , 0 ),
JS_INLINABLE_FN("TypedArrayLength" , intrinsic_TypedArrayLength, 1 , 0 ,
IntrinsicTypedArrayLength),
JS_INLINABLE_FN("UnsafeGetInt32FromReservedSlot" ,
intrinsic_UnsafeGetInt32FromReservedSlot, 2 , 0 ,
IntrinsicUnsafeGetInt32FromReservedSlot),
JS_INLINABLE_FN("UnsafeGetObjectFromReservedSlot" ,
intrinsic_UnsafeGetObjectFromReservedSlot, 2 , 0 ,
IntrinsicUnsafeGetObjectFromReservedSlot),
JS_INLINABLE_FN("UnsafeGetReservedSlot" , intrinsic_UnsafeGetReservedSlot, 2 ,
0 , IntrinsicUnsafeGetReservedSlot),
JS_INLINABLE_FN("UnsafeGetStringFromReservedSlot" ,
intrinsic_UnsafeGetStringFromReservedSlot, 2 , 0 ,
IntrinsicUnsafeGetStringFromReservedSlot),
JS_INLINABLE_FN("UnsafeSetReservedSlot" , intrinsic_UnsafeSetReservedSlot, 3 ,
0 , IntrinsicUnsafeSetReservedSlot),
// Intrinsics and standard functions used by Intl API implementation.
#ifdef JS_HAS_INTL_API
JS_FN("intl_CallSegmentIteratorMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<intl::SegmentIteratorObject>>, 2 ,
0 ),
JS_FN("intl_CallSegmentsMethodIfWrapped" ,
CallNonGenericSelfhostedMethod<Is<intl::SegmentsObject>>, 2 , 0 ),
JS_FN("intl_CreateSegmentIterator" , intl_CreateSegmentIterator, 1 , 0 ),
JS_FN("intl_FindNextSegmentBoundaries" , intl_FindNextSegmentBoundaries, 1 ,
0 ),
JS_FN("intl_FindSegmentBoundaries" , intl_FindSegmentBoundaries, 2 , 0 ),
JS_INLINABLE_FN("intl_GuardToSegmentIterator" ,
intrinsic_GuardToBuiltin<intl::SegmentIteratorObject>, 1 , 0 ,
IntlGuardToSegmentIterator),
JS_INLINABLE_FN("intl_GuardToSegments" ,
intrinsic_GuardToBuiltin<intl::SegmentsObject>, 1 , 0 ,
IntlGuardToSegments),
#endif // JS_HAS_INTL_API
// Standard builtins used by self-hosting.
JS_FN("new_List" , intrinsic_newList, 0 , 0 ),
JS_INLINABLE_FN("std_Array" , array_construct, 1 , 0 , Array),
JS_INLINABLE_FN("std_Array_pop" , array_pop, 0 , 0 , ArrayPop),
JS_INLINABLE_FN("std_Array_shift" , array_shift, 0 , 0 , ArrayShift),
JS_INLINABLE_FN("std_Array_slice" , array_slice, 2 , 0 , ArraySlice),
JS_TRAMPOLINE_FN("std_Array_sort" , array_sort, 1 , 0 , ArraySort),
JS_FN("std_Function_apply" , fun_apply, 2 , 0 ),
JS_FN("std_Map_entries" , MapObject::entries, 0 , 0 ),
JS_INLINABLE_FN("std_Map_get" , MapObject::get, 1 , 0 , MapGet),
JS_INLINABLE_FN("std_Map_has" , MapObject::has, 1 , 0 , MapHas),
JS_INLINABLE_FN("std_Map_set" , MapObject::set, 2 , 0 , MapSet),
JS_INLINABLE_FN("std_Math_max" , math_max, 2 , 0 , MathMax),
JS_INLINABLE_FN("std_Math_min" , math_min, 2 , 0 , MathMin),
JS_INLINABLE_FN("std_Math_trunc" , math_trunc, 1 , 0 , MathTrunc),
JS_INLINABLE_FN("std_Object_create" , obj_create, 2 , 0 , ObjectCreate),
JS_INLINABLE_FN("std_Object_isPrototypeOf" , obj_isPrototypeOf, 1 , 0 ,
ObjectIsPrototypeOf),
JS_FN("std_Object_propertyIsEnumerable" , obj_propertyIsEnumerable, 1 , 0 ),
JS_FN("std_Object_setProto" , obj_setProto, 1 , 0 ),
JS_INLINABLE_FN("std_Object_toString" , obj_toString, 0 , 0 , ObjectToString),
JS_INLINABLE_FN("std_Reflect_getPrototypeOf" , Reflect_getPrototypeOf, 1 , 0 ,
ReflectGetPrototypeOf),
JS_FN("std_Reflect_isExtensible" , Reflect_isExtensible, 1 , 0 ),
JS_FN("std_Reflect_ownKeys" , Reflect_ownKeys, 1 , 0 ),
JS_INLINABLE_FN("std_Set_add" , SetObject::add, 1 , 0 , SetAdd),
JS_INLINABLE_FN("std_Set_delete" , SetObject::delete_, 1 , 0 , SetDelete),
JS_INLINABLE_FN("std_Set_has" , SetObject::has, 1 , 0 , SetHas),
JS_INLINABLE_FN("std_Set_size" , SetObject::size, 1 , 0 , SetSize),
JS_FN("std_Set_values" , SetObject::values, 0 , 0 ),
JS_INLINABLE_FN("std_String_codePointAt" , str_codePointAt, 1 , 0 ,
StringCodePointAt),
JS_INLINABLE_FN("std_String_fromCodePoint" , str_fromCodePoint, 1 , 0 ,
StringFromCodePoint),
JS_INLINABLE_FN("std_String_includes" , str_includes, 1 , 0 , StringIncludes),
JS_INLINABLE_FN("std_String_indexOf" , str_indexOf, 1 , 0 , StringIndexOf),
JS_TRAMPOLINE_FN("std_TypedArray_sort" , TypedArrayObject::sort, 1 , 0 ,
TypedArraySort),
JS_INLINABLE_FN("std_WeakMap_get" , WeakMapObject::get, 1 , 0 , WeakMapGet),
JS_INLINABLE_FN("std_WeakMap_has" , WeakMapObject::has, 1 , 0 , WeakMapHas),
JS_FN("std_WeakMap_set" , WeakMapObject::set, 2 , 0 ),
JS_FS_END,
};
#ifdef DEBUG
static void CheckSelfHostedIntrinsics() {
// The `intrinsic_functions` list must be sorted so that we can use
// mozilla::BinarySearch to do lookups on demand.
const char * prev = "" ;
for (JSFunctionSpec spec : intrinsic_functions) {
if (spec.name.string()) {
MOZ_ASSERT(strcmp(prev, spec.name.string()) < 0 ,
"Self-hosted intrinsics must be sorted" );
prev = spec.name.string();
}
}
}
class CheckTenuredTracer : public JS::CallbackTracer {
HashSet<gc::Cell*, DefaultHasher<gc::Cell*>, SystemAllocPolicy> visited;
Vector<JS::GCCellPtr, 0 , SystemAllocPolicy> stack;
public:
explicit CheckTenuredTracer(JSRuntime* rt) : JS::CallbackTracer(rt) {}
void check() {
while (!stack.empty()) {
JS::TraceChildren(this, stack.popCopy());
}
}
bool onChild(JS::GCCellPtr thing, const char * name) override {
gc::Cell* cell = thing.asCell();
MOZ_RELEASE_ASSERT(cell->isTenured(), "Expected tenured cell" );
if (!visited.has(cell)) {
if (!visited.put(cell) || !stack.append(thing)) {
// Ignore OOM. This can happen during fuzzing.
return true;
}
}
return true;
}
};
static void CheckSelfHostingDataIsTenured(JSRuntime* rt) {
// Check everything is tenured as we don't trace it when collecting the
// nursery.
CheckTenuredTracer trc(rt);
rt->traceSelfHostingStencil(&trc);
trc.check();
}
#endif
const JSFunctionSpec* js::FindIntrinsicSpec(js::PropertyName* name) {
size_t limit = std::size(intrinsic_functions) - 1 ;
MOZ_ASSERT(!intrinsic_functions[limit].name);
MOZ_ASSERT(name->hasLatin1Chars());
JS::AutoCheckCannotGC nogc;
const char * chars = reinterpret_cast<const char *>(name->latin1Chars(nogc));
size_t len = name->length();
// NOTE: CheckSelfHostedIntrinsics checks that the intrinsic_functions list is
// sorted appropriately so that we can use binary search here.
size_t loc = 0 ;
bool match = mozilla::BinarySearchIf(
intrinsic_functions, 0 , limit,
[chars, len](const JSFunctionSpec& spec) {
// The spec string is null terminated but the `name` string is not, so
// compare chars up until the length of `name`. Since the `name` string
// does not contain any nulls, seeing the null terminator of the spec
// string will terminate the loop appropriately. A final comparison
// against null is needed to determine if the spec string has an extra
// suffix.
const char * spec_chars = spec.name.string();
for (size_t i = 0 ; i < len; ++i) {
if (auto cmp_result = int (chars[i]) - int (spec_chars[i])) {
return cmp_result;
}
}
return int ('\0' ) - int (spec_chars[len]);
},
&loc);
if (match) {
return &intrinsic_functions[loc];
}
return nullptr;
}
void js::FillSelfHostingCompileOptions(CompileOptions& options) {
/*
* In self - hosting mode , scripts use JSOp : : GetIntrinsic instead of
* JSOp : : GetName or JSOp : : GetGName to access unbound variables .
* JSOp : : GetIntrinsic does a name lookup on a special object , whose
* properties are filled in lazily upon first access for a given global .
*
* As that object is inaccessible to client code , the lookups are
* guaranteed to return the original objects , ensuring safe implementation
* of self - hosted builtins .
*
* Additionally , the special syntax callFunction ( fun , receiver , . . . args )
* is supported , for which bytecode is emitted that invokes | fun | with
* | receiver | as the this - object and . . . args as the arguments .
*/
options.setIntroductionType("self-hosted" );
options.setFileAndLine("self-hosted" , 1 );
options.setSkipFilenameValidation(true);
options.setSelfHostingMode(true);
options.setForceFullParse();
options.setForceStrictMode();
options.setDiscardSource();
options.setIsRunOnce(true);
options.setNoScriptRval(true);
}
// Report all errors and warnings to stderr because it is too early in the
// startup process for any other error reporting to be used, and we don't want
// errors in self-hosted code to be silently swallowed.
class MOZ_STACK_CLASS AutoPrintSelfHostingFrontendContext
: public FrontendContext {
JSContext* cx_;
public:
explicit AutoPrintSelfHostingFrontendContext(JSContext* cx) : cx_(cx) {
setCurrentJSContext(cx_);
}
~AutoPrintSelfHostingFrontendContext() {
// TODO: Remove this once JSContext is removed from frontend.
MaybePrintAndClearPendingException(cx_);
if (hadOutOfMemory()) {
fprintf(stderr, "Out of memory\n" );
}
if (maybeError()) {
JS::PrintError(stderr, &*maybeError(), true);
}
for (CompileError& error : warnings()) {
JS::PrintError(stderr, &error, true);
}
if (hadOverRecursed()) {
fprintf(stderr, "Over recursed\n" );
}
if (hadAllocationOverflow()) {
fprintf(stderr, "Allocation overflow\n" );
}
}
};
[[nodiscard]] static bool InitSelfHostingFromStencil(
JSContext* cx, frontend::CompilationAtomCache& atomCache,
const frontend::CompilationStencil& stencil) {
// Build the JSAtom -> ScriptIndexRange mapping and save on the runtime.
{
auto & scriptMap = cx->runtime()->selfHostScriptMap.ref();
// We don't easily know the number of top-level functions, so use the total
// number of stencil functions instead. There is very little nesting of
// functions in self-hosted code so this is a good approximation.
size_t numSelfHostedScripts = stencil.scriptData.size();
if (!scriptMap.reserve(numSelfHostedScripts)) {
ReportOutOfMemory(cx);
return false ;
}
auto topLevelThings =
stencil.scriptData[frontend::CompilationStencil::TopLevelIndex]
.gcthings(stencil);
// Iterate over the (named) top-level functions. We record the ScriptIndex
// as well as the ScriptIndex of the next top-level function. Scripts
// between these two indices are the inner functions of the first one. We
// only record named scripts here since they are what might be looked up.
Rooted<JSAtom*> prevAtom(cx);
frontend::ScriptIndex prevIndex;
for (frontend::TaggedScriptThingIndex thing : topLevelThings) {
if (!thing.isFunction()) {
continue ;
}
frontend::ScriptIndex index = thing.toFunction();
const auto & script = stencil.scriptData[index];
if (prevAtom) {
frontend::ScriptIndexRange range{prevIndex, index};
scriptMap.putNewInfallible(prevAtom, range);
}
prevAtom = script.functionAtom
? atomCache.getExistingAtomAt(cx, script.functionAtom)
: nullptr;
prevIndex = index;
}
if (prevAtom) {
frontend::ScriptIndexRange range{
prevIndex, frontend::ScriptIndex(stencil.scriptData.size())};
scriptMap.putNewInfallible(prevAtom, range);
}
// We over-estimated the capacity of `scriptMap`, so check that the estimate
// hasn't drifted too hasn't drifted too far since this was written. If this
// assert fails, we may need a new way to size the `scriptMap`.
MOZ_ASSERT(numSelfHostedScripts < (scriptMap.count() * 1 .15 ));
}
#ifdef DEBUG
// Check that the list of intrinsics is well-formed.
CheckSelfHostedIntrinsics();
CheckSelfHostingDataIsTenured(cx->runtime());
#endif
return true;
}
bool JSRuntime::initSelfHostingStencil(JSContext* cx,
JS::SelfHostedCache xdrCache,
JS::SelfHostedWriter xdrWriter) {
if (parentRuntime) {
MOZ_RELEASE_ASSERT(
parentRuntime->hasInitializedSelfHosting(),
"Parent runtime must initialize self-hosting before workers" );
selfHostStencilInput_ = parentRuntime->selfHostStencilInput_;
selfHostStencil_ = parentRuntime->selfHostStencil_;
return true;
}
auto start = mozilla::TimeStamp::Now();
// Variables used to instantiate scripts.
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
// Try initializing from Stencil XDR.
AutoPrintSelfHostingFrontendContext fc(cx);
if (xdrCache.Length() > 0 ) {
// Allow the VM to directly use bytecode from the XDR buffer without
// copying it. The buffer must outlive all runtimes (including workers).
options.borrowBuffer = true;
options.usePinnedBytecode = true;
Rooted<UniquePtr<frontend::CompilationInput>> input(
cx, cx->new_<frontend::CompilationInput>(options));
if (!input) {
return false ;
}
{
AutoReportFrontendContext fc(cx);
if (!input->initForSelfHostingGlobal(&fc)) {
return false ;
}
}
JS::DecodeOptions decodeOption(options);
RefPtr<frontend::CompilationStencil> stencil;
JS::TranscodeResult result =
js::DecodeStencil(&fc, decodeOption, xdrCache, getter_AddRefs(stencil));
if (result == JS::TranscodeResult::Ok) {
MOZ_ASSERT(input->atomCache.empty());
MOZ_ASSERT(!hasSelfHostStencil());
// Move it to the runtime.
setSelfHostingStencil(&input, std::move(stencil));
auto end = mozilla::TimeStamp::Now();
JS_LOG(startup, Info,
"Used XDR for process self-hosted startup. Took %f us" ,
(end - start).ToMicroseconds());
return true;
}
}
// If script wasn't generated, it means XDR was either not provided or that it
// failed the decoding phase. Parse from text as before.
uint32_t srcLen = GetRawScriptsSize();
const unsigned char * compressed = compressedSources;
uint32_t compressedLen = GetCompressedSize();
auto src = cx->make_pod_array<char >(srcLen);
if (!src) {
return false ;
}
if (!DecompressString(compressed, compressedLen,
reinterpret_cast<unsigned char *>(src.get()), srcLen)) {
return false ;
}
JS::SourceText<mozilla::Utf8Unit> srcBuf;
if (!srcBuf.init(cx, std::move(src), srcLen)) {
return false ;
}
Rooted<UniquePtr<frontend::CompilationInput>> input(
cx, cx->new_<frontend::CompilationInput>(options));
if (!input) {
return false ;
}
frontend::NoScopeBindingCache scopeCache;
RefPtr<frontend::CompilationStencil> stencil =
frontend::CompileGlobalScriptToStencilWithInput(
cx, &fc, cx->tempLifoAlloc(), *input, &scopeCache, srcBuf,
ScopeKind::Global);
if (!stencil) {
return false ;
}
mozilla::TimeDuration xdrDuration;
// Serialize the stencil to XDR.
if (xdrWriter) {
auto encodeStart = mozilla::TimeStamp::Now();
JS::TranscodeBuffer xdrBuffer;
JS::TranscodeResult result = js::EncodeStencil(cx, stencil, xdrBuffer);
if (result != JS::TranscodeResult::Ok) {
JS_ReportErrorASCII(cx, "Encoding failure" );
return false ;
}
if (!xdrWriter(cx, xdrBuffer)) {
return false ;
}
auto encodeEnd = mozilla::TimeStamp::Now();
xdrDuration = (encodeEnd - encodeStart);
JS_LOG(startup, Info, "Saved XDR Buffer. Took %f us" ,
xdrDuration.ToMicroseconds());
}
MOZ_ASSERT(input->atomCache.empty());
MOZ_ASSERT(!hasSelfHostStencil());
// Move it to the runtime.
setSelfHostingStencil(&input, std::move(stencil));
auto end = mozilla::TimeStamp::Now();
JS_LOG(startup, Info,
"Used source text for process self-hosted startup. Took %f us (%f us "
"XDR encode)" ,
(end - start).ToMicroseconds(), xdrDuration.ToMicroseconds());
return true;
}
void JSRuntime::setSelfHostingStencil(
MutableHandle<UniquePtr<frontend::CompilationInput>> input,
RefPtr<frontend::CompilationStencil>&& stencil) {
MOZ_ASSERT(!selfHostStencilInput_);
MOZ_ASSERT(!selfHostStencil_);
selfHostStencilInput_ = input.release();
selfHostStencil_ = stencil.forget().take();
#ifdef DEBUG
CheckSelfHostingDataIsTenured(this);
#endif
}
bool JSRuntime::initSelfHostingFromStencil(JSContext* cx) {
return InitSelfHostingFromStencil(
cx, cx->runtime()->selfHostStencilInput_->atomCache,
*cx->runtime()->selfHostStencil_);
}
void JSRuntime::finishSelfHosting() {
if (!parentRuntime) {
js_delete(selfHostStencilInput_.ref());
if (selfHostStencil_) {
// delete selfHostStencil_ by decrementing the ref-count of the last
// instance.
RefPtr<frontend::CompilationStencil> stencil;
*getter_AddRefs(stencil) = selfHostStencil_;
MOZ_ASSERT(!stencil->hasMultipleReference());
}
}
selfHostStencilInput_ = nullptr;
selfHostStencil_ = nullptr;
selfHostScriptMap.ref().clear();
clearSelfHostedJitCache();
}
void JSRuntime::clearSelfHostedJitCache() {
for (auto iter = selfHostJitCache.ref().iter(); !iter.done(); iter.next()) {
jit::BaselineScript* baselineScript = iter.get().value();
jit::BaselineScript::Destroy(gcContext(), baselineScript);
}
selfHostJitCache.ref().clear();
}
void JSRuntime::traceSelfHostingStencil(JSTracer* trc) {
if (selfHostStencilInput_.ref()) {
selfHostStencilInput_->trace(trc);
}
selfHostScriptMap.ref().trace(trc);
selfHostJitCache.ref().trace(trc);
}
GeneratorKind JSRuntime::getSelfHostedFunctionGeneratorKind(
js::PropertyName* name) {
frontend::ScriptIndex index = getSelfHostedScriptIndexRange(name)->start;
auto flags = selfHostStencil().scriptExtra[index].immutableFlags;
return flags.hasFlag(js::ImmutableScriptFlagsEnum::IsGenerator)
? GeneratorKind::Generator
: GeneratorKind::NotGenerator;
}
// Returns the ScriptSourceObject to use for cloned self-hosted scripts in the
// current realm.
ScriptSourceObject* js::SelfHostingScriptSourceObject(JSContext* cx) {
return GlobalObject::getOrCreateSelfHostingScriptSourceObject(cx,
cx->global());
}
/* static */
ScriptSourceObject* GlobalObject::getOrCreateSelfHostingScriptSourceObject(
JSContext* cx, Handle<GlobalObject*> global) {
MOZ_ASSERT(cx->global() == global);
if (ScriptSourceObject* sso = global->data().selfHostingScriptSource) {
return sso;
}
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
RefPtr<ScriptSource> source(cx->new_<ScriptSource>());
if (!source) {
return nullptr;
}
Rooted<ScriptSourceObject*> sourceObject(cx);
{
AutoReportFrontendContext fc(cx);
if (!source->initFromOptions(&fc, options)) {
return nullptr;
}
sourceObject = ScriptSourceObject::create(cx, source.get());
if (!sourceObject) {
return nullptr;
}
JS::InstantiateOptions instantiateOptions(options);
if (!ScriptSourceObject::initFromOptions(cx, sourceObject,
instantiateOptions)) {
return nullptr;
}
global->data().selfHostingScriptSource.init(sourceObject);
}
return sourceObject;
}
bool JSRuntime::delazifySelfHostedFunction(JSContext* cx,
Handle<PropertyName*> name,
HandleFunction targetFun) {
MOZ_ASSERT(targetFun->isExtended());
MOZ_ASSERT(targetFun->hasSelfHostedLazyScript());
auto indexRange = *getSelfHostedScriptIndexRange(name);
auto & stencil = cx->runtime()->selfHostStencil();
if (!stencil.delazifySelfHostedFunction(
cx, cx->runtime()->selfHostStencilInput().atomCache, indexRange, name,
targetFun)) {
return false ;
}
// Relazifiable self-hosted functions may be relazified later into a
// SelfHostedLazyScript, dropping the BaseScript entirely. This only applies
// to named function being delazified. Inner functions used by self-hosting
// are never relazified.
BaseScript* targetScript = targetFun->baseScript();
if (targetScript->isRelazifiable()) {
targetScript->setAllowRelazify();
}
return true;
}
mozilla::Maybe<frontend::ScriptIndexRange>
JSRuntime::getSelfHostedScriptIndexRange(js::PropertyName* name) {
if (parentRuntime) {
return parentRuntime->getSelfHostedScriptIndexRange(name);
}
MOZ_ASSERT(name->isPermanentAndMayBeShared());
if (auto ptr = selfHostScriptMap.ref().readonlyThreadsafeLookup(name)) {
return mozilla::Some(ptr->value());
}
return mozilla::Nothing();
}
static bool GetComputedIntrinsic(JSContext* cx, Handle<PropertyName*> name,
MutableHandleValue vp) {
// If the intrinsic was not in hardcoded set, run the top-level of the
// selfhosted script. This will generate values and call `SetIntrinsic` to
// save them on a special "computed intrinsics holder". We then can check for
// our required values and cache on the normal intrinsics holder.
Rooted<NativeObject*> computedIntrinsicsHolder(
cx, cx->global()->getComputedIntrinsicsHolder());
if (!computedIntrinsicsHolder) {
auto computedIntrinsicHolderGuard = mozilla::MakeScopeExit(
[cx]() { cx->global()->setComputedIntrinsicsHolder(nullptr); });
// Instantiate a script in current realm from the shared Stencil.
JSRuntime* runtime = cx->runtime();
RootedScript script(
cx, runtime->selfHostStencil().instantiateSelfHostedTopLevelForRealm(
cx, runtime->selfHostStencilInput()));
if (!script) {
return false ;
}
// Attach the computed intrinsics holder to the global now to capture
// generated values.
computedIntrinsicsHolder =
NewPlainObjectWithProto(cx, nullptr, TenuredObject);
if (!computedIntrinsicsHolder) {
return false ;
}
cx->global()->setComputedIntrinsicsHolder(computedIntrinsicsHolder);
// Disable the interrupt callback while executing the top-level script.
// This prevents recursive calls to GetComputedIntrinsic through the
// interrupt callback.
bool hadInterruptsDisabled = JS_DisableInterruptCallback(cx);
auto resetInterrupts = mozilla::MakeScopeExit(
[&]() { JS_ResetInterruptCallback(cx, hadInterruptsDisabled); });
// Attempt to execute the top-level script. If they fails to run to
// successful completion, throw away the holder to avoid a partial
// initialization state.
if (!JS_ExecuteScript(cx, script)) {
return false ;
}
// Successfully ran the self-host top-level in current realm, so these
// computed intrinsic values are now source of truth for the realm.
computedIntrinsicHolderGuard.release();
}
// Cache the individual intrinsic on the standard holder object so that we
// only have to look for it in one place when performing `GetIntrinsic`.
mozilla::Maybe<PropertyInfo> prop =
computedIntrinsicsHolder->lookup(cx, name);
#ifdef DEBUG
if (!prop) {
Fprinter out(stderr);
out.printf("SelfHosted intrinsic not found: " );
name->dumpPropertyName(out);
out.printf("\n" );
}
#endif
MOZ_RELEASE_ASSERT(prop, "SelfHosted intrinsic not found" );
RootedValue value(cx, computedIntrinsicsHolder->getSlot(prop->slot()));
return GlobalObject::addIntrinsicValue(cx, cx->global(), name, value);
}
bool JSRuntime::getSelfHostedValue(JSContext* cx, Handle<PropertyName*> name,
MutableHandleValue vp) {
// If the self-hosted value we want is a function in the stencil, instantiate
// a lazy self-hosted function for it. This is typical when a self-hosted
// function calls other self-hosted helper functions.
if (auto index = getSelfHostedScriptIndexRange(name)) {
JSFunction* fun =
cx->runtime()->selfHostStencil().instantiateSelfHostedLazyFunction(
cx, cx->runtime()->selfHostStencilInput().atomCache, index->start,
name);
if (!fun) {
return false ;
}
vp.setObject(*fun);
return true;
}
return GetComputedIntrinsic(cx, name, vp);
}
void JSRuntime::assertSelfHostedFunctionHasCanonicalName(
Handle<PropertyName*> name) {
#ifdef DEBUG
frontend::ScriptIndex index = getSelfHostedScriptIndexRange(name)->start;
MOZ_ASSERT(selfHostStencil().scriptData[index].hasSelfHostedCanonicalName());
#endif
}
bool js::IsSelfHostedFunctionWithName(JSFunction* fun, JSAtom* name) {
return fun->isSelfHostedBuiltin() && fun->isExtended() &&
GetClonedSelfHostedFunctionName(fun) == name;
}
bool js::IsSelfHostedFunctionWithName(const Value& v, JSAtom* name) {
if (!v.isObject() || !v.toObject().is<JSFunction>()) {
return false ;
}
JSFunction* fun = &v.toObject().as<JSFunction>();
return IsSelfHostedFunctionWithName(fun, name);
}
static_assert(
JSString::MAX_LENGTH <= INT32_MAX,
"StringIteratorNext in builtin/String.js assumes the stored index "
"into the string is an Int32Value" );
static_assert(JSString::MAX_LENGTH == MAX_STRING_LENGTH,
"JSString::MAX_LENGTH matches self-hosted constant for maximum "
"string length" );
static_assert(ARGS_LENGTH_MAX == MAX_ARGS_LENGTH,
"ARGS_LENGTH_MAX matches self-hosted constant for maximum "
"arguments length" );
Messung V0.5 in Prozent C=98 H=98 G=97
¤ Dauer der Verarbeitung: 0.33 Sekunden
¤
*© Formatika GbR, Deutschland