CustomExternalIterator.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #include "RuntimeLibraryPch.h"
  6. namespace Js
  7. {
  8. ExternalIteratorCreatorFunction::ExternalIteratorCreatorFunction(DynamicType* type,
  9. FunctionInfo* functionInfo,
  10. JavascriptTypeId typeId,
  11. uint byteCount,
  12. Var prototypeForIterator, InitIteratorFunction initFunction, NextFunction nextFunction)
  13. : RuntimeFunction(type, functionInfo), m_externalTypeId(typeId), m_extraByteCount(byteCount),
  14. m_prototypeForIterator(prototypeForIterator), m_initFunction(initFunction), m_nextFunction(nextFunction)
  15. {
  16. }
  17. void ExternalIteratorCreatorFunction::ThrowIfNotValidObject(Var instance)
  18. {
  19. JavascriptTypeId typeId = (JavascriptTypeId)Js::JavascriptOperators::GetTypeId(instance);
  20. if (typeId != m_externalTypeId || !RecyclableObject::Is(m_prototypeForIterator))
  21. {
  22. JavascriptError::ThrowTypeError(GetScriptContext(), JSERR_InvalidIterableObject);
  23. }
  24. }
  25. Var ExternalIteratorCreatorFunction::CreateFunction(JavascriptLibrary *library,
  26. JavascriptTypeId typeId,
  27. JavascriptMethod entryPoint,
  28. uint byteCount,
  29. Var prototypeForIterator, InitIteratorFunction initFunction, NextFunction nextFunction)
  30. {
  31. FunctionInfo* functionInfo = RecyclerNew(library->GetRecycler(), FunctionInfo, entryPoint);
  32. DynamicType* type = library->CreateDeferredPrototypeFunctionType(entryPoint);
  33. ExternalIteratorCreatorFunction* function = RecyclerNewEnumClass(library->GetRecycler(),
  34. EnumClass_1_Bit,
  35. ExternalIteratorCreatorFunction,
  36. type,
  37. functionInfo,
  38. typeId,
  39. byteCount,
  40. prototypeForIterator, initFunction, nextFunction);
  41. function->SetPropertyWithAttributes(PropertyIds::length, TaggedInt::ToVarUnchecked(0), PropertyConfigurable, nullptr);
  42. return function;
  43. }
  44. Var ExternalIteratorCreatorFunction::CreateCustomExternalIterator(Var instance, ExternalIteratorCreatorFunction* function, ExternalIteratorKind kind)
  45. {
  46. Assert(function != nullptr);
  47. function->ThrowIfNotValidObject(instance);
  48. ScriptContext *scriptContext = function->GetScriptContext();
  49. AssertOrFailFast(RecyclableObject::Is(function->m_prototypeForIterator));
  50. DynamicObject *prototype = static_cast<DynamicObject*>(PointerValue(function->m_prototypeForIterator));
  51. Js::DynamicType *type = scriptContext->GetLibrary()->CreateObjectTypeNoCache(prototype, TypeIds_ExternalIterator);
  52. AssertOrFailFast(function->m_extraByteCount >= sizeof(void*));
  53. CustomExternalIterator *iterator = RecyclerNewPlus(scriptContext->GetRecycler(),
  54. function->m_extraByteCount,
  55. CustomExternalIterator,
  56. type,
  57. kind,
  58. function->m_externalTypeId,
  59. function->m_nextFunction);
  60. AssertOrFailFast(function->m_initFunction != nullptr);
  61. BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext)
  62. {
  63. function->m_initFunction(instance, (Var)iterator);
  64. }
  65. END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext);
  66. return iterator;
  67. }
  68. Var ExternalIteratorCreatorFunction::EntryExternalEntries(RecyclableObject* function, CallInfo callInfo, ...)
  69. {
  70. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  71. ARGUMENTS(args, callInfo);
  72. if (args.Info.Flags & CallFlags_New)
  73. {
  74. JavascriptError::ThrowTypeError(function->GetScriptContext(), JSERR_ErrorOnNew);
  75. }
  76. ExternalIteratorCreatorFunction* iteratorFunction = static_cast<ExternalIteratorCreatorFunction*>(function);
  77. return CreateCustomExternalIterator(args[0], iteratorFunction, ExternalIteratorKind::External_KeyAndValue);
  78. }
  79. Var ExternalIteratorCreatorFunction::EntryExternalKeys(RecyclableObject* function, CallInfo callInfo, ...)
  80. {
  81. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  82. ARGUMENTS(args, callInfo);
  83. if (args.Info.Flags & CallFlags_New)
  84. {
  85. JavascriptError::ThrowTypeError(function->GetScriptContext(), JSERR_ErrorOnNew);
  86. }
  87. ExternalIteratorCreatorFunction* iteratorFunction = static_cast<ExternalIteratorCreatorFunction*>(function);
  88. return CreateCustomExternalIterator(args[0], iteratorFunction, ExternalIteratorKind::External_Keys);
  89. }
  90. Var ExternalIteratorCreatorFunction::EntryExternalValues(RecyclableObject* function, CallInfo callInfo, ...)
  91. {
  92. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  93. ARGUMENTS(args, callInfo);
  94. if (args.Info.Flags & CallFlags_New)
  95. {
  96. JavascriptError::ThrowTypeError(function->GetScriptContext(), JSERR_ErrorOnNew);
  97. }
  98. ExternalIteratorCreatorFunction* iteratorFunction = static_cast<ExternalIteratorCreatorFunction*>(function);
  99. return CreateCustomExternalIterator(args[0], iteratorFunction, ExternalIteratorKind::External_Values);
  100. }
  101. JavascriptExternalIteratorNextFunction::JavascriptExternalIteratorNextFunction(DynamicType* type,
  102. FunctionInfo* functionInfo,
  103. JavascriptTypeId typeId)
  104. : RuntimeFunction(type, functionInfo), m_externalTypeId(typeId)
  105. { }
  106. JavascriptExternalIteratorNextFunction* JavascriptExternalIteratorNextFunction::CreateFunction(JavascriptLibrary *library, JavascriptTypeId typeId, JavascriptMethod entryPoint)
  107. {
  108. FunctionInfo* functionInfo = RecyclerNew(library->GetRecycler(), FunctionInfo, entryPoint);
  109. DynamicType* type = library->CreateDeferredPrototypeFunctionType(entryPoint);
  110. JavascriptExternalIteratorNextFunction* function = RecyclerNewEnumClass(library->GetRecycler(), EnumClass_1_Bit, JavascriptExternalIteratorNextFunction, type, functionInfo, typeId);
  111. function->SetPropertyWithAttributes(PropertyIds::length, TaggedInt::ToVarUnchecked(0), PropertyConfigurable, nullptr);
  112. return function;
  113. }
  114. CustomExternalIterator::CustomExternalIterator(DynamicType* type, ExternalIteratorKind kind, JavascriptTypeId typeId, NextFunction nextFunction) :
  115. DynamicObject(type),
  116. m_kind(kind),
  117. m_externalTypeId(typeId),
  118. m_nextFunction(nextFunction)
  119. {
  120. Assert(type->GetTypeId() == TypeIds_ExternalIterator);
  121. }
  122. bool CustomExternalIterator::Is(Var aValue)
  123. {
  124. TypeId typeId = JavascriptOperators::GetTypeId(aValue);
  125. return typeId == TypeIds_ExternalIterator;
  126. }
  127. CustomExternalIterator* CustomExternalIterator::FromVar(Var aValue)
  128. {
  129. AssertMsg(Is(aValue), "Ensure var is actually a 'ExternalIterator'");
  130. return static_cast<CustomExternalIterator *>(RecyclableObject::FromVar(aValue));
  131. }
  132. Var CustomExternalIterator::CreateNextFunction(JavascriptLibrary *library, JavascriptTypeId typeId)
  133. {
  134. return JavascriptExternalIteratorNextFunction::CreateFunction(library, typeId, CustomExternalIterator::EntryNext);
  135. }
  136. Var CustomExternalIterator::EntryNext(RecyclableObject* function, CallInfo callInfo, ...)
  137. {
  138. PROBE_STACK(function->GetScriptContext(), Js::Constants::MinStackDefault);
  139. ARGUMENTS(args, callInfo);
  140. ScriptContext* scriptContext = function->GetScriptContext();
  141. if (args.Info.Flags & CallFlags_New)
  142. {
  143. JavascriptError::ThrowTypeError(scriptContext, JSERR_ErrorOnNew);
  144. }
  145. JavascriptExternalIteratorNextFunction* iteratorNextFunction = static_cast<JavascriptExternalIteratorNextFunction*>(function);
  146. Var thisObj = args[0];
  147. if (!CustomExternalIterator::Is(thisObj))
  148. {
  149. JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidIteratorObject, _u("Iterator.prototype.next"));
  150. }
  151. CustomExternalIterator * currentIterator = CustomExternalIterator::FromVar(thisObj);
  152. if (iteratorNextFunction->GetExternalTypeId() != currentIterator->m_externalTypeId)
  153. {
  154. JavascriptError::ThrowTypeError(scriptContext, JSERR_InvalidIteratorObject, _u("Iterator.prototype.next"));
  155. }
  156. Var key = nullptr;
  157. Var value = nullptr;
  158. JavascriptLibrary* library = scriptContext->GetLibrary();
  159. if (currentIterator->m_nextFunction == nullptr)
  160. {
  161. return library->CreateIteratorResultObjectUndefinedTrue();
  162. }
  163. bool ret = false;
  164. BEGIN_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext)
  165. {
  166. ret = currentIterator->m_nextFunction(currentIterator, &key, &value);
  167. }
  168. END_LEAVE_SCRIPT_WITH_EXCEPTION(scriptContext);
  169. if (!ret)
  170. {
  171. return library->CreateIteratorResultObjectUndefinedTrue();
  172. }
  173. Var result;
  174. if (currentIterator->m_kind == ExternalIteratorKind::External_KeyAndValue)
  175. {
  176. JavascriptArray* keyValueTuple = library->CreateArray(2);
  177. keyValueTuple->SetItem(0, key, PropertyOperation_None);
  178. keyValueTuple->SetItem(1, value, PropertyOperation_None);
  179. result = keyValueTuple;
  180. }
  181. else if (currentIterator->m_kind == ExternalIteratorKind::External_Keys)
  182. {
  183. result = key;
  184. }
  185. else
  186. {
  187. Assert(currentIterator->m_kind == ExternalIteratorKind::External_Values);
  188. result = value;
  189. }
  190. return library->CreateIteratorResultObjectValueFalse(result);
  191. }
  192. }