#include "config.h"
#include "APICast.h"
#include "JSCInlines.h"
#include "CodeCache.h"
#include "CachedTypes.h"
#include "CachedBytecode.h"
#include "Completion.h"
#include "SourceCode.h"
#include "SourceProvider.h"
#include "Parser.h"
#include "JSGlobalObject.h"
#include "Identifier.h"
#include "Exception.h"
#include <wtf/MallocSpan.h>
#include <wtf/NakedPtr.h>
#include <wtf/text/WTFString.h>
#include <cstdlib>
#include <cstring>
using namespace JSC;
namespace {
class CachedSourceProvider final : public StringSourceProvider {
public:
static Ref<CachedSourceProvider> create(const String& source,
const SourceOrigin& origin, String url, SourceTaintedOrigin taint,
SourceProviderSourceType type, RefPtr<CachedBytecode>&& bc)
{
return adoptRef(*new CachedSourceProvider(source, origin,
std::move(url), taint, type, std::move(bc)));
}
RefPtr<CachedBytecode> cachedBytecode() const final { return m_cached; }
private:
CachedSourceProvider(const String& source, const SourceOrigin& origin,
String&& url, SourceTaintedOrigin taint, SourceProviderSourceType type,
RefPtr<CachedBytecode>&& bc)
: StringSourceProvider(source, origin, taint, std::move(url),
TextPosition(), type)
, m_cached(std::move(bc))
{
}
RefPtr<CachedBytecode> m_cached;
};
}
extern "C" {
uint8_t* v82jsc_bytecode_encode(JSContextRef ctxRef, const char* url,
const char* src, int is_module, size_t* outLen)
{
if (outLen)
*outLen = 0;
JSGlobalObject* globalObject = toJS(ctxRef);
VM& vm = globalObject->vm();
JSLockHolder locker(vm);
String urlStr = String::fromUTF8(url);
SourceOrigin sourceOrigin { URL { urlStr } };
SourceCode sourceCode = makeSource(String::fromUTF8(src), sourceOrigin,
SourceTaintedOrigin::Untainted, urlStr);
ParserError error;
RefPtr<CachedBytecode> cached;
if (is_module) {
UnlinkedModuleProgramCodeBlock* ucb =
recursivelyGenerateUnlinkedCodeBlockForModuleProgram(vm, sourceCode,
StrictModeLexicallyScopedFeature, JSParserScriptMode::Module,
{ }, error, EvalContextType::None);
if (error.isValid() || !ucb)
return nullptr;
SourceCodeKey key = sourceCodeKeyForSerializedModule(vm, sourceCode);
cached = encodeCodeBlock(vm, key, ucb);
} else {
UnlinkedProgramCodeBlock* ucb =
recursivelyGenerateUnlinkedCodeBlockForProgram(vm, sourceCode,
NoLexicallyScopedFeatures, JSParserScriptMode::Classic,
{ }, error, EvalContextType::None);
if (error.isValid() || !ucb)
return nullptr;
SourceCodeKey key = sourceCodeKeyForSerializedProgram(vm, sourceCode);
cached = encodeCodeBlock(vm, key, ucb);
}
if (!cached)
return nullptr;
std::span<const uint8_t> bytes = cached->span();
uint8_t* out = static_cast<uint8_t*>(malloc(bytes.size()));
if (!out)
return nullptr;
memcpy(out, bytes.data(), bytes.size());
if (outLen)
*outLen = bytes.size();
return out;
}
void v82jsc_bytecode_free(uint8_t* p)
{
free(p);
}
JSValueRef v82jsc_program_eval_cached(JSContextRef ctxRef, const char* url,
const char* src, const uint8_t* bytecode, size_t bytecodeLen,
JSValueRef* excOut)
{
JSGlobalObject* globalObject = toJS(ctxRef);
VM& vm = globalObject->vm();
JSLockHolder locker(vm);
RefPtr<CachedBytecode> cached;
if (bytecode && bytecodeLen) {
auto buf = MallocSpan<uint8_t, VMMalloc>::malloc(bytecodeLen);
memcpy(buf.mutableSpan().data(), bytecode, bytecodeLen);
cached = CachedBytecode::create(std::move(buf), { });
}
String urlStr = String::fromUTF8(url);
SourceOrigin sourceOrigin { URL { urlStr } };
Ref<CachedSourceProvider> provider = CachedSourceProvider::create(
String::fromUTF8(src), sourceOrigin, urlStr,
SourceTaintedOrigin::Untainted, SourceProviderSourceType::Program,
std::move(cached));
SourceCode sourceCode(std::move(provider));
NakedPtr<Exception> exception;
JSValue result = JSC::evaluate(globalObject, sourceCode, JSValue(), exception);
if (exception) {
if (excOut)
*excOut = toRef(globalObject, exception->value());
return nullptr;
}
return toRef(globalObject, result);
}
}