1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 /* Same-thread compilation and evaluation APIs. */
8
9 #include "js/CompilationAndEvaluation.h"
10
11 #include "mozilla/Maybe.h" // mozilla::None, mozilla::Some
12 #include "mozilla/TextUtils.h" // mozilla::IsAscii
13 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
14
15 #include <utility> // std::move
16
17 #include "jsapi.h" // JS_WrapValue
18 #include "jstypes.h" // JS_PUBLIC_API
19
20 #include "frontend/BytecodeCompilation.h" // frontend::CompileGlobalScript
21 #include "frontend/CompilationStencil.h" // for frontened::{CompilationStencil, BorrowingCompilationStencil, CompilationGCOutput}
22 #include "frontend/Parser.h" // frontend::Parser, frontend::ParseGoal
23 #include "js/CharacterEncoding.h" // JS::UTF8Chars, JS::UTF8CharsToNewTwoByteCharsZ
24 #include "js/experimental/JSStencil.h" // JS::Stencil
25 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
26 #include "js/RootingAPI.h" // JS::Rooted
27 #include "js/SourceText.h" // JS::SourceText
28 #include "js/TypeDecls.h" // JS::HandleObject, JS::MutableHandleScript
29 #include "js/Utility.h" // js::MallocArena, JS::UniqueTwoByteChars
30 #include "js/Value.h" // JS::Value
31 #include "util/CompleteFile.h" // js::FileContents, js::ReadCompleteFile
32 #include "util/StringBuffer.h" // js::StringBuffer
33 #include "vm/EnvironmentObject.h" // js::CreateNonSyntacticEnvironmentChain
34 #include "vm/FunctionFlags.h" // js::FunctionFlags
35 #include "vm/Interpreter.h" // js::Execute
36 #include "vm/JSContext.h" // JSContext
37
38 #include "debugger/DebugAPI-inl.h" // js::DebugAPI
39 #include "vm/JSContext-inl.h" // JSContext::check
40
41 using mozilla::Utf8Unit;
42
43 using JS::CompileOptions;
44 using JS::HandleObject;
45 using JS::ReadOnlyCompileOptions;
46 using JS::SourceOwnership;
47 using JS::SourceText;
48 using JS::UniqueTwoByteChars;
49 using JS::UTF8Chars;
50 using JS::UTF8CharsToNewTwoByteCharsZ;
51
52 using namespace js;
53
ReportSourceTooLong(JSContext * cx)54 JS_PUBLIC_API void JS::detail::ReportSourceTooLong(JSContext* cx) {
55 JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
56 JSMSG_SOURCE_TOO_LONG);
57 }
58
59 template <typename Unit>
CompileSourceBuffer(JSContext * cx,const ReadOnlyCompileOptions & options,SourceText<Unit> & srcBuf)60 static JSScript* CompileSourceBuffer(JSContext* cx,
61 const ReadOnlyCompileOptions& options,
62 SourceText<Unit>& srcBuf) {
63 ScopeKind scopeKind =
64 options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
65
66 MOZ_ASSERT(!cx->zone()->isAtomsZone());
67 AssertHeapIsIdle();
68 CHECK_THREAD(cx);
69
70 return frontend::CompileGlobalScript(cx, options, srcBuf, scopeKind);
71 }
72
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,SourceText<char16_t> & srcBuf)73 JSScript* JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
74 SourceText<char16_t>& srcBuf) {
75 return CompileSourceBuffer(cx, options, srcBuf);
76 }
77
Compile(JSContext * cx,const ReadOnlyCompileOptions & options,SourceText<Utf8Unit> & srcBuf)78 JSScript* JS::Compile(JSContext* cx, const ReadOnlyCompileOptions& options,
79 SourceText<Utf8Unit>& srcBuf) {
80 return CompileSourceBuffer(cx, options, srcBuf);
81 }
82
83 template <typename Unit>
CompileSourceBufferAndStartIncrementalEncoding(JSContext * cx,const ReadOnlyCompileOptions & options,SourceText<Unit> & srcBuf)84 static JSScript* CompileSourceBufferAndStartIncrementalEncoding(
85 JSContext* cx, const ReadOnlyCompileOptions& options,
86 SourceText<Unit>& srcBuf) {
87 MOZ_ASSERT(!cx->zone()->isAtomsZone());
88 AssertHeapIsIdle();
89 CHECK_THREAD(cx);
90
91 ScopeKind scopeKind =
92 options.nonSyntacticScope ? ScopeKind::NonSyntactic : ScopeKind::Global;
93
94 Rooted<frontend::CompilationInput> input(cx,
95 frontend::CompilationInput(options));
96 auto stencil = frontend::CompileGlobalScriptToExtensibleStencil(
97 cx, input.get(), srcBuf, scopeKind);
98 if (!stencil) {
99 return nullptr;
100 }
101
102 RootedScript script(cx);
103 {
104 frontend::BorrowingCompilationStencil borrowingStencil(*stencil);
105
106 Rooted<frontend::CompilationGCOutput> gcOutput(cx);
107 if (!frontend::InstantiateStencils(cx, input.get(), borrowingStencil,
108 gcOutput.get())) {
109 return nullptr;
110 }
111
112 script = gcOutput.get().script;
113 if (!script) {
114 return nullptr;
115 }
116 }
117
118 if (!script->scriptSource()->startIncrementalEncoding(cx,
119 std::move(stencil))) {
120 return nullptr;
121 }
122
123 return script;
124 }
125
CompileAndStartIncrementalEncoding(JSContext * cx,const ReadOnlyCompileOptions & options,SourceText<char16_t> & srcBuf)126 JSScript* JS::CompileAndStartIncrementalEncoding(
127 JSContext* cx, const ReadOnlyCompileOptions& options,
128 SourceText<char16_t>& srcBuf) {
129 return CompileSourceBufferAndStartIncrementalEncoding(cx, options, srcBuf);
130 }
131
CompileAndStartIncrementalEncoding(JSContext * cx,const ReadOnlyCompileOptions & options,SourceText<Utf8Unit> & srcBuf)132 JSScript* JS::CompileAndStartIncrementalEncoding(
133 JSContext* cx, const ReadOnlyCompileOptions& options,
134 SourceText<Utf8Unit>& srcBuf) {
135 return CompileSourceBufferAndStartIncrementalEncoding(cx, options, srcBuf);
136 }
137
StartIncrementalEncoding(JSContext * cx,RefPtr<JS::Stencil> && stencil)138 JS_PUBLIC_API bool JS::StartIncrementalEncoding(JSContext* cx,
139 RefPtr<JS::Stencil>&& stencil) {
140 MOZ_ASSERT(cx);
141 MOZ_ASSERT(!stencil->hasMultipleReference());
142
143 auto* source = stencil->source.get();
144
145 UniquePtr<frontend::ExtensibleCompilationStencil> initial;
146 if (stencil->hasOwnedBorrow()) {
147 initial.reset(stencil->takeOwnedBorrow());
148 stencil = nullptr;
149 } else {
150 initial = cx->make_unique<frontend::ExtensibleCompilationStencil>(
151 cx, stencil->source);
152 if (!initial) {
153 return false;
154 }
155
156 if (!initial->steal(cx, std::move(stencil))) {
157 return false;
158 }
159 }
160
161 return source->startIncrementalEncoding(cx, std::move(initial));
162 }
163
CompileUtf8File(JSContext * cx,const ReadOnlyCompileOptions & options,FILE * file)164 JSScript* JS::CompileUtf8File(JSContext* cx,
165 const ReadOnlyCompileOptions& options,
166 FILE* file) {
167 FileContents buffer(cx);
168 if (!ReadCompleteFile(cx, file, buffer)) {
169 return nullptr;
170 }
171
172 SourceText<Utf8Unit> srcBuf;
173 if (!srcBuf.init(cx, reinterpret_cast<const char*>(buffer.begin()),
174 buffer.length(), SourceOwnership::Borrowed)) {
175 return nullptr;
176 }
177
178 return CompileSourceBuffer(cx, options, srcBuf);
179 }
180
CompileUtf8Path(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char * filename)181 JSScript* JS::CompileUtf8Path(JSContext* cx,
182 const ReadOnlyCompileOptions& optionsArg,
183 const char* filename) {
184 AutoFile file;
185 if (!file.open(cx, filename)) {
186 return nullptr;
187 }
188
189 CompileOptions options(cx, optionsArg);
190 options.setFileAndLine(filename, 1);
191 return CompileUtf8File(cx, options, file.fp());
192 }
193
JS_Utf8BufferIsCompilableUnit(JSContext * cx,HandleObject obj,const char * utf8,size_t length)194 JS_PUBLIC_API bool JS_Utf8BufferIsCompilableUnit(JSContext* cx,
195 HandleObject obj,
196 const char* utf8,
197 size_t length) {
198 AssertHeapIsIdle();
199 CHECK_THREAD(cx);
200 cx->check(obj);
201
202 cx->clearPendingException();
203
204 JS::UniqueTwoByteChars chars{
205 UTF8CharsToNewTwoByteCharsZ(cx, UTF8Chars(utf8, length), &length,
206 js::MallocArena)
207 .get()};
208 if (!chars) {
209 return true;
210 }
211
212 // Return true on any out-of-memory error or non-EOF-related syntax error, so
213 // our caller doesn't try to collect more buffered source.
214 bool result = true;
215
216 using frontend::FullParseHandler;
217 using frontend::ParseGoal;
218 using frontend::Parser;
219
220 CompileOptions options(cx);
221 Rooted<frontend::CompilationInput> input(cx,
222 frontend::CompilationInput(options));
223 if (!input.get().initForGlobal(cx)) {
224 return false;
225 }
226
227 LifoAllocScope allocScope(&cx->tempLifoAlloc());
228 frontend::CompilationState compilationState(cx, allocScope, input.get());
229 if (!compilationState.init(cx)) {
230 return false;
231 }
232
233 JS::AutoSuppressWarningReporter suppressWarnings(cx);
234 Parser<FullParseHandler, char16_t> parser(cx, options, chars.get(), length,
235 /* foldConstants = */ true,
236 compilationState,
237 /* syntaxParser = */ nullptr);
238 if (!parser.checkOptions() || !parser.parse()) {
239 // We ran into an error. If it was because we ran out of source, we
240 // return false so our caller knows to try to collect more buffered
241 // source.
242 if (parser.isUnexpectedEOF()) {
243 result = false;
244 }
245
246 cx->clearPendingException();
247 }
248
249 return result;
250 }
251
252 class FunctionCompiler {
253 private:
254 JSContext* const cx_;
255 RootedAtom nameAtom_;
256 StringBuffer funStr_;
257
258 uint32_t parameterListEnd_ = 0;
259 bool nameIsIdentifier_ = true;
260
261 public:
FunctionCompiler(JSContext * cx)262 explicit FunctionCompiler(JSContext* cx)
263 : cx_(cx), nameAtom_(cx), funStr_(cx) {
264 AssertHeapIsIdle();
265 CHECK_THREAD(cx);
266 MOZ_ASSERT(!cx->zone()->isAtomsZone());
267 }
268
init(const char * name,unsigned nargs,const char * const * argnames)269 [[nodiscard]] bool init(const char* name, unsigned nargs,
270 const char* const* argnames) {
271 if (!funStr_.ensureTwoByteChars()) {
272 return false;
273 }
274 if (!funStr_.append("function ")) {
275 return false;
276 }
277
278 if (name) {
279 size_t nameLen = strlen(name);
280
281 nameAtom_ = Atomize(cx_, name, nameLen);
282 if (!nameAtom_) {
283 return false;
284 }
285
286 // If the name is an identifier, we can just add it to source text.
287 // Otherwise we'll have to set it manually later.
288 nameIsIdentifier_ = js::frontend::IsIdentifier(
289 reinterpret_cast<const Latin1Char*>(name), nameLen);
290 if (nameIsIdentifier_) {
291 if (!funStr_.append(nameAtom_)) {
292 return false;
293 }
294 }
295 }
296
297 if (!funStr_.append("(")) {
298 return false;
299 }
300
301 for (unsigned i = 0; i < nargs; i++) {
302 if (i != 0) {
303 if (!funStr_.append(", ")) {
304 return false;
305 }
306 }
307 if (!funStr_.append(argnames[i], strlen(argnames[i]))) {
308 return false;
309 }
310 }
311
312 // Remember the position of ")".
313 parameterListEnd_ = funStr_.length();
314 MOZ_ASSERT(FunctionConstructorMedialSigils[0] == ')');
315
316 return funStr_.append(FunctionConstructorMedialSigils);
317 }
318
319 template <typename Unit>
addFunctionBody(const SourceText<Unit> & srcBuf)320 [[nodiscard]] inline bool addFunctionBody(const SourceText<Unit>& srcBuf) {
321 return funStr_.append(srcBuf.get(), srcBuf.length());
322 }
323
finish(HandleObjectVector envChain,const ReadOnlyCompileOptions & optionsArg)324 JSFunction* finish(HandleObjectVector envChain,
325 const ReadOnlyCompileOptions& optionsArg) {
326 using js::frontend::FunctionSyntaxKind;
327
328 if (!funStr_.append(FunctionConstructorFinalBrace)) {
329 return nullptr;
330 }
331
332 size_t newLen = funStr_.length();
333 UniqueTwoByteChars stolen(funStr_.stealChars());
334 if (!stolen) {
335 return nullptr;
336 }
337
338 SourceText<char16_t> newSrcBuf;
339 if (!newSrcBuf.init(cx_, std::move(stolen), newLen)) {
340 return nullptr;
341 }
342
343 RootedObject enclosingEnv(cx_);
344 ScopeKind kind;
345 if (envChain.empty()) {
346 // A compiled function has a burned-in environment chain, so if no exotic
347 // environment was requested, we can use the global lexical environment
348 // directly and not need to worry about any potential non-syntactic scope.
349 enclosingEnv.set(&cx_->global()->lexicalEnvironment());
350 kind = ScopeKind::Global;
351 } else {
352 if (!CreateNonSyntacticEnvironmentChain(cx_, envChain, &enclosingEnv)) {
353 return nullptr;
354 }
355 kind = ScopeKind::NonSyntactic;
356 }
357
358 cx_->check(enclosingEnv);
359
360 // Make sure the static scope chain matches up when we have a
361 // non-syntactic scope.
362 MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(enclosingEnv),
363 kind == ScopeKind::NonSyntactic);
364
365 CompileOptions options(cx_, optionsArg);
366 options.setNonSyntacticScope(kind == ScopeKind::NonSyntactic);
367
368 FunctionSyntaxKind syntaxKind = FunctionSyntaxKind::Statement;
369 RootedFunction fun(cx_);
370 if (kind == ScopeKind::NonSyntactic) {
371 RootedScope enclosingScope(
372 cx_, GlobalScope::createEmpty(cx_, ScopeKind::NonSyntactic));
373 if (!enclosingScope) {
374 return nullptr;
375 }
376
377 fun = js::frontend::CompileStandaloneFunctionInNonSyntacticScope(
378 cx_, options, newSrcBuf, mozilla::Some(parameterListEnd_), syntaxKind,
379 enclosingScope);
380 } else {
381 fun = js::frontend::CompileStandaloneFunction(
382 cx_, options, newSrcBuf, mozilla::Some(parameterListEnd_),
383 syntaxKind);
384 }
385 if (!fun) {
386 return nullptr;
387 }
388
389 // When the function name isn't a valid identifier, the generated function
390 // source in srcBuf won't include the name, so name the function manually.
391 if (!nameIsIdentifier_) {
392 fun->setAtom(nameAtom_);
393 }
394
395 if (fun->isInterpreted()) {
396 fun->initEnvironment(enclosingEnv);
397 }
398
399 return fun;
400 }
401 };
402
CompileFunction(JSContext * cx,HandleObjectVector envChain,const ReadOnlyCompileOptions & options,const char * name,unsigned nargs,const char * const * argnames,SourceText<char16_t> & srcBuf)403 JS_PUBLIC_API JSFunction* JS::CompileFunction(
404 JSContext* cx, HandleObjectVector envChain,
405 const ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
406 const char* const* argnames, SourceText<char16_t>& srcBuf) {
407 FunctionCompiler compiler(cx);
408 if (!compiler.init(name, nargs, argnames) ||
409 !compiler.addFunctionBody(srcBuf)) {
410 return nullptr;
411 }
412
413 return compiler.finish(envChain, options);
414 }
415
CompileFunction(JSContext * cx,HandleObjectVector envChain,const ReadOnlyCompileOptions & options,const char * name,unsigned nargs,const char * const * argnames,SourceText<Utf8Unit> & srcBuf)416 JS_PUBLIC_API JSFunction* JS::CompileFunction(
417 JSContext* cx, HandleObjectVector envChain,
418 const ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
419 const char* const* argnames, SourceText<Utf8Unit>& srcBuf) {
420 FunctionCompiler compiler(cx);
421 if (!compiler.init(name, nargs, argnames) ||
422 !compiler.addFunctionBody(srcBuf)) {
423 return nullptr;
424 }
425
426 return compiler.finish(envChain, options);
427 }
428
CompileFunctionUtf8(JSContext * cx,HandleObjectVector envChain,const ReadOnlyCompileOptions & options,const char * name,unsigned nargs,const char * const * argnames,const char * bytes,size_t length)429 JS_PUBLIC_API JSFunction* JS::CompileFunctionUtf8(
430 JSContext* cx, HandleObjectVector envChain,
431 const ReadOnlyCompileOptions& options, const char* name, unsigned nargs,
432 const char* const* argnames, const char* bytes, size_t length) {
433 SourceText<Utf8Unit> srcBuf;
434 if (!srcBuf.init(cx, bytes, length, SourceOwnership::Borrowed)) {
435 return nullptr;
436 }
437
438 return CompileFunction(cx, envChain, options, name, nargs, argnames, srcBuf);
439 }
440
ExposeScriptToDebugger(JSContext * cx,HandleScript script)441 JS_PUBLIC_API void JS::ExposeScriptToDebugger(JSContext* cx,
442 HandleScript script) {
443 MOZ_ASSERT(cx);
444 MOZ_ASSERT(CurrentThreadCanAccessRuntime(cx->runtime()));
445
446 DebugAPI::onNewScript(cx, script);
447 }
448
UpdateDebugMetadata(JSContext * cx,Handle<JSScript * > script,const InstantiateOptions & options,HandleValue privateValue,HandleString elementAttributeName,HandleScript introScript,HandleScript scriptOrModule)449 JS_PUBLIC_API bool JS::UpdateDebugMetadata(
450 JSContext* cx, Handle<JSScript*> script, const InstantiateOptions& options,
451 HandleValue privateValue, HandleString elementAttributeName,
452 HandleScript introScript, HandleScript scriptOrModule) {
453 RootedScriptSourceObject sso(cx, script->sourceObject());
454
455 if (!ScriptSourceObject::initElementProperties(cx, sso,
456 elementAttributeName)) {
457 return false;
458 }
459
460 // There is no equivalent of cross-compartment wrappers for scripts. If the
461 // introduction script and ScriptSourceObject are in different compartments,
462 // we would be creating a cross-compartment script reference, which is
463 // forbidden. We can still store a CCW to the script source object though.
464 RootedValue introductionScript(cx);
465 if (introScript) {
466 if (introScript->compartment() == cx->compartment()) {
467 introductionScript.setPrivateGCThing(introScript);
468 }
469 }
470 sso->setIntroductionScript(introductionScript);
471
472 RootedValue privateValueStore(cx, UndefinedValue());
473 if (privateValue.isUndefined()) {
474 // Set the private value to that of the script or module that this source is
475 // part of, if any.
476 if (scriptOrModule) {
477 privateValueStore = scriptOrModule->sourceObject()->getPrivate();
478 }
479 } else {
480 privateValueStore = privateValue;
481 }
482
483 if (!privateValueStore.isUndefined()) {
484 if (!JS_WrapValue(cx, &privateValueStore)) {
485 return false;
486 }
487 }
488 sso->setPrivate(cx->runtime(), privateValueStore);
489
490 if (!options.hideScriptFromDebugger) {
491 JS::ExposeScriptToDebugger(cx, script);
492 }
493
494 return true;
495 }
496
SetSourceElementCallback(JSContext * cx,JSSourceElementCallback callback)497 JS_PUBLIC_API void JS::SetSourceElementCallback(
498 JSContext* cx, JSSourceElementCallback callback) {
499 MOZ_ASSERT(cx->runtime());
500 cx->runtime()->setSourceElementCallback(cx->runtime(), callback);
501 }
502
ExecuteScript(JSContext * cx,HandleObject envChain,HandleScript script,MutableHandleValue rval)503 MOZ_NEVER_INLINE static bool ExecuteScript(JSContext* cx, HandleObject envChain,
504 HandleScript script,
505 MutableHandleValue rval) {
506 MOZ_ASSERT(!cx->zone()->isAtomsZone());
507 AssertHeapIsIdle();
508 CHECK_THREAD(cx);
509 cx->check(envChain, script);
510
511 if (!IsGlobalLexicalEnvironment(envChain)) {
512 MOZ_RELEASE_ASSERT(script->hasNonSyntacticScope());
513 }
514
515 return Execute(cx, script, envChain, rval);
516 }
517
ExecuteScript(JSContext * cx,HandleObjectVector envChain,HandleScript script,MutableHandleValue rval)518 static bool ExecuteScript(JSContext* cx, HandleObjectVector envChain,
519 HandleScript script, MutableHandleValue rval) {
520 RootedObject env(cx);
521 if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env)) {
522 return false;
523 }
524
525 return ExecuteScript(cx, env, script, rval);
526 }
527
JS_ExecuteScript(JSContext * cx,HandleScript scriptArg,MutableHandleValue rval)528 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
529 HandleScript scriptArg,
530 MutableHandleValue rval) {
531 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
532 return ExecuteScript(cx, globalLexical, scriptArg, rval);
533 }
534
JS_ExecuteScript(JSContext * cx,HandleScript scriptArg)535 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(JSContext* cx,
536 HandleScript scriptArg) {
537 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
538 RootedValue rval(cx);
539 return ExecuteScript(cx, globalLexical, scriptArg, &rval);
540 }
541
JS_ExecuteScript(JSContext * cx,HandleObjectVector envChain,HandleScript scriptArg,MutableHandleValue rval)542 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(
543 JSContext* cx, HandleObjectVector envChain, HandleScript scriptArg,
544 MutableHandleValue rval) {
545 return ExecuteScript(cx, envChain, scriptArg, rval);
546 }
547
JS_ExecuteScript(JSContext * cx,HandleObjectVector envChain,HandleScript scriptArg)548 MOZ_NEVER_INLINE JS_PUBLIC_API bool JS_ExecuteScript(
549 JSContext* cx, HandleObjectVector envChain, HandleScript scriptArg) {
550 RootedValue rval(cx);
551 return ExecuteScript(cx, envChain, scriptArg, &rval);
552 }
553
554 template <typename Unit>
EvaluateSourceBuffer(JSContext * cx,ScopeKind scopeKind,Handle<JSObject * > env,const ReadOnlyCompileOptions & optionsArg,SourceText<Unit> & srcBuf,MutableHandle<Value> rval)555 static bool EvaluateSourceBuffer(JSContext* cx, ScopeKind scopeKind,
556 Handle<JSObject*> env,
557 const ReadOnlyCompileOptions& optionsArg,
558 SourceText<Unit>& srcBuf,
559 MutableHandle<Value> rval) {
560 CompileOptions options(cx, optionsArg);
561 MOZ_ASSERT(!cx->zone()->isAtomsZone());
562 AssertHeapIsIdle();
563 CHECK_THREAD(cx);
564 cx->check(env);
565 MOZ_ASSERT_IF(!IsGlobalLexicalEnvironment(env),
566 scopeKind == ScopeKind::NonSyntactic);
567
568 options.setNonSyntacticScope(scopeKind == ScopeKind::NonSyntactic);
569 options.setIsRunOnce(true);
570
571 RootedScript script(
572 cx, frontend::CompileGlobalScript(cx, options, srcBuf, scopeKind));
573 if (!script) {
574 return false;
575 }
576
577 return Execute(cx, script, env, rval);
578 }
579
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & options,SourceText<Utf8Unit> & srcBuf,MutableHandle<Value> rval)580 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx,
581 const ReadOnlyCompileOptions& options,
582 SourceText<Utf8Unit>& srcBuf,
583 MutableHandle<Value> rval) {
584 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
585 return EvaluateSourceBuffer(cx, ScopeKind::Global, globalLexical, options,
586 srcBuf, rval);
587 }
588
Evaluate(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,SourceText<char16_t> & srcBuf,MutableHandleValue rval)589 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx,
590 const ReadOnlyCompileOptions& optionsArg,
591 SourceText<char16_t>& srcBuf,
592 MutableHandleValue rval) {
593 RootedObject globalLexical(cx, &cx->global()->lexicalEnvironment());
594 return EvaluateSourceBuffer(cx, ScopeKind::Global, globalLexical, optionsArg,
595 srcBuf, rval);
596 }
597
Evaluate(JSContext * cx,HandleObjectVector envChain,const ReadOnlyCompileOptions & options,SourceText<char16_t> & srcBuf,MutableHandleValue rval)598 JS_PUBLIC_API bool JS::Evaluate(JSContext* cx, HandleObjectVector envChain,
599 const ReadOnlyCompileOptions& options,
600 SourceText<char16_t>& srcBuf,
601 MutableHandleValue rval) {
602 RootedObject env(cx);
603 if (!CreateNonSyntacticEnvironmentChain(cx, envChain, &env)) {
604 return false;
605 }
606
607 return EvaluateSourceBuffer(cx, ScopeKind::NonSyntactic, env, options, srcBuf,
608 rval);
609 }
610
EvaluateUtf8Path(JSContext * cx,const ReadOnlyCompileOptions & optionsArg,const char * filename,MutableHandleValue rval)611 JS_PUBLIC_API bool JS::EvaluateUtf8Path(
612 JSContext* cx, const ReadOnlyCompileOptions& optionsArg,
613 const char* filename, MutableHandleValue rval) {
614 FileContents buffer(cx);
615 {
616 AutoFile file;
617 if (!file.open(cx, filename) || !file.readAll(cx, buffer)) {
618 return false;
619 }
620 }
621
622 CompileOptions options(cx, optionsArg);
623 options.setFileAndLine(filename, 1);
624
625 auto contents = reinterpret_cast<const char*>(buffer.begin());
626 size_t length = buffer.length();
627
628 JS::SourceText<Utf8Unit> srcBuf;
629 if (!srcBuf.init(cx, contents, length, JS::SourceOwnership::Borrowed)) {
630 return false;
631 }
632
633 return Evaluate(cx, options, srcBuf, rval);
634 }
635