// FIXME: Use the enumeration cache. EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec) { if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, ASCIILiteral("Requested keys of a value that is not an object."))); PropertyNameArray properties(exec); asObject(exec->argument(0))->methodTable(exec->vm())->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties); JSArray* keys = constructEmptyArray(exec, 0); size_t numProperties = properties.size(); for (size_t i = 0; i < numProperties; i++) keys->push(exec, jsOwnedString(exec, properties[i].string())); return JSValue::encode(keys); }
// FIXME: Use the enumeration cache. EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec) { if (!exec->argument(0).isObject()) return throwVMError(exec, createTypeError(exec, "Requested property names of a value that is not an object.")); PropertyNameArray properties(exec); asObject(exec->argument(0))->getOwnPropertyNames(exec, properties, IncludeDontEnumProperties); JSArray* names = constructEmptyArray(exec); size_t numProperties = properties.size(); for (size_t i = 0; i < numProperties; i++) names->push(exec, jsOwnedString(exec, properties[i].ustring())); return JSValue::encode(names); }
JSArray* ShadowChicken::functionsOnStack(ExecState* exec) { JSArray* result = constructEmptyArray(exec, 0); iterate( exec->vm(), exec, [&] (const Frame& frame) -> bool { result->push(exec, frame.callee); return true; }); return result; }
JSArray* ShadowChicken::functionsOnStack(ExecState* exec) { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSArray* result = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, nullptr); iterate( vm, exec, [&] (const Frame& frame) -> bool { result->push(exec, frame.callee); RELEASE_ASSERT(!scope.exception()); // This function is only called from tests. return true; }); return result; }
JSValue Compilation::toJS(ExecState* exec) const { JSObject* result = constructEmptyObject(exec); result->putDirect(exec->vm(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); result->putDirect(exec->vm(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); JSArray* profiledBytecodes = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec)); result->putDirect(exec->vm(), exec->propertyNames().profiledBytecodes, profiledBytecodes); JSArray* descriptions = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_descriptions.size(); ++i) descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec)); result->putDirect(exec->vm(), exec->propertyNames().descriptions, descriptions); JSArray* counters = constructEmptyArray(exec, 0); for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) { JSObject* counterEntry = constructEmptyObject(exec); counterEntry->putDirect(exec->vm(), exec->propertyNames().origin, it->key.toJS(exec)); counterEntry->putDirect(exec->vm(), exec->propertyNames().executionCount, jsNumber(it->value->count())); counters->push(exec, counterEntry); } result->putDirect(exec->vm(), exec->propertyNames().counters, counters); JSArray* exitSites = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_osrExitSites.size(); ++i) exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec)); result->putDirect(exec->vm(), exec->propertyNames().osrExitSites, exitSites); JSArray* exits = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_osrExits.size(); ++i) exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec)); result->putDirect(exec->vm(), exec->propertyNames().osrExits, exits); result->putDirect(exec->vm(), exec->propertyNames().numInlinedGetByIds, jsNumber(m_numInlinedGetByIds)); result->putDirect(exec->vm(), exec->propertyNames().numInlinedPutByIds, jsNumber(m_numInlinedPutByIds)); result->putDirect(exec->vm(), exec->propertyNames().numInlinedCalls, jsNumber(m_numInlinedCalls)); result->putDirect(exec->vm(), exec->propertyNames().jettisonReason, jsString(exec, String::fromUTF8(toCString(m_jettisonReason)))); if (!m_additionalJettisonReason.isNull()) result->putDirect(exec->vm(), exec->propertyNames().additionalJettisonReason, jsString(exec, String::fromUTF8(m_additionalJettisonReason))); return result; }
JSValue Compilation::toJS(ExecState* exec) const { JSObject* result = constructEmptyObject(exec); result->putDirect(exec->globalData(), exec->propertyNames().bytecodesID, jsNumber(m_bytecodes->id())); result->putDirect(exec->globalData(), exec->propertyNames().compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); JSArray* profiledBytecodes = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) profiledBytecodes->putDirectIndex(exec, i, m_profiledBytecodes[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().profiledBytecodes, profiledBytecodes); JSArray* descriptions = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_descriptions.size(); ++i) descriptions->putDirectIndex(exec, i, m_descriptions[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().descriptions, descriptions); JSArray* counters = constructEmptyArray(exec, 0); HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator end = m_counters.end(); for (HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator iter = m_counters.begin(); iter != end; ++iter) { JSObject* counterEntry = constructEmptyObject(exec); counterEntry->putDirect(exec->globalData(), exec->propertyNames().origin, iter->key.toJS(exec)); counterEntry->putDirect(exec->globalData(), exec->propertyNames().executionCount, jsNumber(iter->value->count())); counters->push(exec, counterEntry); } result->putDirect(exec->globalData(), exec->propertyNames().counters, counters); JSArray* exitSites = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_osrExitSites.size(); ++i) exitSites->putDirectIndex(exec, i, m_osrExitSites[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().osrExitSites, exitSites); JSArray* exits = constructEmptyArray(exec, 0); for (unsigned i = 0; i < m_osrExits.size(); ++i) exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec)); result->putDirect(exec->globalData(), exec->propertyNames().osrExits, exits); return result; }
JSValue LiteralParser::parseArray() { StackGuard guard(this); if (!guard.isSafe()) return abortParse(); JSArray* array = constructEmptyArray(m_exec); while (true) { m_lexer.next(); JSValue value = parseExpression(); if (m_aborted) return JSValue(); if (!value) break; array->push(m_exec, value); if (m_lexer.currentToken().type != TokComma) break; } if (m_lexer.currentToken().type != TokRBracket) return abortParse(); m_lexer.next(); return array; }
JSValue collectMatches(VM& vm, ExecState* exec, JSString* string, const String& s, RegExpConstructor* constructor, RegExp* regExp, const FixEndFunc& fixEnd) { auto scope = DECLARE_THROW_SCOPE(vm); MatchResult result = constructor->performMatch(vm, regExp, string, s, 0); if (!result) return jsNull(); static unsigned maxSizeForDirectPath = 100000; JSArray* array = constructEmptyArray(exec, nullptr); if (UNLIKELY(vm.exception())) return jsUndefined(); auto iterate = [&] () { size_t end = result.end; size_t length = end - result.start; array->push(exec, JSRopeString::createSubstringOfResolved(vm, string, result.start, length)); if (!length) end = fixEnd(end); result = constructor->performMatch(vm, regExp, string, s, end); }; do { if (array->length() >= maxSizeForDirectPath) { // First do a throw-away match to see how many matches we'll get. unsigned matchCount = 0; MatchResult savedResult = result; do { if (array->length() + matchCount >= MAX_STORAGE_VECTOR_LENGTH) { throwOutOfMemoryError(exec, scope); return jsUndefined(); } size_t end = result.end; matchCount++; if (result.empty()) end = fixEnd(end); // Using RegExpConstructor::performMatch() instead of calling RegExp::match() // directly is a surprising but profitable choice: it means that when we do OOM, we // will leave the cached result in the state it ought to have had just before the // OOM! On the other hand, if this loop concludes that the result is small enough, // then the iterate() loop below will overwrite the cached result anyway. result = constructor->performMatch(vm, regExp, string, s, end); } while (result); // OK, we have a sensible number of matches. Now we can create them for reals. result = savedResult; do iterate(); while (result); return array; } iterate(); } while (result); return array; }
JSValue Compilation::toJS(ExecState* exec) const { VM& vm = exec->vm(); auto scope = DECLARE_THROW_SCOPE(vm); JSObject* result = constructEmptyObject(exec); RETURN_IF_EXCEPTION(scope, { }); result->putDirect(vm, vm.propertyNames->bytecodesID, jsNumber(m_bytecodes->id())); result->putDirect(vm, vm.propertyNames->compilationKind, jsString(exec, String::fromUTF8(toCString(m_kind)))); JSArray* profiledBytecodes = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, { }); for (unsigned i = 0; i < m_profiledBytecodes.size(); ++i) { auto value = m_profiledBytecodes[i].toJS(exec); RETURN_IF_EXCEPTION(scope, { }); profiledBytecodes->putDirectIndex(exec, i, value); RETURN_IF_EXCEPTION(scope, { }); } result->putDirect(vm, vm.propertyNames->profiledBytecodes, profiledBytecodes); JSArray* descriptions = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, { }); for (unsigned i = 0; i < m_descriptions.size(); ++i) { auto value = m_descriptions[i].toJS(exec); RETURN_IF_EXCEPTION(scope, { }); descriptions->putDirectIndex(exec, i, value); RETURN_IF_EXCEPTION(scope, { }); } result->putDirect(vm, vm.propertyNames->descriptions, descriptions); JSArray* counters = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, { }); for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) { JSObject* counterEntry = constructEmptyObject(exec); RETURN_IF_EXCEPTION(scope, { }); auto value = it->key.toJS(exec); RETURN_IF_EXCEPTION(scope, { }); counterEntry->putDirect(vm, vm.propertyNames->origin, value); counterEntry->putDirect(vm, vm.propertyNames->executionCount, jsNumber(it->value->count())); counters->push(exec, counterEntry); RETURN_IF_EXCEPTION(scope, { }); } result->putDirect(vm, vm.propertyNames->counters, counters); JSArray* exitSites = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, { }); for (unsigned i = 0; i < m_osrExitSites.size(); ++i) { auto value = m_osrExitSites[i].toJS(exec); RETURN_IF_EXCEPTION(scope, { }); exitSites->putDirectIndex(exec, i, value); RETURN_IF_EXCEPTION(scope, { }); } result->putDirect(vm, vm.propertyNames->osrExitSites, exitSites); JSArray* exits = constructEmptyArray(exec, 0); RETURN_IF_EXCEPTION(scope, { }); for (unsigned i = 0; i < m_osrExits.size(); ++i) { exits->putDirectIndex(exec, i, m_osrExits[i].toJS(exec)); RETURN_IF_EXCEPTION(scope, { }); } result->putDirect(vm, vm.propertyNames->osrExits, exits); result->putDirect(vm, vm.propertyNames->numInlinedGetByIds, jsNumber(m_numInlinedGetByIds)); result->putDirect(vm, vm.propertyNames->numInlinedPutByIds, jsNumber(m_numInlinedPutByIds)); result->putDirect(vm, vm.propertyNames->numInlinedCalls, jsNumber(m_numInlinedCalls)); result->putDirect(vm, vm.propertyNames->jettisonReason, jsString(exec, String::fromUTF8(toCString(m_jettisonReason)))); if (!m_additionalJettisonReason.isNull()) result->putDirect(vm, vm.propertyNames->additionalJettisonReason, jsString(exec, String::fromUTF8(m_additionalJettisonReason))); result->putDirect(vm, vm.propertyNames->uid, m_uid.toJS(exec)); return result; }
static JSValue performPromiseAll(ExecState* exec, JSValue iterator, JSValue C, JSPromiseDeferred* deferred) { JSObject* thisObject = asObject(C); VM& vm = exec->vm(); // 6. Let 'values' be the result of calling ArrayCreate(0). JSArray* values = constructEmptyArray(exec, nullptr, thisObject->globalObject()); // 7. Let 'countdownHolder' be Record { [[Countdown]]: 0 }. NumberObject* countdownHolder = constructNumber(exec, thisObject->globalObject(), JSValue(0)); // 8. Let 'index' be 0. unsigned index = 0; // 9. Repeat. do { // i. Let 'next' be the result of calling IteratorStep(iterator). JSValue next = iteratorStep(exec, iterator); if (exec->hadException()) return jsUndefined(); // iii. If 'next' is false, if (next.isFalse()) { // a. If 'index' is 0, if (!index) { // a. Let 'resolveResult' be the result of calling the [[Call]] internal method // of deferred.[[Resolve]] with undefined as thisArgument and a List containing // values as argumentsList. performDeferredResolve(exec, deferred, values); // b. ReturnIfAbrupt(resolveResult). if (exec->hadException()) return jsUndefined(); } // b. Return deferred.[[Promise]]. return deferred->promise(); } // iv. Let 'nextValue' be the result of calling IteratorValue(next). // v. RejectIfAbrupt(nextValue, deferred). JSValue nextValue = iteratorValue(exec, next); if (exec->hadException()) return jsUndefined(); values->push(exec, jsUndefined()); // vi. Let 'nextPromise' be the result of calling Invoke(C, "resolve", (nextValue)). JSValue resolveFunction = C.get(exec, vm.propertyNames->resolve); if (exec->hadException()) return jsUndefined(); CallData resolveFunctionCallData; CallType resolveFunctionCallType = getCallData(resolveFunction, resolveFunctionCallData); if (resolveFunctionCallType == CallTypeNone) { throwTypeError(exec); return jsUndefined(); } MarkedArgumentBuffer resolveFunctionArguments; resolveFunctionArguments.append(nextValue); JSValue nextPromise = call(exec, resolveFunction, resolveFunctionCallType, resolveFunctionCallData, C, resolveFunctionArguments); // vii. RejectIfAbrupt(nextPromise, deferred). if (exec->hadException()) return jsUndefined(); // viii. Let 'countdownFunction' be a new built-in function object as defined in Promise.all Countdown Functions. JSFunction* countdownFunction = createPromiseAllCountdownFunction(vm, thisObject->globalObject()); // ix. Set the [[Index]] internal slot of 'countdownFunction' to 'index'. countdownFunction->putDirect(vm, vm.propertyNames->indexPrivateName, JSValue(index)); // x. Set the [[Values]] internal slot of 'countdownFunction' to 'values'. countdownFunction->putDirect(vm, vm.propertyNames->valuesPrivateName, values); // xi. Set the [[Deferred]] internal slot of 'countdownFunction' to 'deferred'. countdownFunction->putDirect(vm, vm.propertyNames->deferredPrivateName, deferred); // xii. Set the [[CountdownHolder]] internal slot of 'countdownFunction' to 'countdownHolder'. countdownFunction->putDirect(vm, vm.propertyNames->countdownHolderPrivateName, countdownHolder); // xiii. Let 'result' be the result of calling Invoke(nextPromise, "then", (countdownFunction, deferred.[[Reject]])). JSValue thenFunction = nextPromise.get(exec, vm.propertyNames->then); if (exec->hadException()) return jsUndefined(); CallData thenFunctionCallData; CallType thenFunctionCallType = getCallData(thenFunction, thenFunctionCallData); if (thenFunctionCallType == CallTypeNone) { throwTypeError(exec); return jsUndefined(); } MarkedArgumentBuffer thenFunctionArguments; thenFunctionArguments.append(countdownFunction); thenFunctionArguments.append(deferred->reject()); call(exec, thenFunction, thenFunctionCallType, thenFunctionCallData, nextPromise, thenFunctionArguments); // xiv. RejectIfAbrupt(result, deferred). if (exec->hadException()) return jsUndefined(); // xv. Set index to index + 1. index++; // xvi. Set countdownHolder.[[Countdown]] to countdownHolder.[[Countdown]] + 1. uint32_t newCountdownValue = countdownHolder->internalValue().asUInt32() + 1; countdownHolder->setInternalValue(vm, JSValue(newCountdownValue)); } while (true); ASSERT_NOT_REACHED(); return jsUndefined(); }
JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source) { JSGlobalData* globalData = &exec->globalData(); addErrorInfo(globalData, error, line, source); UStringBuilder stackString; JSArray* stackArray = constructEmptyArray(exec); CallFrame* frame = exec; stackString.append(error->toString(exec)); bool functionKnown; ReturnAddressPtr pc; while (!frame->hasHostCallFrameFlag()) { CodeBlock* codeBlock = frame->codeBlock(); JSObject* arrayItem = constructEmptyObject(exec); stackString.append("\n at "); JSObject* callee = frame->callee(); UString functionName; if (callee && callee->inherits(&JSFunction::s_info)) { functionName = asFunction(callee)->calculatedDisplayName(exec); functionKnown = !functionName.isEmpty(); } else { functionKnown = false; } if (functionKnown) { stackString.append(functionName); stackString.append(" ("); arrayItem->putWithAttributes( globalData, Identifier(globalData, functionPropertyName), jsString(globalData, functionName), ReadOnly | DontDelete ); } UString sourceURL = codeBlock->ownerExecutable()->sourceURL(); arrayItem->putWithAttributes( globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete ); stackString.append(sourceURL); stackString.append(":"); if (frame != exec) { line = codeBlock->lineNumberForBytecodeOffset(codeBlock->bytecodeOffset(pc)); } arrayItem->putWithAttributes( globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete ); stackString.append(UString::number(line)); if (functionKnown) { stackString.append(")"); } stackArray->push(exec, JSValue(arrayItem)); pc = frame->returnPC(); frame = frame->callerFrame(); } error->putWithAttributes( globalData, Identifier(globalData, stackPropertyName), jsString(globalData, stackString.toUString()), ReadOnly | DontDelete ); error->putWithAttributes( globalData, Identifier(globalData, "stackArray"), stackArray, ReadOnly | DontDelete ); return error; }