summaryrefslogtreecommitdiffstats
path: root/js/public/Transcoding.h
blob: ca0828330a135d8c06032c42bab63864b2a5ef49 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */

/*
 * Structures and functions for transcoding compiled scripts and functions to
 * and from memory.
 */

#ifndef js_Transcoding_h
#define js_Transcoding_h

#include "mozilla/Range.h"   // mozilla::Range
#include "mozilla/Vector.h"  // mozilla::Vector

#include <stddef.h>  // size_t
#include <stdint.h>  // uint8_t, uint32_t

#include "js/TypeDecls.h"

namespace JS {

class JS_PUBLIC_API ReadOnlyCompileOptions;

using TranscodeBuffer = mozilla::Vector<uint8_t>;
using TranscodeRange = mozilla::Range<const uint8_t>;

struct TranscodeSource final {
  TranscodeSource(const TranscodeRange& range_, const char* file, uint32_t line)
      : range(range_), filename(file), lineno(line) {}

  const TranscodeRange range;
  const char* filename;
  const uint32_t lineno;
};

using TranscodeSources = mozilla::Vector<TranscodeSource>;

enum class TranscodeResult : uint8_t {
  // Successful encoding / decoding.
  Ok = 0,

  // A warning message, is set to the message out-param.
  Failure = 0x10,
  Failure_BadBuildId = Failure | 0x1,
  Failure_AsmJSNotSupported = Failure | 0x2,
  Failure_BadDecode = Failure | 0x3,

  // There is a pending exception on the context.
  Throw = 0x20
};

inline bool IsTranscodeFailureResult(const TranscodeResult result) {
  uint8_t raw_result = static_cast<uint8_t>(result);
  uint8_t raw_failure = static_cast<uint8_t>(TranscodeResult::Failure);
  TranscodeResult masked =
      static_cast<TranscodeResult>(raw_result & raw_failure);
  return masked == TranscodeResult::Failure;
}

static constexpr size_t BytecodeOffsetAlignment = 4;
static_assert(BytecodeOffsetAlignment <= alignof(std::max_align_t),
              "Alignment condition requires a custom allocator.");

// Align the bytecode offset for transcoding for the requirement.
inline size_t AlignTranscodingBytecodeOffset(size_t offset) {
  size_t extra = offset % BytecodeOffsetAlignment;
  if (extra == 0) {
    return offset;
  }
  size_t padding = BytecodeOffsetAlignment - extra;
  return offset + padding;
}

inline bool IsTranscodingBytecodeOffsetAligned(size_t offset) {
  return offset % BytecodeOffsetAlignment == 0;
}

inline bool IsTranscodingBytecodeAligned(const void* offset) {
  return IsTranscodingBytecodeOffsetAligned(size_t(offset));
}

// Finish incremental encoding started by JS::StartIncrementalEncoding.
//
//   * Regular script case
//     the |script| argument must be the top-level script returned from
//     |JS::InstantiateGlobalStencil| with the same stencil
//
//   * Module script case
//     the |script| argument must be the script returned by
//     |JS::GetModuleScript| called on the module returned by
//     |JS::InstantiateModuleStencil| with the same stencil
//
//     NOTE: |JS::GetModuleScript| doesn't work after evaluating the
//           module script.  For the case, use Handle<JSObject*> variant of
//           this function below.
//
// The |buffer| argument of |FinishIncrementalEncoding| is used for appending
// the encoded bytecode into the buffer. If any of these functions failed, the
// content of |buffer| would be undefined.
//
// |buffer| contains encoded CompilationStencil.
//
// If the `buffer` isn't empty, the start of the `buffer` should meet
// IsTranscodingBytecodeAligned, and the length should meet
// IsTranscodingBytecodeOffsetAligned.
//
// NOTE: As long as IsTranscodingBytecodeOffsetAligned is met, that means
//       there's JS::BytecodeOffsetAlignment+extra bytes in the buffer,
//       IsTranscodingBytecodeAligned should be guaranteed to meet by
//       malloc, used by MallocAllocPolicy in mozilla::Vector.
extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx,
                                                    Handle<JSScript*> script,
                                                    TranscodeBuffer& buffer);

// Similar to |JS::FinishIncrementalEncoding|, but receives module obect.
//
// The |module| argument must be the module returned by
// |JS::InstantiateModuleStencil| with the same stencil that's passed to
// |JS::StartIncrementalEncoding|.
extern JS_PUBLIC_API bool FinishIncrementalEncoding(JSContext* cx,
                                                    Handle<JSObject*> module,
                                                    TranscodeBuffer& buffer);

// Abort incremental encoding started by JS::StartIncrementalEncoding.
extern JS_PUBLIC_API void AbortIncrementalEncoding(Handle<JSScript*> script);
extern JS_PUBLIC_API void AbortIncrementalEncoding(Handle<JSObject*> module);

// Check if the compile options and script's flag matches.
//
// JS::DecodeScript* and JS::DecodeOffThreadScript internally check this.
//
// JS::DecodeMultiStencilsOffThread checks some options shared across multiple
// scripts. Caller is responsible for checking each script with this API when
// using the decoded script instead of compiling a new script wiht the given
// options.
extern JS_PUBLIC_API bool CheckCompileOptionsMatch(
    const ReadOnlyCompileOptions& options, JSScript* script);

}  // namespace JS

#endif /* js_Transcoding_h */