mirror of
https://github.com/bytecodealliance/wasm-micro-runtime.git
synced 2025-02-06 23:15:16 +00:00
16a4d71b34
Implement the GC (Garbage Collection) feature for interpreter mode, AOT mode and LLVM-JIT mode, and support most features of the latest spec proposal, and also enable the stringref feature. Use `cmake -DWAMR_BUILD_GC=1/0` to enable/disable the feature, and `wamrc --enable-gc` to generate the AOT file with GC supported. And update the AOT file version from 2 to 3 since there are many AOT ABI breaks, including the changes of AOT file format, the changes of AOT module/memory instance layouts, the AOT runtime APIs for the AOT code to invoke and so on.
1444 lines
44 KiB
C
1444 lines
44 KiB
C
/*
|
|
* Copyright (C) 2019 Intel Corporation. All rights reserved.
|
|
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
*/
|
|
|
|
#if WASM_ENABLE_STRINGREF != 0
|
|
|
|
#include "aot_emit_stringref.h"
|
|
#include "aot_emit_exception.h"
|
|
#include "aot_emit_memory.h"
|
|
#include "aot_emit_gc.h"
|
|
#include "aot.h"
|
|
#include "aot_compiler.h"
|
|
#include "aot_emit_memory.h"
|
|
#include "gc_object.h"
|
|
#include "string_object.h"
|
|
|
|
#define BUILD_ISNULL(ptr, res, name) \
|
|
do { \
|
|
if (!(res = LLVMBuildIsNull(comp_ctx->builder, ptr, name))) { \
|
|
aot_set_last_error("llvm build isnull failed."); \
|
|
goto fail; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define BUILD_ISNOTNULL(ptr, res, name) \
|
|
do { \
|
|
if (!(res = LLVMBuildIsNotNull(comp_ctx->builder, ptr, name))) { \
|
|
aot_set_last_error("llvm build isnotnull failed."); \
|
|
goto fail; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define ADD_BASIC_BLOCK(block, name) \
|
|
do { \
|
|
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
|
|
func_ctx->func, name))) { \
|
|
aot_set_last_error("llvm add basic block failed."); \
|
|
goto fail; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define CURR_BLOCK() LLVMGetInsertBlock(comp_ctx->builder)
|
|
|
|
#define MOVE_BLOCK_AFTER(llvm_block, llvm_block_after) \
|
|
LLVMMoveBasicBlockAfter(llvm_block, llvm_block_after)
|
|
|
|
#define MOVE_BLOCK_AFTER_CURR(llvm_block) \
|
|
LLVMMoveBasicBlockAfter(llvm_block, CURR_BLOCK())
|
|
|
|
#define DEFINE_STRINGREF_CHECK_VAR() \
|
|
LLVMBasicBlockRef check_string_obj_succ, check_stringref_obj_succ; \
|
|
LLVMValueRef cmp
|
|
|
|
#define CHECK_STRING_OBJ(str_obj) \
|
|
do { \
|
|
ADD_BASIC_BLOCK(check_string_obj_succ, "check string obj succ"); \
|
|
MOVE_BLOCK_AFTER_CURR(check_string_obj_succ); \
|
|
\
|
|
BUILD_ISNULL(str_obj, cmp, "cmp_string_obj"); \
|
|
if (!aot_emit_exception(comp_ctx, func_ctx, \
|
|
EXCE_FAILED_TO_CREATE_STRING, true, cmp, \
|
|
check_string_obj_succ)) \
|
|
goto fail; \
|
|
} while (0)
|
|
|
|
#define CHECK_STRINGREF_INTERNAL(stringref_obj, exce_id, name) \
|
|
do { \
|
|
ADD_BASIC_BLOCK(check_stringref_obj_succ, "check " name " obj succ"); \
|
|
MOVE_BLOCK_AFTER(check_stringref_obj_succ, check_string_obj_succ); \
|
|
\
|
|
BUILD_ISNULL(stringref_obj, cmp, "cmp_" name "_obj"); \
|
|
if (!aot_emit_exception(comp_ctx, func_ctx, exce_id, true, cmp, \
|
|
check_stringref_obj_succ)) \
|
|
goto fail; \
|
|
} while (0)
|
|
|
|
#define CHECK_STRINGREF_OBJ(stringref_obj) \
|
|
CHECK_STRINGREF_INTERNAL(stringref_obj, EXCE_FAILED_TO_CREATE_STRINGREF, \
|
|
"stringref")
|
|
|
|
#define CHECK_STRINGVIEW_OBJ(stringview_obj) \
|
|
CHECK_STRINGREF_INTERNAL(stringview_obj, EXCE_FAILED_TO_CREATE_STRINGVIEW, \
|
|
"stringview")
|
|
|
|
#define CHECK_STRING_ENCODE(value) \
|
|
do { \
|
|
ADD_BASIC_BLOCK(check_string_encode_succ, "check string encode succ"); \
|
|
MOVE_BLOCK_AFTER_CURR(check_string_encode_succ); \
|
|
\
|
|
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntSLT, value, \
|
|
I32_ZERO, "cmp_string_encode"))) { \
|
|
aot_set_last_error("llvm build icmp failed."); \
|
|
goto fail; \
|
|
} \
|
|
\
|
|
if (!aot_emit_exception(comp_ctx, func_ctx, \
|
|
EXCE_FAILED_TO_ENCODE_STRING, true, cmp, \
|
|
check_string_encode_succ)) \
|
|
goto fail; \
|
|
} while (0)
|
|
|
|
static bool
|
|
aot_call_wasm_stringref_obj_new(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx, LLVMValueRef str_obj,
|
|
uint32 stringref_type, uint32 pos,
|
|
LLVMValueRef *stringref_obj)
|
|
{
|
|
LLVMValueRef param_values[3], func, value, res;
|
|
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
|
|
uint32 argc = 2;
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = INT8_PTR_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
if (stringref_type == WASM_TYPE_STRINGREF) {
|
|
GET_AOT_FUNCTION(wasm_stringref_obj_new, argc);
|
|
}
|
|
else if (stringref_type == WASM_TYPE_STRINGVIEWWTF8) {
|
|
GET_AOT_FUNCTION(wasm_stringview_wtf8_obj_new, argc);
|
|
}
|
|
else if (stringref_type == WASM_TYPE_STRINGVIEWWTF16) {
|
|
GET_AOT_FUNCTION(wasm_stringview_wtf16_obj_new, argc);
|
|
}
|
|
else {
|
|
argc = 3;
|
|
GET_AOT_FUNCTION(wasm_stringview_iter_obj_new, argc);
|
|
}
|
|
|
|
param_values[0] = func_ctx->exec_env;
|
|
param_values[1] = str_obj;
|
|
if (stringref_type == WASM_TYPE_STRINGVIEWITER) {
|
|
param_values[2] = I32_CONST(pos);
|
|
}
|
|
|
|
if (!(res = LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
|
|
argc, "create_stringref"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
*stringref_obj = res;
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
static LLVMValueRef
|
|
aot_stringref_obj_get_value(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
LLVMValueRef stringref_obj)
|
|
{
|
|
LLVMValueRef str_obj_ptr, str_obj, host_ptr_offset;
|
|
|
|
/* header */
|
|
host_ptr_offset = I32_CONST(comp_ctx->pointer_size);
|
|
|
|
if (!(stringref_obj =
|
|
LLVMBuildBitCast(comp_ctx->builder, stringref_obj, INT8_PTR_TYPE,
|
|
"stringref_obj_i8p"))) {
|
|
aot_set_last_error("llvm build bitcast failed.");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(str_obj_ptr =
|
|
LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE, stringref_obj,
|
|
&host_ptr_offset, 1, "str_obj_i8p"))) {
|
|
aot_set_last_error("llvm build gep failed.");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(str_obj_ptr = LLVMBuildBitCast(comp_ctx->builder, str_obj_ptr,
|
|
GC_REF_PTR_TYPE, "str_obj_gcref_p"))) {
|
|
aot_set_last_error("llvm build bitcast failed.");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(str_obj = LLVMBuildLoad2(comp_ctx->builder, GC_REF_TYPE, str_obj_ptr,
|
|
"str_obj"))) {
|
|
aot_set_last_error("llvm build load failed.");
|
|
goto fail;
|
|
}
|
|
|
|
LLVMSetAlignment(str_obj, 4);
|
|
|
|
return str_obj;
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef
|
|
get_stringview_iter_pos_addr(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
LLVMValueRef stringview_iter_obj)
|
|
{
|
|
LLVMValueRef iter_pos_ptr, host_ptr_offset;
|
|
|
|
/* header + str_obj */
|
|
host_ptr_offset = I32_CONST(comp_ctx->pointer_size * 2);
|
|
|
|
if (!(stringview_iter_obj =
|
|
LLVMBuildBitCast(comp_ctx->builder, stringview_iter_obj,
|
|
INT8_PTR_TYPE, "stringview_iter_obj_i8p"))) {
|
|
aot_set_last_error("llvm build bitcast failed.");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(iter_pos_ptr = LLVMBuildInBoundsGEP2(
|
|
comp_ctx->builder, INT8_TYPE, stringview_iter_obj,
|
|
&host_ptr_offset, 1, "iter_pos_i8p"))) {
|
|
aot_set_last_error("llvm build gep failed.");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(iter_pos_ptr = LLVMBuildBitCast(comp_ctx->builder, iter_pos_ptr,
|
|
INT32_PTR_TYPE, "iter_pos_i32p"))) {
|
|
aot_set_last_error("llvm build bitcast failed.");
|
|
goto fail;
|
|
}
|
|
|
|
return iter_pos_ptr;
|
|
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef
|
|
aot_call_wasm_string_measure(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
LLVMValueRef stringref_obj, uint32 encoding)
|
|
{
|
|
LLVMValueRef param_values[3], func, value, str_obj;
|
|
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_measure, 2);
|
|
|
|
/* Call function wasm_string_measure() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = I32_CONST(encoding);
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 2, "string_measure"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
return value;
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef
|
|
aot_call_wasm_string_create_view(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx,
|
|
LLVMValueRef stringref_obj, uint32 encoding)
|
|
{
|
|
LLVMValueRef param_values[3], func, value, str_obj;
|
|
LLVMTypeRef param_types[3], ret_type, func_type, func_ptr_type;
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_create_view, 2);
|
|
|
|
/* Call function wasm_string_create_view() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = I32_CONST(encoding);
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 2, "string_create_view"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
return value;
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef
|
|
aot_call_wasm_string_advance(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
LLVMValueRef stringref_obj, LLVMValueRef bytes,
|
|
LLVMValueRef pos)
|
|
{
|
|
LLVMValueRef param_values[4], func, value, str_obj;
|
|
LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
param_types[3] = INT32_PTR_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_advance, 4);
|
|
|
|
/* Call function wasm_string_advance() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = pos;
|
|
param_values[2] = bytes;
|
|
param_values[3] = I8_PTR_NULL;
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 4, "string_advance"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
return value;
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
static LLVMValueRef
|
|
aot_call_wasm_string_slice(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
LLVMValueRef stringref_obj, LLVMValueRef start,
|
|
LLVMValueRef end, StringViewType stringview_type)
|
|
{
|
|
LLVMValueRef param_values[4], func, value, str_obj;
|
|
LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
param_types[3] = I32_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_slice, 4);
|
|
|
|
/* Call function wasm_string_slice() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = start;
|
|
param_values[2] = end;
|
|
param_values[3] = I32_CONST(stringview_type);
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 4, "string_slice"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
return value;
|
|
fail:
|
|
return NULL;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_new(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 encoding)
|
|
{
|
|
LLVMValueRef maddr, byte_length, offset, str_obj, stringref_obj;
|
|
LLVMValueRef param_values[5], func, value;
|
|
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_I32(byte_length);
|
|
POP_I32(offset);
|
|
|
|
if (!(maddr = check_bulk_memory_overflow(comp_ctx, func_ctx, offset,
|
|
byte_length)))
|
|
goto fail;
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_new_with_encoding, 3);
|
|
|
|
/* Call function wasm_struct_obj_new() */
|
|
param_values[0] = maddr;
|
|
param_values[1] = byte_length;
|
|
param_values[2] = I32_CONST(encoding);
|
|
|
|
if (!(str_obj = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 3, "wasm_string_new"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(str_obj);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, str_obj,
|
|
WASM_TYPE_STRINGREF, 0,
|
|
&stringref_obj)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGREF_OBJ(stringref_obj);
|
|
|
|
PUSH_GC_REF(stringref_obj);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_const(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 contents)
|
|
{
|
|
LLVMValueRef param_values[2], func, value, str_obj, stringref_obj;
|
|
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_new_const, 2);
|
|
|
|
bh_assert(contents < comp_ctx->comp_data->string_literal_count);
|
|
param_values[0] = LLVMConstIntToPtr(
|
|
I64_CONST((unsigned long long)(uintptr_t)
|
|
comp_ctx->comp_data->string_literal_ptrs_wp[contents]),
|
|
INT8_PTR_TYPE);
|
|
param_values[1] =
|
|
I32_CONST(comp_ctx->comp_data->string_literal_lengths_wp[contents]);
|
|
|
|
if (!(str_obj = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 2, "create_stringref"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(str_obj);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, str_obj,
|
|
WASM_TYPE_STRINGREF, 0,
|
|
&stringref_obj)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGREF_OBJ(stringref_obj);
|
|
|
|
PUSH_GC_REF(stringref_obj);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_measure(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx, uint32 encoding)
|
|
{
|
|
LLVMValueRef stringref_obj, value;
|
|
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(value = aot_call_wasm_string_measure(comp_ctx, func_ctx,
|
|
stringref_obj, encoding))) {
|
|
goto fail;
|
|
}
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_encode(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
|
|
uint32 mem_idx, uint32 encoding)
|
|
{
|
|
LLVMValueRef param_values[6], func, value, offset, length, maddr, str_obj,
|
|
stringref_obj;
|
|
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
|
|
LLVMBasicBlockRef check_string_encode_succ;
|
|
LLVMValueRef cmp;
|
|
|
|
POP_I32(offset);
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(length = aot_call_wasm_string_measure(comp_ctx, func_ctx,
|
|
stringref_obj, encoding))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(maddr =
|
|
check_bulk_memory_overflow(comp_ctx, func_ctx, offset, length)))
|
|
goto fail;
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
param_types[3] = INT8_PTR_TYPE;
|
|
param_types[4] = INT8_PTR_TYPE;
|
|
param_types[5] = I32_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_encode, 6);
|
|
|
|
/* Call function wasm_string_measure() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = I32_ZERO;
|
|
param_values[2] = length;
|
|
param_values[3] = maddr;
|
|
param_values[4] = I8_PTR_NULL;
|
|
param_values[5] = I32_CONST(encoding);
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 6, "string_encode"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
CHECK_STRING_ENCODE(value);
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_concat(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef param_values[2], func, value, str_obj_lhs, str_obj_rhs,
|
|
stringref_obj_lhs, stringref_obj_rhs, stringref_obj_new;
|
|
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_GC_REF(stringref_obj_rhs);
|
|
POP_GC_REF(stringref_obj_lhs);
|
|
|
|
if (!(str_obj_lhs = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringref_obj_lhs))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(str_obj_rhs = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringref_obj_rhs))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = INT8_PTR_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_concat, 2);
|
|
|
|
/* Call function wasm_string_concat() */
|
|
param_values[0] = str_obj_lhs;
|
|
param_values[1] = str_obj_rhs;
|
|
|
|
if (!(str_obj_lhs = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 2, "string_concat"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(str_obj_lhs);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, str_obj_lhs,
|
|
WASM_TYPE_STRINGREF, 0,
|
|
&stringref_obj_new)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGREF_OBJ(stringref_obj_new);
|
|
|
|
PUSH_GC_REF(stringref_obj_new);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_eq(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef param_values[2], func, value, str_obj_lhs, str_obj_rhs,
|
|
stringref_obj_lhs, stringref_obj_rhs;
|
|
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
|
|
|
POP_GC_REF(stringref_obj_lhs);
|
|
POP_GC_REF(stringref_obj_rhs);
|
|
|
|
if (!(str_obj_lhs = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringref_obj_lhs))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(str_obj_rhs = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringref_obj_rhs))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = INT8_PTR_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_eq, 2);
|
|
|
|
/* Call function wasm_string_eq() */
|
|
param_values[0] = str_obj_lhs;
|
|
param_values[1] = str_obj_rhs;
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 2, "string_eq"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_is_usv_sequence(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef param_values[1], func, value, str_obj, stringref_obj;
|
|
LLVMTypeRef param_types[1], ret_type, func_type, func_ptr_type;
|
|
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_is_usv_sequence, 1);
|
|
|
|
/* Call function wasm_string_is_usv_sequence() */
|
|
param_values[0] = str_obj;
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 1, "string_is_usv_sequence"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_as_wtf8(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef str_obj, stringref_obj, stringview_wtf8_obj;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(str_obj = aot_call_wasm_string_create_view(
|
|
comp_ctx, func_ctx, stringref_obj, STRING_VIEW_WTF8))) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(str_obj);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, str_obj,
|
|
WASM_TYPE_STRINGVIEWWTF8, 0,
|
|
&stringview_wtf8_obj)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGVIEW_OBJ(stringref_obj);
|
|
|
|
PUSH_GC_REF(stringview_wtf8_obj);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_wtf8_advance(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef stringref_obj, bytes, pos, value;
|
|
|
|
POP_I32(bytes);
|
|
POP_I32(pos);
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(value = aot_call_wasm_string_advance(comp_ctx, func_ctx,
|
|
stringref_obj, bytes, pos))) {
|
|
goto fail;
|
|
}
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_wtf8_encode(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx, uint32 mem_idx,
|
|
uint32 encoding)
|
|
{
|
|
LLVMValueRef param_values[6], func, value, offset, maddr, str_obj,
|
|
stringref_obj;
|
|
LLVMValueRef bytes, pos, next_pos;
|
|
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
|
|
LLVMBasicBlockRef check_string_encode_succ;
|
|
LLVMValueRef cmp;
|
|
|
|
POP_I32(bytes);
|
|
POP_I32(pos);
|
|
POP_I32(offset);
|
|
|
|
next_pos = LLVMBuildAlloca(comp_ctx->builder, I32_TYPE, "next_pos");
|
|
if (!next_pos) {
|
|
aot_set_last_error("failed to build alloca");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(maddr =
|
|
check_bulk_memory_overflow(comp_ctx, func_ctx, offset, bytes)))
|
|
goto fail;
|
|
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
param_types[3] = INT8_PTR_TYPE;
|
|
param_types[4] = INT8_PTR_TYPE;
|
|
param_types[5] = I32_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_encode, 6);
|
|
|
|
/* Call function wasm_string_measure() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = pos;
|
|
param_values[2] = bytes;
|
|
param_values[3] = maddr;
|
|
param_values[4] = next_pos;
|
|
param_values[5] = I32_CONST(encoding);
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 6, "string_encode"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
CHECK_STRING_ENCODE(value);
|
|
|
|
next_pos =
|
|
LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, next_pos, "next_pos");
|
|
if (!next_pos) {
|
|
aot_set_last_error("llvm build load failed.");
|
|
goto fail;
|
|
}
|
|
|
|
LLVMSetAlignment(next_pos, 4);
|
|
|
|
PUSH_I32(next_pos);
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_wtf8_slice(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef stringref_obj, start, end, stringref_obj_new, value;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_I32(start);
|
|
POP_I32(end);
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(value = aot_call_wasm_string_slice(comp_ctx, func_ctx, stringref_obj,
|
|
start, end, STRING_VIEW_WTF8))) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(value);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, value,
|
|
WASM_TYPE_STRINGREF, 0,
|
|
&stringref_obj_new)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGREF_OBJ(stringref_obj_new);
|
|
|
|
PUSH_GC_REF(stringref_obj_new);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_as_wtf16(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef str_obj, stringref_obj, stringview_wtf16_obj;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(str_obj = aot_call_wasm_string_create_view(
|
|
comp_ctx, func_ctx, stringref_obj, STRING_VIEW_WTF16))) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(str_obj);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, str_obj,
|
|
WASM_TYPE_STRINGVIEWWTF16, 0,
|
|
&stringview_wtf16_obj)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGVIEW_OBJ(stringview_wtf16_obj);
|
|
|
|
PUSH_GC_REF(stringview_wtf16_obj);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_wtf16_length(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef param_values[2], func, value, str_obj, stringview_wtf16_obj;
|
|
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
|
|
|
POP_GC_REF(stringview_wtf16_obj);
|
|
|
|
if (!(str_obj = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringview_wtf16_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_wtf16_get_length, 6);
|
|
|
|
/* Call function wasm_string_wtf16_get_length() */
|
|
param_values[0] = str_obj;
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 1, "stringview_wtf16_length"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_wtf16_get_codeunit(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef param_values[2], func, value, str_obj, stringview_wtf16_obj,
|
|
pos;
|
|
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
|
|
|
POP_I32(pos);
|
|
POP_GC_REF(stringview_wtf16_obj);
|
|
|
|
if (!(str_obj = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringview_wtf16_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_get_wtf16_codeunit, 2);
|
|
|
|
/* Call function wasm_string_get_wtf16_codeunit() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = pos;
|
|
|
|
if (!(value =
|
|
LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
|
|
2, "stringview_wtf16_get_codeunit"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_wtf16_encode(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx, uint32 mem_idx)
|
|
{
|
|
LLVMValueRef param_values[6], func, value, offset, maddr, str_obj,
|
|
stringref_obj;
|
|
LLVMValueRef len, pos;
|
|
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
|
|
LLVMBasicBlockRef check_string_encode_succ;
|
|
LLVMValueRef cmp;
|
|
|
|
POP_I32(len);
|
|
POP_I32(pos);
|
|
POP_I32(offset);
|
|
|
|
if (!(maddr = check_bulk_memory_overflow(
|
|
comp_ctx, func_ctx, offset,
|
|
LLVMBuildMul(comp_ctx->builder, len, I32_CONST(2), "wtf16_len"))))
|
|
goto fail;
|
|
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!check_memory_alignment(comp_ctx, func_ctx, maddr, 2)) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
param_types[3] = INT8_PTR_TYPE;
|
|
param_types[4] = INT8_PTR_TYPE;
|
|
param_types[5] = I32_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_encode, 6);
|
|
|
|
/* Call function wasm_string_measure() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = pos;
|
|
param_values[2] = len;
|
|
param_values[3] = maddr;
|
|
param_values[4] = I8_PTR_NULL;
|
|
param_values[5] = I32_CONST(WTF16);
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 6, "string_encode"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
CHECK_STRING_ENCODE(value);
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_wtf16_slice(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef stringref_obj, start, end, stringref_obj_new, value;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_I32(end);
|
|
POP_I32(start);
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(value = aot_call_wasm_string_slice(comp_ctx, func_ctx, stringref_obj,
|
|
start, end, STRING_VIEW_WTF16))) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(value);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, value,
|
|
WASM_TYPE_STRINGREF, 0,
|
|
&stringref_obj_new)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGREF_OBJ(stringref_obj_new);
|
|
|
|
PUSH_GC_REF(stringref_obj_new);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_as_iter(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef stringref_obj, stringview_iter_obj, str_obj;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(str_obj = aot_call_wasm_string_create_view(
|
|
comp_ctx, func_ctx, stringref_obj, STRING_VIEW_WTF8))) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(str_obj);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, stringref_obj,
|
|
WASM_TYPE_STRINGVIEWITER, 0,
|
|
&stringview_iter_obj)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGVIEW_OBJ(stringview_iter_obj);
|
|
|
|
PUSH_GC_REF(stringview_iter_obj);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_iter_next(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef param_values[2], func, value, stringview_iter_obj, str_obj,
|
|
iter_pos_addr, pos;
|
|
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
|
|
|
|
POP_GC_REF(stringview_iter_obj);
|
|
|
|
if (!(str_obj = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringview_iter_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(iter_pos_addr = get_stringview_iter_pos_addr(comp_ctx, func_ctx,
|
|
stringview_iter_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
pos = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, iter_pos_addr,
|
|
"get_iter_pos");
|
|
LLVMSetAlignment(pos, 4);
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_next_codepoint, 2);
|
|
|
|
/* Call function wasm_string_measure() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = pos;
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 2, "stringview_iter_next"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
static bool
|
|
stringview_iter_advance_or_rewind(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx, bool is_rewind)
|
|
{
|
|
LLVMValueRef param_values[4], func, value, stringview_iter_obj, str_obj,
|
|
code_points_consumed, iter_pos_addr, pos, code_points_count, res;
|
|
LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
|
|
|
|
POP_I32(code_points_count);
|
|
POP_GC_REF(stringview_iter_obj);
|
|
|
|
if (!(str_obj = aot_stringref_obj_get_value(comp_ctx, func_ctx,
|
|
stringview_iter_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(iter_pos_addr = get_stringview_iter_pos_addr(comp_ctx, func_ctx,
|
|
stringview_iter_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(pos = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, iter_pos_addr,
|
|
"get_iter_pos"))) {
|
|
goto fail;
|
|
}
|
|
LLVMSetAlignment(pos, 4);
|
|
|
|
if (!(code_points_consumed = LLVMBuildAlloca(comp_ctx->builder, I32_TYPE,
|
|
"code_points_consumed"))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
param_types[3] = INT32_PTR_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
if (is_rewind) {
|
|
GET_AOT_FUNCTION(wasm_string_rewind, 4);
|
|
}
|
|
else {
|
|
GET_AOT_FUNCTION(wasm_string_advance, 4);
|
|
}
|
|
|
|
/* Call function wasm_string_advance() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = pos;
|
|
param_values[2] = code_points_count;
|
|
param_values[3] = code_points_consumed;
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 4, "string_advance"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
if (!(code_points_consumed =
|
|
LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, code_points_consumed,
|
|
"get_code_points_consumed"))) {
|
|
aot_set_last_error("llvm build load failed.");
|
|
goto fail;
|
|
}
|
|
LLVMSetAlignment(code_points_consumed, 4);
|
|
|
|
if (!(res = LLVMBuildStore(comp_ctx->builder, code_points_consumed,
|
|
iter_pos_addr))) {
|
|
aot_set_last_error("llvm build store failed.");
|
|
goto fail;
|
|
}
|
|
LLVMSetAlignment(res, 4);
|
|
|
|
PUSH_I32(code_points_consumed);
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_iter_advance(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
return stringview_iter_advance_or_rewind(comp_ctx, func_ctx, false);
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_iter_rewind(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
return stringview_iter_advance_or_rewind(comp_ctx, func_ctx, true);
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_stringview_iter_slice(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx)
|
|
{
|
|
LLVMValueRef stringview_iter_obj, start, end, stringref_obj_new, value,
|
|
iter_pos_addr, code_points_count;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_I32(code_points_count);
|
|
POP_GC_REF(stringview_iter_obj);
|
|
|
|
if (!(iter_pos_addr = get_stringview_iter_pos_addr(comp_ctx, func_ctx,
|
|
stringview_iter_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(start = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, iter_pos_addr,
|
|
"get_iter_pos"))) {
|
|
goto fail;
|
|
}
|
|
LLVMSetAlignment(start, 4);
|
|
|
|
if (!(end = LLVMBuildAdd(comp_ctx->builder, start, code_points_count,
|
|
"calc_slice_end"))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(value = aot_call_wasm_string_slice(comp_ctx, func_ctx,
|
|
stringview_iter_obj, start, end,
|
|
STRING_VIEW_ITER))) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(value);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, value,
|
|
WASM_TYPE_STRINGREF, 0,
|
|
&stringref_obj_new)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGREF_OBJ(stringref_obj_new);
|
|
|
|
PUSH_GC_REF(stringref_obj_new);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_new_array(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx, uint32 encoding)
|
|
{
|
|
LLVMValueRef start, end, count, str_obj, stringref_obj, array_obj,
|
|
elem_data_ptr;
|
|
LLVMValueRef param_values[5], func, value;
|
|
LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
|
|
DEFINE_STRINGREF_CHECK_VAR();
|
|
|
|
if (!aot_gen_commit_values(comp_ctx->aot_frame))
|
|
return false;
|
|
|
|
if (!aot_gen_commit_sp_ip(comp_ctx->aot_frame, true, true))
|
|
return false;
|
|
|
|
POP_I32(end);
|
|
POP_I32(start);
|
|
POP_GC_REF(array_obj);
|
|
|
|
if (!aot_array_obj_elem_addr(
|
|
comp_ctx, func_ctx, array_obj, start, &elem_data_ptr,
|
|
encoding == WTF16 ? PACKED_TYPE_I16 : PACKED_TYPE_I8)) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(count = LLVMBuildSub(comp_ctx->builder, end, start, "calc_count"))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
ret_type = INT8_PTR_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_new_with_encoding, 3);
|
|
|
|
/* Call function wasm_struct_obj_new() */
|
|
param_values[0] = elem_data_ptr;
|
|
param_values[1] = count;
|
|
param_values[2] = I32_CONST(encoding);
|
|
|
|
if (!(str_obj = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 3, "wasm_string_new"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
CHECK_STRING_OBJ(str_obj);
|
|
|
|
if (!aot_call_wasm_stringref_obj_new(comp_ctx, func_ctx, str_obj,
|
|
WASM_TYPE_STRINGREF, 0,
|
|
&stringref_obj)) {
|
|
goto fail;
|
|
}
|
|
CHECK_STRINGREF_OBJ(stringref_obj);
|
|
|
|
PUSH_GC_REF(stringref_obj);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
bool
|
|
aot_compile_op_string_encode_array(AOTCompContext *comp_ctx,
|
|
AOTFuncContext *func_ctx, uint32 encoding)
|
|
{
|
|
LLVMValueRef param_values[6], func, value, count, start, str_obj,
|
|
stringref_obj, array_obj, elem_data_ptr, array_len;
|
|
LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
|
|
LLVMBasicBlockRef check_string_encode_succ, check_array_index_succ;
|
|
LLVMValueRef cmp;
|
|
|
|
POP_I32(start);
|
|
POP_GC_REF(array_obj);
|
|
POP_GC_REF(stringref_obj);
|
|
|
|
if (!(str_obj =
|
|
aot_stringref_obj_get_value(comp_ctx, func_ctx, stringref_obj))) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!aot_array_obj_length(comp_ctx, array_obj, &array_len))
|
|
goto fail;
|
|
|
|
if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, start, array_len,
|
|
"check_array_index"))) {
|
|
aot_set_last_error("llvm build icmp failed.");
|
|
goto fail;
|
|
}
|
|
|
|
ADD_BASIC_BLOCK(check_array_index_succ, "check array index succ");
|
|
MOVE_BLOCK_AFTER_CURR(check_array_index_succ);
|
|
|
|
if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_ARRAY_IDX_OOB, true, cmp,
|
|
check_array_index_succ)) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!aot_array_obj_elem_addr(
|
|
comp_ctx, func_ctx, stringref_obj, start, &elem_data_ptr,
|
|
encoding == WTF16 ? PACKED_TYPE_I16 : PACKED_TYPE_I8)) {
|
|
goto fail;
|
|
}
|
|
|
|
if (!(count = aot_call_wasm_string_measure(comp_ctx, func_ctx,
|
|
stringref_obj, encoding))) {
|
|
goto fail;
|
|
}
|
|
|
|
param_types[0] = INT8_PTR_TYPE;
|
|
param_types[1] = I32_TYPE;
|
|
param_types[2] = I32_TYPE;
|
|
param_types[3] = INT8_PTR_TYPE;
|
|
param_types[4] = INT8_PTR_TYPE;
|
|
param_types[5] = I32_TYPE;
|
|
ret_type = I32_TYPE;
|
|
|
|
GET_AOT_FUNCTION(wasm_string_encode, 6);
|
|
|
|
/* Call function wasm_string_measure() */
|
|
param_values[0] = str_obj;
|
|
param_values[1] = start;
|
|
param_values[2] = count;
|
|
param_values[3] = elem_data_ptr;
|
|
param_values[4] = I8_PTR_NULL;
|
|
param_values[5] = I32_CONST(encoding);
|
|
|
|
if (!(value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
|
|
param_values, 6, "string_encode"))) {
|
|
aot_set_last_error("llvm build call failed.");
|
|
goto fail;
|
|
}
|
|
|
|
CHECK_STRING_ENCODE(value);
|
|
|
|
PUSH_I32(value);
|
|
|
|
return true;
|
|
fail:
|
|
return false;
|
|
}
|
|
|
|
#endif /* WASM_ENABLE_STRINGREF != 0 */
|