BOOL DynamicObject::CallToPrimitiveFunction(Var toPrimitiveFunction, PropertyId propertyId, Var* result, ScriptContext * requestContext) { if (JavascriptConversion::IsCallable(toPrimitiveFunction)) { RecyclableObject* toStringFunction = RecyclableObject::FromVar(toPrimitiveFunction); ThreadContext * threadContext = requestContext->GetThreadContext(); Var aResult = threadContext->ExecuteImplicitCall(toStringFunction, ImplicitCall_ToPrimitive, [=]() -> Js::Var { // Stack object should have a pre-op bail on implicit call. We shouldn't see them here. Assert(!ThreadContext::IsOnStack(this) || threadContext->HasNoSideEffect(toStringFunction)); return toStringFunction->GetEntryPoint()(toStringFunction, CallInfo(CallFlags_Value, 1), this); }); if (!aResult) { // There was an implicit call and implicit calls are disabled. This would typically cause a bailout. Assert(threadContext->IsDisableImplicitCall()); *result = requestContext->GetLibrary()->GetNull(); return true; } if (JavascriptOperators::GetTypeId(aResult) <= TypeIds_LastToPrimitiveType) { *result = aResult; return true; } } return false; }
Var JavascriptWeakMap::NewInstance(RecyclableObject* function, CallInfo callInfo, ...) { PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault); ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); JavascriptLibrary* library = scriptContext->GetLibrary(); Var newTarget = callInfo.Flags & CallFlags_NewTarget ? args.Values[args.Info.Count] : args[0]; bool isCtorSuperCall = (callInfo.Flags & CallFlags_New) && newTarget != nullptr && RecyclableObject::Is(newTarget); Assert(isCtorSuperCall || !(callInfo.Flags & CallFlags_New) || args[0] == nullptr); CHAKRATEL_LANGSTATS_INC_BUILTINCOUNT(WeakMapCount); JavascriptWeakMap* weakMapObject = nullptr; if (callInfo.Flags & CallFlags_New) { weakMapObject = library->CreateWeakMap(); } else { JavascriptError::ThrowTypeErrorVar(scriptContext, JSERR_NeedObjectOfType, _u("WeakMap"), _u("WeakMap")); } Assert(weakMapObject != nullptr); Var iterable = (args.Info.Count > 1) ? args[1] : library->GetUndefined(); RecyclableObject* iter = nullptr; RecyclableObject* adder = nullptr; if (JavascriptConversion::CheckObjectCoercible(iterable, scriptContext)) { iter = JavascriptOperators::GetIterator(iterable, scriptContext); Var adderVar = JavascriptOperators::GetProperty(weakMapObject, PropertyIds::set, scriptContext); if (!JavascriptConversion::IsCallable(adderVar)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction); } adder = RecyclableObject::FromVar(adderVar); } if (iter != nullptr) { Var nextItem; Var undefined = library->GetUndefined(); while (JavascriptOperators::IteratorStepAndValue(iter, scriptContext, &nextItem)) { if (!JavascriptOperators::IsObject(nextItem)) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedObject); } RecyclableObject* obj = RecyclableObject::FromVar(nextItem); Var key, value; if (!JavascriptOperators::GetItem(obj, 0u, &key, scriptContext)) { key = undefined; } if (!JavascriptOperators::GetItem(obj, 1u, &value, scriptContext)) { value = undefined; } adder->GetEntryPoint()(adder, CallInfo(CallFlags_Value, 3), weakMapObject, key, value); } } return isCtorSuperCall ? JavascriptOperators::OrdinaryCreateFromConstructor(RecyclableObject::FromVar(newTarget), weakMapObject, nullptr, scriptContext) : weakMapObject; }
Var BoundFunction::NewInstance(RecyclableObject* function, CallInfo callInfo, ...) { RUNTIME_ARGUMENTS(args, callInfo); ScriptContext* scriptContext = function->GetScriptContext(); if (args.Info.Count == 0) { JavascriptError::ThrowTypeError(scriptContext, JSERR_NeedFunction /* TODO-ERROR: get arg name - args[0] */); } BoundFunction *boundFunction = (BoundFunction *) function; Var targetFunction = boundFunction->targetFunction; // // var o = new boundFunction() // a new object should be created using the actual function object // Var newVarInstance = nullptr; if (callInfo.Flags & CallFlags_New) { if (JavascriptProxy::Is(targetFunction)) { JavascriptProxy* proxy = JavascriptProxy::FromVar(targetFunction); Arguments proxyArgs(CallInfo(CallFlags_New, 1), &targetFunction); args.Values[0] = newVarInstance = proxy->ConstructorTrap(proxyArgs, scriptContext, 0); } else { args.Values[0] = newVarInstance = JavascriptOperators::NewScObjectNoCtor(targetFunction, scriptContext); } } Js::Arguments actualArgs = args; if (boundFunction->count > 0) { BOOL isCrossSiteObject = boundFunction->IsCrossSiteObject(); // OACR thinks that this can change between here and the check in the for loop below const unsigned int argCount = args.Info.Count; if ((boundFunction->count + argCount) > CallInfo::kMaxCountArgs) { JavascriptError::ThrowRangeError(scriptContext, JSERR_ArgListTooLarge); } Var *newValues = RecyclerNewArray(scriptContext->GetRecycler(), Var, boundFunction->count + argCount); uint index = 0; // // For [[Construct]] use the newly created var instance // For [[Call]] use the "this" to which bind bound it. // if (callInfo.Flags & CallFlags_New) { newValues[index++] = args[0]; } else { newValues[index++] = boundFunction->boundThis; } // Copy the bound args if (!isCrossSiteObject) { for (uint i = 0; i < boundFunction->count; i++) { newValues[index++] = boundFunction->boundArgs[i]; } } else { // it is possible that the bound arguments are not marshalled yet. for (uint i = 0; i < boundFunction->count; i++) { newValues[index++] = CrossSite::MarshalVar(scriptContext, boundFunction->boundArgs[i]); } } // Copy the extra args for (uint i=1; i<argCount; i++) { newValues[index++] = args[i]; } actualArgs = Arguments(args.Info, newValues); actualArgs.Info.Count = boundFunction->count + argCount; } else { if (!(callInfo.Flags & CallFlags_New)) { actualArgs.Values[0] = boundFunction->boundThis; } } RecyclableObject* actualFunction = RecyclableObject::FromVar(targetFunction); Var aReturnValue = JavascriptFunction::CallFunction<true>(actualFunction, actualFunction->GetEntryPoint(), actualArgs); // // [[Construct]] and call returned a non-object // return the newly created var instance // if ((callInfo.Flags & CallFlags_New) && !JavascriptOperators::IsObject(aReturnValue)) { aReturnValue = newVarInstance; } return aReturnValue; }