blob: 5c6360f6c7d587e9d6690b0441d4b9aa75c2b2bd [file] [log] [blame]
/*
* Copyright (C) 2015 The Android Open Source Project
*
* 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 "interpreter.h"
#include "memory_manager.h"
#include <gapic/log.h>
#include <utility>
#include <vector>
namespace gapir {
Interpreter::Interpreter(const MemoryManager* memoryManager, uint32_t stackDepth) :
mMemoryManager(memoryManager), mStack(stackDepth, mMemoryManager),
mLabel(0) {
registerFunction(PRINT_STACK_FUNCTION_ID, [](Stack* stack, bool) {
stack->printStack();
return true;
});
}
bool Interpreter::run(const std::pair<const uint32_t*, uint32_t>& instructions) {
for (uint32_t i = 0; i < instructions.second; ++i) {
if (!interpret(instructions.first[i])) {
GAPID_WARNING(
"Interpreter stopped because of an interpretation error at opcode %u (%u)\n"
"Last reached label: %d\n",
i, instructions.first[i], mLabel);
return false;
}
}
return true;
}
void Interpreter::registerFunction(uint16_t functionCode, Function function) {
mFunctions[functionCode] = function;
}
BaseType Interpreter::extractType(uint32_t opcode) const {
return BaseType((opcode & TYPE_MASK) >> TYPE_BIT_SHIFT);
}
uint32_t Interpreter::extract20bitData(uint32_t opcode) const {
return opcode & DATA_MASK20;
}
uint32_t Interpreter::extract26bitData(uint32_t opcode) const {
return opcode & DATA_MASK26;
}
bool Interpreter::call(uint32_t opcode) {
auto func = mFunctions.find(opcode & FUNCTION_ID_MASK);
if (func == mFunctions.end()) {
GAPID_WARNING("Invalid function id: %u\n", opcode & FUNCTION_ID_MASK);
return false;
} else {
return func->second(&mStack, (opcode & PUSH_RETURN_MASK) != 0);
}
}
bool Interpreter::pushI(uint32_t opcode) {
BaseType type = extractType(opcode);
if (!isValid(type)) {
GAPID_WARNING("Error: pushI basic type invalid %u\n", type);
return false;
}
Stack::BaseValue data = extract20bitData(opcode);
switch (type) {
// Sign extension for signed types
case BaseType::Int32:
case BaseType::Int64:
if (data & 0x80000) {
data |= 0xfffffffffff00000ULL;
}
break;
// Shifting the value into the exponent for floating point types
case BaseType::Float:
data <<= 23;
break;
case BaseType::Double:
data <<= 52;
break;
default:
break;
}
mStack.pushValue(type, data);
return mStack.isValid();
}
bool Interpreter::loadC(uint32_t opcode) {
BaseType type = extractType(opcode);
if (!isValid(type)) {
GAPID_WARNING("Error: loadC basic type invalid %u\n", type);
return false;
}
const void* address = mMemoryManager->constantToAbsolute(extract20bitData(opcode));
if (!isConstantAddressForType(address, type)) {
GAPID_WARNING("Error: loadC not constant address %p\n", address);
return false;
}
mStack.pushFrom(type, address);
return mStack.isValid();
}
bool Interpreter::loadV(uint32_t opcode) {
BaseType type = extractType(opcode);
if (!isValid(type)) {
GAPID_WARNING("Error: loadV basic type invalid %u\n", type);
return false;
}
const void* address = mMemoryManager->volatileToAbsolute(extract20bitData(opcode));
if (!isVolatileAddressForType(address, type)) {
GAPID_WARNING("Error: loadV not volatile address %p\n", address);
return false;
}
mStack.pushFrom(type, address);
return mStack.isValid();
}
bool Interpreter::load(uint32_t opcode) {
BaseType type = extractType(opcode);
if (!isValid(type)) {
GAPID_WARNING("Error: load basic type invalid %u\n", type);
return false;
}
const void* address = mStack.pop<const void*>();
if (!isReadAddress(address)) {
GAPID_WARNING("Error: load not readable address %p\n", address);
return false;
}
mStack.pushFrom(type, address);
return mStack.isValid();
}
bool Interpreter::pop(uint32_t opcode) {
mStack.discard(extract26bitData(opcode));
return mStack.isValid();
}
bool Interpreter::storeV(uint32_t opcode) {
void* address = mMemoryManager->volatileToAbsolute(extract26bitData(opcode));
if (!isVolatileAddressForType(address, mStack.getTopType())) {
GAPID_WARNING("Error: storeV not volatile address %p\n", address);
return false;
}
mStack.popTo(address);
return mStack.isValid();
}
bool Interpreter::store() {
void* address = mStack.pop<void*>();
if (!isWriteAddress(address)) {
GAPID_WARNING("Error: store not write address %p\n", address);
return false;
}
mStack.popTo(address);
return mStack.isValid();
}
bool Interpreter::resource(uint32_t opcode) {
mStack.push<uint32_t>(extract26bitData(opcode));
return this->call(Interpreter::RESOURCE_FUNCTION_ID);
}
bool Interpreter::post() {
return this->call(Interpreter::POST_FUNCTION_ID);
}
bool Interpreter::copy(uint32_t opcode) {
uint32_t count = extract26bitData(opcode);
void* target = mStack.pop<void*>();
const void* source = mStack.pop<const void*>();
if (!isWriteAddress(target)) {
GAPID_WARNING("Error: copy target is invalid %p %d\n", target, count);
return false;
}
if (!isReadAddress(source)) {
GAPID_WARNING("Error: copy source is invalid %p %d\n", target, count);
return false;
}
if (source == nullptr) {
GAPID_WARNING("Error: copy source address is null\n");
return false;
}
if (target == nullptr) {
GAPID_WARNING("Error: copy destination address is null\n");
return false;
}
memcpy(target, source, count);
return mStack.isValid();
}
bool Interpreter::clone(uint32_t opcode) {
mStack.clone(extract26bitData(opcode));
return mStack.isValid();
}
bool Interpreter::strcpy(uint32_t opcode) {
uint32_t count = extract26bitData(opcode);
char* target = mStack.pop<char*>();
const char* source = mStack.pop<const char*>();
// Requires that the whole count is available, even if source is shorter.
if (!isWriteAddress(target)) {
GAPID_WARNING("Error: copy target is invalid %p %d\n", target, count);
return false;
}
if (!isReadAddress(source)) {
GAPID_WARNING("Error: copy source is invalid %p %d\n", target, count);
return false;
}
if (source == nullptr) {
GAPID_WARNING("Error: strcpy source address is null\n");
return false;
}
if (target == nullptr) {
GAPID_WARNING("Error: strcpy destination address is null\n");
return false;
}
uint32_t i;
for (i = 0; i < count - 1; i++) {
char c = source[i];
if (c == 0) {
break;
}
target[i] = c;
}
for (; i < count; i++) {
target[i] = 0;
}
return mStack.isValid();
}
bool Interpreter::extend(uint32_t opcode) {
uint32_t data = extract26bitData(opcode);
auto type = mStack.getTopType();
auto value = mStack.popBaseValue();
switch (type) {
// Masking out the mantissa end extending it with the new bits for floating point types
case BaseType::Float: {
value |= (data & 0x007fffffULL);
break;
}
case BaseType::Double: {
uint64_t exponent = value & 0xfff0000000000000ULL;
value <<= 26;
value |= data;
value &= 0x000fffffffffffffULL;
value |= exponent;
break;
}
// Extending the value with 26 new LSB
default: {
value = (value << 26) | data;
break;
}
}
mStack.pushValue(type, value);
return mStack.isValid();
}
bool Interpreter::label(uint32_t opcode) {
mLabel = extract26bitData(opcode);
return mStack.isValid();
}
#define DEBUG_OPCODE(name, value) GAPID_DEBUG(name "\n")
#define DEBUG_OPCODE_26(name, value) GAPID_DEBUG(name "(%#010x)\n", value & DATA_MASK26)
#define DEBUG_OPCODE_TY_20(name, value) GAPID_DEBUG(name "(%#010x, %s)\n", value & DATA_MASK20, baseTypeName(extractType(value)))
bool Interpreter::interpret(uint32_t opcode) {
InstructionCode code = static_cast<InstructionCode>(opcode >> OPCODE_BIT_SHIFT);
switch (code) {
case InstructionCode::CALL:
DEBUG_OPCODE_26("CALL", opcode);
return this->call(opcode);
case InstructionCode::PUSH_I:
DEBUG_OPCODE_TY_20("PUSH_I", opcode);
return this->pushI(opcode);
case InstructionCode::LOAD_C:
DEBUG_OPCODE_TY_20("LOAD_C", opcode);
return this->loadC(opcode);
case InstructionCode::LOAD_V:
DEBUG_OPCODE_TY_20("LOAD_V", opcode);
return this->loadV(opcode);
case InstructionCode::LOAD:
DEBUG_OPCODE_TY_20("LOAD", opcode);
return this->load(opcode);
case InstructionCode::POP:
DEBUG_OPCODE_26("POP", opcode);
return this->pop(opcode);
case InstructionCode::STORE_V:
DEBUG_OPCODE_26("STORE_V", opcode);
return this->storeV(opcode);
case InstructionCode::STORE:
DEBUG_OPCODE("STORE", opcode);
return this->store();
case InstructionCode::RESOURCE:
DEBUG_OPCODE_26("RESOURCE", opcode);
return this->resource(opcode);
case InstructionCode::POST:
DEBUG_OPCODE("POST", opcode);
return this->post();
case InstructionCode::COPY:
DEBUG_OPCODE_26("COPY", opcode);
return this->copy(opcode);
case InstructionCode::CLONE:
DEBUG_OPCODE_26("CLONE", opcode);
return this->clone(opcode);
case InstructionCode::STRCPY:
DEBUG_OPCODE_26("STRCPY", opcode);
return this->strcpy(opcode);
case InstructionCode::EXTEND:
DEBUG_OPCODE_26("EXTEND", opcode);
return this->extend(opcode);
case InstructionCode::LABEL:
DEBUG_OPCODE_26("LABEL", opcode);
return this->label(opcode);
default:
GAPID_WARNING("Unknown opcode! %#010x\n", opcode);
return false;
}
}
#undef DEBUG_OPCODE
} // namespace gapir