1/*
2 * Copyright (C) 2012-2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27
28#include "APICast.h"
29#include "Completion.h"
30#include "Exception.h"
31#include "JSBasePrivate.h"
32#include "VM.h"
33#include "JSScriptRefPrivate.h"
34#include "OpaqueJSString.h"
35#include "JSCInlines.h"
36#include "Parser.h"
37#include "SourceCode.h"
38#include "SourceProvider.h"
39
40using namespace JSC;
41
42struct OpaqueJSScript : public SourceProvider {
43public:
44 static WTF::Ref<OpaqueJSScript> create(VM& vm, const SourceOrigin& sourceOrigin, URL&& url, int startingLineNumber, const String& source)
45 {
46 return WTF::adoptRef(*new OpaqueJSScript(vm, sourceOrigin, WTFMove(url), startingLineNumber, source));
47 }
48
49 unsigned hash() const override
50 {
51 return m_source.get().hash();
52 }
53
54 StringView source() const override
55 {
56 return m_source.get();
57 }
58
59 VM& vm() const { return m_vm; }
60
61private:
62 OpaqueJSScript(VM& vm, const SourceOrigin& sourceOrigin, URL&& url, int startingLineNumber, const String& source)
63 : SourceProvider(sourceOrigin, WTFMove(url), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber()), SourceProviderSourceType::Program)
64 , m_vm(vm)
65 , m_source(source.isNull() ? *StringImpl::empty() : *source.impl())
66 {
67 }
68
69 virtual ~OpaqueJSScript() { }
70
71 VM& m_vm;
72 Ref<StringImpl> m_source;
73};
74
75static bool parseScript(VM& vm, const SourceCode& source, ParserError& error)
76{
77 return !!JSC::parse<JSC::ProgramNode>(
78 vm, source, Identifier(), JSParserBuiltinMode::NotBuiltin,
79 JSParserStrictMode::NotStrict, JSParserScriptMode::Classic, SourceParseMode::ProgramMode, SuperBinding::NotNeeded,
80 error);
81}
82
83extern "C" {
84
85JSScriptRef JSScriptCreateReferencingImmortalASCIIText(JSContextGroupRef contextGroup, JSStringRef url, int startingLineNumber, const char* source, size_t length, JSStringRef* errorMessage, int* errorLine)
86{
87 auto& vm = *toJS(contextGroup);
88 JSLockHolder locker(&vm);
89 for (size_t i = 0; i < length; i++) {
90 if (!isASCII(source[i]))
91 return 0;
92 }
93
94 startingLineNumber = std::max(1, startingLineNumber);
95
96 auto sourceURLString = url ? url->string() : String();
97 auto result = OpaqueJSScript::create(vm, SourceOrigin { sourceURLString }, URL({ }, sourceURLString), startingLineNumber, String(StringImpl::createFromLiteral(source, length)));
98
99 ParserError error;
100 if (!parseScript(vm, SourceCode(result.copyRef()), error)) {
101 if (errorMessage)
102 *errorMessage = OpaqueJSString::tryCreate(error.message()).leakRef();
103 if (errorLine)
104 *errorLine = error.line();
105 return nullptr;
106 }
107
108 return &result.leakRef();
109}
110
111JSScriptRef JSScriptCreateFromString(JSContextGroupRef contextGroup, JSStringRef url, int startingLineNumber, JSStringRef source, JSStringRef* errorMessage, int* errorLine)
112{
113 auto& vm = *toJS(contextGroup);
114 JSLockHolder locker(&vm);
115
116 startingLineNumber = std::max(1, startingLineNumber);
117
118 auto sourceURLString = url ? url->string() : String();
119 auto result = OpaqueJSScript::create(vm, SourceOrigin { sourceURLString }, URL({ }, sourceURLString), startingLineNumber, source->string());
120
121 ParserError error;
122 if (!parseScript(vm, SourceCode(result.copyRef()), error)) {
123 if (errorMessage)
124 *errorMessage = OpaqueJSString::tryCreate(error.message()).leakRef();
125 if (errorLine)
126 *errorLine = error.line();
127 return nullptr;
128 }
129
130 return &result.leakRef();
131}
132
133void JSScriptRetain(JSScriptRef script)
134{
135 JSLockHolder locker(&script->vm());
136 script->ref();
137}
138
139void JSScriptRelease(JSScriptRef script)
140{
141 JSLockHolder locker(&script->vm());
142 script->deref();
143}
144
145JSValueRef JSScriptEvaluate(JSContextRef context, JSScriptRef script, JSValueRef thisValueRef, JSValueRef* exception)
146{
147 JSGlobalObject* globalObject = toJS(context);
148 VM& vm = globalObject->vm();
149 JSLockHolder locker(vm);
150 if (&script->vm() != &vm) {
151 RELEASE_ASSERT_NOT_REACHED();
152 return 0;
153 }
154 NakedPtr<Exception> internalException;
155 JSValue thisValue = thisValueRef ? toJS(globalObject, thisValueRef) : jsUndefined();
156 JSValue result = evaluate(globalObject, SourceCode(*script), thisValue, internalException);
157 if (internalException) {
158 if (exception)
159 *exception = toRef(globalObject, internalException->value());
160 return 0;
161 }
162 ASSERT(result);
163 return toRef(globalObject, result);
164}
165
166}
167