/* * Tencent is pleased to support the open source community by making ScriptX available. * Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "../../src/Native.hpp" #include "../../src/Reference.h" #include "WasmEngine.h" namespace script { #define REF_IMPL_BASIC_FUNC(ValueType) \ Local::Local(const Local& copy) : val_(copy.val_) {} \ Local::Local(Local&& move) noexcept : val_(move.val_) { move.val_ = -1; } \ Local& Local::operator=(const Local& from) { \ Local(from).swap(*this); \ return *this; \ } \ Local& Local::operator=(Local&& move) noexcept { \ Local(std::move(move)).swap(*this); \ return *this; \ } \ void Local::swap(Local& rhs) noexcept { \ using std::swap; \ swap(val_, rhs.val_); \ } #define REF_IMPL_BASIC_EQUALS(ValueType) \ bool Local::operator==(const script::Local& other) const { \ return asValue() == other; \ } #define REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(ValueType) \ Local::Local(InternalLocalRef val) : val_(val) { \ if (val < 0) { \ throw Exception("create Local<" #ValueType "> with null reference"); \ } \ wasm_backend::currentEngine(); \ } \ Local::~Local() {} #define REF_IMPL_BASIC_DESCRIBE(ValueType) \ Local Local::describe() const { return asValue().describe(); } \ std::string Local::describeUtf8() const { return asValue().describeUtf8(); } #define REF_IMPL_TO_VALUE(ValueType) \ Local Local::asValue() const { return Local(val_); } REF_IMPL_BASIC_FUNC(Value) REF_IMPL_BASIC_FUNC(Object) REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(Object) REF_IMPL_BASIC_DESCRIBE(Object) REF_IMPL_BASIC_EQUALS(Object) REF_IMPL_TO_VALUE(Object) REF_IMPL_BASIC_FUNC(String) REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(String) REF_IMPL_BASIC_DESCRIBE(String) REF_IMPL_BASIC_EQUALS(String) REF_IMPL_TO_VALUE(String) REF_IMPL_BASIC_FUNC(Number) REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(Number) REF_IMPL_BASIC_DESCRIBE(Number) REF_IMPL_BASIC_EQUALS(Number) REF_IMPL_TO_VALUE(Number) REF_IMPL_BASIC_FUNC(Boolean) REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(Boolean) REF_IMPL_BASIC_DESCRIBE(Boolean) REF_IMPL_BASIC_EQUALS(Boolean) REF_IMPL_TO_VALUE(Boolean) REF_IMPL_BASIC_FUNC(Function) REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(Function) REF_IMPL_BASIC_DESCRIBE(Function) REF_IMPL_BASIC_EQUALS(Function) REF_IMPL_TO_VALUE(Function) REF_IMPL_BASIC_FUNC(Array) REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(Array) REF_IMPL_BASIC_DESCRIBE(Array) REF_IMPL_BASIC_EQUALS(Array) REF_IMPL_TO_VALUE(Array) REF_IMPL_BASIC_FUNC(ByteBuffer) REF_IMPL_BASIC_DESCRIBE(ByteBuffer) REF_IMPL_BASIC_EQUALS(ByteBuffer) REF_IMPL_BASIC_FUNC(Unsupported) REF_IMPL_BASIC_NOT_VALUE_CTOR_DTOR(Unsupported) REF_IMPL_BASIC_DESCRIBE(Unsupported) REF_IMPL_BASIC_EQUALS(Unsupported) REF_IMPL_TO_VALUE(Unsupported) // ==== value ==== Local::Local() noexcept : val_(-1) {} Local::Local(InternalLocalRef local) : val_(local) { wasm_backend::currentEngine(); } Local::~Local() = default; bool Local::isNull() const { return val_ < 0 || wasm_backend::Stack::isNullOrUndefined(val_); } void Local::reset() { val_ = -1; } ValueKind Local::getKind() const { if (isNull()) { return ValueKind::kNull; } else if (isString()) { return ValueKind::kString; } else if (isNumber()) { return ValueKind::kNumber; } else if (isBoolean()) { return ValueKind::kBoolean; } else if (isFunction()) { return ValueKind::kFunction; } else if (isArray()) { return ValueKind::kArray; } else if (isByteBuffer()) { return ValueKind::kByteBuffer; } else if (isObject()) { return ValueKind::kObject; } else { return ValueKind::kUnsupported; } } bool Local::isString() const { return wasm_backend::Stack::isString(val_); } bool Local::isNumber() const { return wasm_backend::Stack::isNumber(val_); } bool Local::isBoolean() const { return wasm_backend::Stack::isBoolean(val_); } bool Local::isFunction() const { return wasm_backend::Stack::isFunction(val_); } bool Local::isArray() const { return wasm_backend::Stack::isArray(val_); } bool Local::isByteBuffer() const { return wasm_backend::Stack::isByteBuffer(val_); } bool Local::isObject() const { return wasm_backend::Stack::isObject(val_); } bool Local::isUnsupported() const { return wasm_backend::Stack::isUnsupported(val_); } Local Local::asString() const { if (!isString()) throw Exception("can't cast value as String"); return Local{val_}; } Local Local::asNumber() const { if (!isNumber()) throw Exception("can't cast value as Number"); return Local(val_); } Local Local::asBoolean() const { if (!isBoolean()) throw Exception("can't cast value as Boolean"); return Local(val_); } Local Local::asFunction() const { if (!isFunction()) throw Exception("can't cast value as Function"); return Local{val_}; } Local Local::asArray() const { if (!isArray()) throw Exception("can't cast value as Array"); return Local(val_); } Local Local::asByteBuffer() const { if (!isByteBuffer()) throw Exception("can't cast value as ByteBuffer"); return Local(wasm_backend::ByteBufferState(val_)); } Local Local::asObject() const { if (!isObject()) throw Exception("can't cast value as Object"); return Local(val_); } Local Local::asUnsupported() const { if (!isUnsupported()) throw Exception("can't cast value as Unsupported"); return Local(val_); } bool Local::operator==(const script::Local& other) const { if (isNull()) return other.isNull(); return wasm_backend::Stack::equals(val_, other.val_); } Local Local::describe() const { return Local(wasm_backend::Stack::toString(val_)); } Local Local::get(const script::Local& key) const { return Local(wasm_backend::Stack::objectGet(val_, key.val_)); } void Local::set(const script::Local& key, const script::Local& value) const { wasm_backend::Stack::objectSet(val_, key.val_, value.val_); } void Local::remove(const Local& key) const { wasm_backend::Stack::objectRemove(val_, key.val_); } bool Local::has(const Local& key) const { return wasm_backend::Stack::objectHas(val_, key.val_); } bool Local::instanceOf(const Local& type) const { return wasm_backend::Stack::objectInstanceOf(val_, type.val_); } std::vector> Local::getKeys() const { auto keys = Local(wasm_backend::Stack::objectGetKeys(val_)); std::vector> ret; ret.reserve(keys.size()); for (size_t i = 0; i < keys.size(); ++i) { ret.push_back(keys.get(i).asString()); } return ret; } float Local::toFloat() const { return wasm_backend::Stack::toNumberFloat(val_); } double Local::toDouble() const { return wasm_backend::Stack::toNumberDouble(val_); } int32_t Local::toInt32() const { return wasm_backend::Stack::toNumberInt32(val_); } int64_t Local::toInt64() const { return wasm_backend::Stack::toNumberInt64(val_); } bool Local::value() const { return wasm_backend::Stack::toBoolean(val_); } Local Local::callImpl(const Local& thiz, size_t size, const Local* args) const { return Local(wasm_backend::callFunction(*this, thiz, size, args)); } size_t Local::size() const { return wasm_backend::Stack::arrayLength(val_); } Local Local::get(size_t index) const { return Local(wasm_backend::Stack::arrayGet(val_, index)); } void Local::set(size_t index, const script::Local& value) const { wasm_backend::Stack::arraySet(val_, index, value.val_); } void Local::add(const script::Local& value) const { set(size(), value); } void Local::clear() const { wasm_backend::Stack::arrayClear(val_); } // ByteBuffer namespace wasm_backend { ByteBufferState::ByteBufferState(int val) : val_(val) {} ByteBufferState::ByteBufferState(std::shared_ptr backingStore, size_t size) : val_(-1), backingStore_(std::move(backingStore)), size_(size), type_(ByteBuffer::Type::kUnspecified) {} ByteBufferState::ByteBufferState(ByteBufferState&& move) noexcept : val_(move.val_), backingStore_(std::move(move.backingStore_)), size_(move.size_), type_(std::move(move.type_)) { move.val_ = -1; move.size_ = 0; } ByteBufferState& ByteBufferState::operator=(int what) { if (what != val_) { reset(); val_ = what; } return *this; } void ByteBufferState::reset() const { val_ = -1; backingStore_.reset(); size_ = 0; type_.reset(); } void ByteBufferState::fillBackingStore() const { if (!backingStore_) { std::shared_ptr* ptr = nullptr; void* buffer = nullptr; ByteBufferHelper::fillBackingStore(val_, &ptr, &buffer); if (ptr) { backingStore_ = *ptr; } else { backingStore_ = std::shared_ptr(buffer, [](void* p) { std::free(p); }); } } } void ByteBufferState::fillTypeAndSize() const { if (!type_.has_value()) { uint16_t type; ByteBufferHelper::fillTypeAndSize(val_, &type, &size_); type_ = ByteBuffer::Type(type); } } void ByteBufferState::fillWrapperIfNeed() const { if (val_ == -1 && backingStore_) { auto sharedPtr = std::make_unique>(backingStore_); val_ = ByteBufferHelper::fillWrapper(backingStore_.get(), sharedPtr.get(), size_); sharedPtr.release(); } } void swap(ByteBufferState& lhs, ByteBufferState& rhs) { std::swap(lhs.val_, rhs.val_); std::swap(lhs.backingStore_, rhs.backingStore_); std::swap(lhs.size_, rhs.size_); std::swap(lhs.type_, rhs.type_); } } // namespace wasm_backend Local::Local(InternalLocalRef val) : val_(val) { if (val.val_ < 0 && val_.backingStore_ == nullptr) { throw Exception("create Local with null reference"); } wasm_backend::currentEngine(); } Local::~Local() { commit(); } ByteBuffer::Type Local::getType() const { val_.fillTypeAndSize(); return val_.type_.value(); } Local Local::asValue() const { val_.fillWrapperIfNeed(); return Local(val_.val_); } size_t Local::byteLength() const { val_.fillTypeAndSize(); return val_.size_; } void* Local::getRawBytes() const { val_.fillBackingStore(); return val_.backingStore_.get(); } std::shared_ptr Local::getRawBytesShared() const { val_.fillBackingStore(); return val_.backingStore_; } bool Local::isShared() const { return wasm_backend::ByteBufferHelper::isSharedByteBuffer(*this); } void Local::commit() const { wasm_backend::ByteBufferHelper::commit(*this); } void Local::sync() const { wasm_backend::ByteBufferHelper::sync(*this); } } // namespace script