blob: 0b86d3585368c02400c87a37ee92001d063bb8e6 [file] [log] [blame]
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/builtins/builtins-utils-gen.h"
#include "src/codegen/code-stub-assembler.h"
#include "src/objects/objects-inl.h"
#include "src/wasm/wasm-objects.h"
#include "src/wasm/wasm-opcodes.h"
namespace v8 {
namespace internal {
class WasmBuiltinsAssembler : public CodeStubAssembler {
public:
explicit WasmBuiltinsAssembler(compiler::CodeAssemblerState* state)
: CodeStubAssembler(state) {}
protected:
TNode<Object> UncheckedParameter(int index) {
return UncheckedCast<Object>(Parameter(index));
}
TNode<Code> LoadBuiltinFromFrame(Builtins::Name id) {
TNode<Object> instance = LoadInstanceFromFrame();
TNode<IntPtrT> isolate_root = UncheckedCast<IntPtrT>(
Load(MachineType::Pointer(), instance,
IntPtrConstant(WasmInstanceObject::kIsolateRootOffset -
kHeapObjectTag)));
TNode<Code> target = UncheckedCast<Code>(
Load(MachineType::TaggedPointer(), isolate_root,
IntPtrConstant(IsolateData::builtin_slot_offset(id))));
return target;
}
TNode<Object> LoadInstanceFromFrame() {
return UncheckedCast<Object>(
LoadFromParentFrame(WasmCompiledFrameConstants::kWasmInstanceOffset));
}
TNode<Object> LoadContextFromInstance(TNode<Object> instance) {
return UncheckedCast<Object>(
Load(MachineType::AnyTagged(), instance,
IntPtrConstant(WasmInstanceObject::kNativeContextOffset -
kHeapObjectTag)));
}
TNode<Code> LoadCEntryFromInstance(TNode<Object> instance) {
return UncheckedCast<Code>(
Load(MachineType::AnyTagged(), instance,
IntPtrConstant(WasmInstanceObject::kCEntryStubOffset -
kHeapObjectTag)));
}
};
TF_BUILTIN(WasmAllocateHeapNumber, WasmBuiltinsAssembler) {
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kAllocateHeapNumber);
TailCallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant());
}
TF_BUILTIN(WasmCallJavaScript, WasmBuiltinsAssembler) {
TNode<Object> context = UncheckedParameter(Descriptor::kContext);
TNode<Object> function = UncheckedParameter(Descriptor::kFunction);
TNode<Object> argc = UncheckedParameter(Descriptor::kActualArgumentsCount);
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kCall_ReceiverIsAny);
TailCallStub(CallTrampolineDescriptor{}, target, context, function, argc);
}
TF_BUILTIN(WasmRecordWrite, WasmBuiltinsAssembler) {
TNode<Object> object = UncheckedParameter(Descriptor::kObject);
TNode<Object> slot = UncheckedParameter(Descriptor::kSlot);
TNode<Object> remembered = UncheckedParameter(Descriptor::kRememberedSet);
TNode<Object> fp_mode = UncheckedParameter(Descriptor::kFPMode);
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kRecordWrite);
TailCallStub(RecordWriteDescriptor{}, target, NoContextConstant(), object,
slot, remembered, fp_mode);
}
TF_BUILTIN(WasmToNumber, WasmBuiltinsAssembler) {
TNode<Object> context = UncheckedParameter(Descriptor::kContext);
TNode<Object> argument = UncheckedParameter(Descriptor::kArgument);
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kToNumber);
TailCallStub(TypeConversionDescriptor(), target, context, argument);
}
TF_BUILTIN(WasmStackGuard, WasmBuiltinsAssembler) {
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Object> context = LoadContextFromInstance(instance);
TailCallRuntimeWithCEntry(Runtime::kWasmStackGuard, centry, context);
}
TF_BUILTIN(WasmStackOverflow, WasmBuiltinsAssembler) {
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Object> context = LoadContextFromInstance(instance);
TailCallRuntimeWithCEntry(Runtime::kThrowWasmStackOverflow, centry, context);
}
TF_BUILTIN(WasmThrow, WasmBuiltinsAssembler) {
TNode<Object> exception = UncheckedParameter(Descriptor::kException);
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Object> context = LoadContextFromInstance(instance);
TailCallRuntimeWithCEntry(Runtime::kThrow, centry, context, exception);
}
TF_BUILTIN(WasmRethrow, WasmBuiltinsAssembler) {
TNode<Object> exception = UncheckedParameter(Descriptor::kException);
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Object> context = LoadContextFromInstance(instance);
TailCallRuntimeWithCEntry(Runtime::kReThrow, centry, context, exception);
}
TF_BUILTIN(WasmAtomicNotify, WasmBuiltinsAssembler) {
TNode<Uint32T> address =
UncheckedCast<Uint32T>(Parameter(Descriptor::kAddress));
TNode<Uint32T> count = UncheckedCast<Uint32T>(Parameter(Descriptor::kCount));
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kAllocateHeapNumber);
// TODO(aseemgarg): Use SMIs if possible for address and count
TNode<HeapNumber> address_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(address_heap, ChangeUint32ToFloat64(address));
TNode<HeapNumber> count_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(count_heap, ChangeUint32ToFloat64(count));
TNode<Smi> result_smi = UncheckedCast<Smi>(CallRuntimeWithCEntry(
Runtime::kWasmAtomicNotify, centry, NoContextConstant(), instance,
address_heap, count_heap));
ReturnRaw(SmiToInt32(result_smi));
}
TF_BUILTIN(WasmI32AtomicWait, WasmBuiltinsAssembler) {
TNode<Uint32T> address =
UncheckedCast<Uint32T>(Parameter(Descriptor::kAddress));
TNode<Int32T> expected_value =
UncheckedCast<Int32T>(Parameter(Descriptor::kExpectedValue));
TNode<Float64T> timeout =
UncheckedCast<Float64T>(Parameter(Descriptor::kTimeout));
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kAllocateHeapNumber);
// TODO(aseemgarg): Use SMIs if possible for address and expected_value
TNode<HeapNumber> address_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(address_heap, ChangeUint32ToFloat64(address));
TNode<HeapNumber> expected_value_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(expected_value_heap,
ChangeInt32ToFloat64(expected_value));
TNode<HeapNumber> timeout_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(timeout_heap, timeout);
TNode<Smi> result_smi = UncheckedCast<Smi>(CallRuntimeWithCEntry(
Runtime::kWasmI32AtomicWait, centry, NoContextConstant(), instance,
address_heap, expected_value_heap, timeout_heap));
ReturnRaw(SmiToInt32(result_smi));
}
TF_BUILTIN(WasmI64AtomicWait, WasmBuiltinsAssembler) {
TNode<Uint32T> address =
UncheckedCast<Uint32T>(Parameter(Descriptor::kAddress));
TNode<Uint32T> expected_value_high =
UncheckedCast<Uint32T>(Parameter(Descriptor::kExpectedValueHigh));
TNode<Uint32T> expected_value_low =
UncheckedCast<Uint32T>(Parameter(Descriptor::kExpectedValueLow));
TNode<Float64T> timeout =
UncheckedCast<Float64T>(Parameter(Descriptor::kTimeout));
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kAllocateHeapNumber);
// TODO(aseemgarg): Use SMIs if possible for address and expected_value
TNode<HeapNumber> address_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(address_heap, ChangeUint32ToFloat64(address));
TNode<HeapNumber> expected_value_high_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(expected_value_high_heap,
ChangeUint32ToFloat64(expected_value_high));
TNode<HeapNumber> expected_value_low_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(expected_value_low_heap,
ChangeUint32ToFloat64(expected_value_low));
TNode<HeapNumber> timeout_heap = UncheckedCast<HeapNumber>(
CallStub(AllocateHeapNumberDescriptor(), target, NoContextConstant()));
StoreHeapNumberValue(timeout_heap, timeout);
TNode<Smi> result_smi = UncheckedCast<Smi>(CallRuntimeWithCEntry(
Runtime::kWasmI64AtomicWait, centry, NoContextConstant(), instance,
address_heap, expected_value_high_heap, expected_value_low_heap,
timeout_heap));
ReturnRaw(SmiToInt32(result_smi));
}
TF_BUILTIN(WasmMemoryGrow, WasmBuiltinsAssembler) {
TNode<Int32T> num_pages =
UncheckedCast<Int32T>(Parameter(Descriptor::kNumPages));
Label num_pages_out_of_range(this, Label::kDeferred);
TNode<BoolT> num_pages_fits_in_smi =
IsValidPositiveSmi(ChangeInt32ToIntPtr(num_pages));
GotoIfNot(num_pages_fits_in_smi, &num_pages_out_of_range);
TNode<Smi> num_pages_smi = SmiFromInt32(num_pages);
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Object> context = LoadContextFromInstance(instance);
TNode<Smi> ret_smi = UncheckedCast<Smi>(CallRuntimeWithCEntry(
Runtime::kWasmMemoryGrow, centry, context, instance, num_pages_smi));
TNode<Int32T> ret = SmiToInt32(ret_smi);
ReturnRaw(ret);
BIND(&num_pages_out_of_range);
ReturnRaw(Int32Constant(-1));
}
TF_BUILTIN(WasmTableGet, WasmBuiltinsAssembler) {
TNode<Int32T> entry_index =
UncheckedCast<Int32T>(Parameter(Descriptor::kEntryIndex));
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Object> context = LoadContextFromInstance(instance);
Label entry_index_out_of_range(this, Label::kDeferred);
TNode<BoolT> entry_index_fits_in_smi =
IsValidPositiveSmi(ChangeInt32ToIntPtr(entry_index));
GotoIfNot(entry_index_fits_in_smi, &entry_index_out_of_range);
TNode<Smi> entry_index_smi = SmiFromInt32(entry_index);
TNode<Smi> table_index_smi =
UncheckedCast<Smi>(Parameter(Descriptor::kTableIndex));
TailCallRuntimeWithCEntry(Runtime::kWasmFunctionTableGet, centry, context,
instance, table_index_smi, entry_index_smi);
BIND(&entry_index_out_of_range);
MessageTemplate message_id =
wasm::WasmOpcodes::TrapReasonToMessageId(wasm::kTrapTableOutOfBounds);
TailCallRuntimeWithCEntry(Runtime::kThrowWasmError, centry, context,
SmiConstant(static_cast<int>(message_id)));
}
TF_BUILTIN(WasmTableSet, WasmBuiltinsAssembler) {
TNode<Int32T> entry_index =
UncheckedCast<Int32T>(Parameter(Descriptor::kEntryIndex));
TNode<Object> instance = LoadInstanceFromFrame();
TNode<Code> centry = LoadCEntryFromInstance(instance);
TNode<Object> context = LoadContextFromInstance(instance);
Label entry_index_out_of_range(this, Label::kDeferred);
TNode<BoolT> entry_index_fits_in_smi =
IsValidPositiveSmi(ChangeInt32ToIntPtr(entry_index));
GotoIfNot(entry_index_fits_in_smi, &entry_index_out_of_range);
TNode<Smi> entry_index_smi = SmiFromInt32(entry_index);
TNode<Smi> table_index_smi =
UncheckedCast<Smi>(Parameter(Descriptor::kTableIndex));
TNode<Object> value = UncheckedCast<Object>(Parameter(Descriptor::kValue));
TailCallRuntimeWithCEntry(Runtime::kWasmFunctionTableSet, centry, context,
instance, table_index_smi, entry_index_smi, value);
BIND(&entry_index_out_of_range);
MessageTemplate message_id =
wasm::WasmOpcodes::TrapReasonToMessageId(wasm::kTrapTableOutOfBounds);
TailCallRuntimeWithCEntry(Runtime::kThrowWasmError, centry, context,
SmiConstant(static_cast<int>(message_id)));
}
TF_BUILTIN(WasmI64ToBigInt, WasmBuiltinsAssembler) {
if (!Is64()) {
Unreachable();
return;
}
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kI64ToBigInt);
TNode<IntPtrT> argument =
UncheckedCast<IntPtrT>(Parameter(Descriptor::kArgument));
TailCallStub(I64ToBigIntDescriptor(), target, NoContextConstant(), argument);
}
TF_BUILTIN(WasmBigIntToI64, WasmBuiltinsAssembler) {
if (!Is64()) {
Unreachable();
return;
}
TNode<Object> context =
UncheckedCast<Object>(Parameter(Descriptor::kContext));
TNode<Code> target = LoadBuiltinFromFrame(Builtins::kBigIntToI64);
TNode<IntPtrT> argument =
UncheckedCast<IntPtrT>(Parameter(Descriptor::kArgument));
TailCallStub(BigIntToI64Descriptor(), target, context, argument);
}
#define DECLARE_ENUM(name) \
TF_BUILTIN(ThrowWasm##name, WasmBuiltinsAssembler) { \
TNode<Object> instance = LoadInstanceFromFrame(); \
TNode<Code> centry = LoadCEntryFromInstance(instance); \
TNode<Object> context = LoadContextFromInstance(instance); \
MessageTemplate message_id = \
wasm::WasmOpcodes::TrapReasonToMessageId(wasm::k##name); \
TailCallRuntimeWithCEntry(Runtime::kThrowWasmError, centry, context, \
SmiConstant(static_cast<int>(message_id))); \
}
FOREACH_WASM_TRAPREASON(DECLARE_ENUM)
#undef DECLARE_ENUM
} // namespace internal
} // namespace v8