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