JavascriptExceptionMetadata.cpp 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  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. #include "JavascriptExceptionMetadata.h"
  7. namespace Js {
  8. SimplePropertyDescriptor const ExceptionMetadataPropertyDescriptors[6] =
  9. {
  10. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::exception), PropertyWritable),
  11. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::source), PropertyWritable),
  12. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::line), PropertyWritable),
  13. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::column), PropertyWritable),
  14. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::length), PropertyWritable),
  15. SimplePropertyDescriptor(NO_WRITE_BARRIER_TAG(BuiltInPropertyRecords::url), PropertyWritable)
  16. };
  17. SimpleTypeHandler<6> JavascriptExceptionMetadata::ExceptionMetadataTypeHandler(NO_WRITE_BARRIER_TAG(ExceptionMetadataPropertyDescriptors));
  18. Var JavascriptExceptionMetadata::CreateMetadataVar(ScriptContext * scriptContext) {
  19. DynamicType* exceptionMetadataType = DynamicType::New(scriptContext, TypeIds_Object,
  20. scriptContext->GetLibrary()->GetNull(), nullptr, &JavascriptExceptionMetadata::ExceptionMetadataTypeHandler, true, true);
  21. return DynamicObject::New(scriptContext->GetRecycler(), exceptionMetadataType);
  22. }
  23. void JavascriptExceptionMetadata::PopulateMetadataFromCompileException(Var metadata, Var exception, ScriptContext * scriptContext) {
  24. Js::Var var;
  25. var = Js::JavascriptOperators::ToNumber(
  26. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::line, scriptContext),
  27. scriptContext);
  28. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::line, var, scriptContext);
  29. var = Js::JavascriptOperators::ToNumber(
  30. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::column, scriptContext),
  31. scriptContext);
  32. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::column, var, scriptContext);
  33. var = Js::JavascriptOperators::ToNumber(
  34. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::length, scriptContext),
  35. scriptContext);
  36. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::length, var, scriptContext);
  37. var = Js::JavascriptConversion::ToString(
  38. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::source, scriptContext),
  39. scriptContext);
  40. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::source, var, scriptContext);
  41. var = Js::JavascriptConversion::ToString(
  42. Js::JavascriptOperators::OP_GetProperty(exception, Js::PropertyIds::url, scriptContext),
  43. scriptContext);
  44. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::url, var, scriptContext);
  45. }
  46. bool JavascriptExceptionMetadata::PopulateMetadataFromException(Var metadata, JavascriptExceptionObject * recordedException, ScriptContext * scriptContext) {
  47. uint32 offset = recordedException->GetByteCodeOffset();
  48. FunctionBody * functionBody = recordedException->GetFunctionBody();
  49. ULONG line;
  50. LONG column;
  51. if (functionBody->GetUtf8SourceInfo()->GetIsLibraryCode() ||
  52. !functionBody->GetLineCharOffset(offset, &line, &column)) {
  53. line = 0;
  54. column = 0;
  55. }
  56. Js::Utf8SourceInfo* sourceInfo = functionBody->GetUtf8SourceInfo();
  57. sourceInfo->EnsureLineOffsetCache();
  58. LineOffsetCache *cache = sourceInfo->GetLineOffsetCache();
  59. if (line >= cache->GetLineCount())
  60. {
  61. return false;
  62. }
  63. uint32 nextLine;
  64. if (UInt32Math::Add(line, 1, &nextLine))
  65. {
  66. // Overflowed
  67. return false;
  68. }
  69. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::line,
  70. Js::JavascriptNumber::New(line, scriptContext), scriptContext);
  71. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::column,
  72. Js::JavascriptNumber::New(column, scriptContext), scriptContext);
  73. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::length,
  74. Js::JavascriptNumber::New(0, scriptContext), scriptContext);
  75. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::url,
  76. Js::JavascriptString::NewCopySz(functionBody->GetSourceName(), scriptContext), scriptContext);
  77. LPCUTF8 functionSource = sourceInfo->GetSource(_u("Jsrt::JsExperimentalGetAndClearExceptionWithMetadata"));
  78. charcount_t startByteOffset = 0;
  79. charcount_t endByteOffset = 0;
  80. charcount_t startCharOffset = 0;
  81. charcount_t endCharOffset = 0;
  82. startCharOffset = cache->GetCharacterOffsetForLine(line, &startByteOffset);
  83. if (nextLine >= cache->GetLineCount())
  84. {
  85. endByteOffset = functionBody->LengthInBytes();
  86. endCharOffset = functionBody->LengthInChars();
  87. }
  88. else
  89. {
  90. endCharOffset = cache->GetCharacterOffsetForLine(nextLine, &endByteOffset);
  91. // The offsets above point to the start of the following line,
  92. // while we need to find the end of the current line.
  93. // To do so, just step back over the preceeding newline character(s)
  94. if (functionSource[endByteOffset - 1] == _u('\n'))
  95. {
  96. endCharOffset--;
  97. endByteOffset--;
  98. // This may have been \r\n
  99. if (endByteOffset > 0 && functionSource[endByteOffset - 1] == _u('\r'))
  100. {
  101. endCharOffset--;
  102. endByteOffset--;
  103. }
  104. }
  105. else
  106. {
  107. utf8::DecodeOptions options = utf8::doAllowThreeByteSurrogates;
  108. LPCUTF8 potentialNewlineStart = functionSource + endByteOffset - 3;
  109. char16 decodedCharacter = utf8::Decode(potentialNewlineStart, functionSource + endByteOffset, options);
  110. if (decodedCharacter == 0x2028 || decodedCharacter == 0x2029)
  111. {
  112. endCharOffset--;
  113. endByteOffset -= 3;
  114. }
  115. else if (functionSource[endByteOffset - 1] == _u('\r'))
  116. {
  117. endCharOffset--;
  118. endByteOffset--;
  119. }
  120. else
  121. {
  122. AssertMsg(FALSE, "Line ending logic out of sync between Js::JavascriptExceptionMetadata and Js::LineOffsetCache::GetCharacterOffsetForLine");
  123. return false;
  124. }
  125. }
  126. }
  127. LPCUTF8 functionStart = functionSource + startByteOffset;
  128. Js::BufferStringBuilder builder(endCharOffset - startCharOffset, scriptContext);
  129. utf8::DecodeOptions options = sourceInfo->IsCesu8() ? utf8::doAllowThreeByteSurrogates : utf8::doDefault;
  130. utf8::DecodeUnitsInto(builder.DangerousGetWritableBuffer(), functionStart, functionSource + endByteOffset, options);
  131. Js::JavascriptOperators::OP_SetProperty(metadata, Js::PropertyIds::source,
  132. builder.ToString(), scriptContext);
  133. return true;
  134. }
  135. }