void ndi_packet_rx_cb(const void *buffer, sai_size_t buffer_size, uint32_t attr_count, const sai_attribute_t *attr_list) { uint32_t attr_index = 0; sai_status_t sai_rc = SAI_STATUS_SUCCESS; ndi_packet_attr_t n_attr; STD_ASSERT(buffer != NULL); if(attr_count == 0) { NDI_LOG_TRACE(ev_log_t_NDI, "NDI-PKT", "Attribute count is 0"); return; } /* @Todo - Adding more attributes should be handled efficiently, if possible without loops */ n_attr.trap_id = NDI_PACKET_TRAP_ID_DEFAULT; for (; attr_index < attr_count; ++attr_index) { sai_rc = ndi_packet_get_attr(&attr_list[attr_index], &n_attr); if (sai_rc != SAI_STATUS_SUCCESS) { return; } } nas_ndi_db_t *ndi_db_ptr = ndi_db_ptr_get(n_attr.npu_id); STD_ASSERT(ndi_db_ptr != NULL); if(ndi_db_ptr->switch_notification->packet_rx_cb) { ndi_db_ptr->switch_notification->packet_rx_cb((uint8_t *)buffer, buffer_size, &n_attr); } return; }
// Remove a value from list void ValueList::remove(ReferenceImpl* value) { STD_ASSERT(("Value is not in this list.", value->owner == this)); #if USE_LIST_IN_VALUE_LIST m_container.remove_node(value); #elif USE_VECTOR_IN_VALUE_LIST STD_ASSERT(("Value offset is invalid.", value->offset < get_count())); STD_ASSERT(("Value is not in the specified offset.", m_container[value->offset] == value)); // Replace with tail element & shrink auto value_offset = value->offset; auto tail_offset = get_count() - 1; m_container[value_offset] = m_container[tail_offset]; m_container[value_offset]->offset = value_offset; m_container[tail_offset] = 0; m_container.shrink(tail_offset); #else // Replace with tail element & shrink m_container.erase(value); #endif // Remove owner value->owner = 0; }
// Thread will be stopped void Thread::stop() { // Verify auto existed = (Thread *)std_get_tls_data(m_thread_tls_id); if (existed != this) throw_error("This structure isn't binded to this thread.\n"); if (m_value_list.get_count()) { printf("There are still %zu active reference values when thread is stopped.\n", m_value_list.get_count()); m_value_list.free(); } // Destroy start domain & context for convenience STD_ASSERT(m_current_domain == m_start_domain); STD_ASSERT(m_this_domain_context == m_all_domain_contexts); // Dont call pop_domain_context() when thread stopped, removed it STD_ASSERT(("There must be existed current_domain.", m_current_domain)); m_current_domain->m_context_list.remove_node(m_this_domain_context); m_this_domain_context--; // Remove the thread local domain XDELETE(m_start_domain); // Unbind std_set_tls_data(m_thread_tls_id, 0); }
// Call function in other object (without parameter) Value call_other(Thread *thread, ObjectId oid, const Value& function_name, Value *args, ArgNo n) { STD_ASSERT(function_name.m_type == ValueType::STRING); auto *entry = Object::get_entry_by_id(oid); auto *program = entry->program; if (entry->domain == thread->get_current_domain()) { STD_ASSERT(("Program shouldn't be null when the object is in same domain.", program)); // In the same domain, just do normal call Program::CalleeInfo callee; if (!program->get_public_callee_by_name((String *)&function_name, &callee)) return NIL; auto *object = entry->object; auto component_no = callee.component_no; auto offset = program->get_component_offset(component_no); auto *component_impl = (AbstractComponent *)(((Uint8 *)object) + offset); auto func = callee.function->get_script_entry(); thread->push_call_context(object, callee.function, args, n, component_no); Value ret = (component_impl->*func)(thread, args, n); thread->pop_call_context(); return ret; } // Call into other domain if (!program) return NIL; Value ret = program->invoke(thread, oid, function_name, args, n); return ret; }
// Define a constant in this program ConstantIndex Program::define_constant(const Value& value) { auto* thread = Thread::get_current_thread(); Value dup = value; if (dup.m_type >= REFERENCE_VALUE) { if (dup.m_type == STRING) { dup.m_string = Program::find_or_add_string(dup.m_string); } else { STD_ASSERT(("There are still values in thread local value list.\n", thread->get_value_list_count() == 0)); dup.m_reference = dup.m_reference->copy_to_local(thread); // Mark them to constant mark_constant(&dup); } } // Add to constants pool auto index = (ConstantIndex)m_constants.size(); STD_ASSERT(("Constants pool is too large to insert new one.\n", index <= Instruction::PARA_UMAX)); m_constants.push_back(dup); // Drop thread local values (should be string only, others were // binded to this program) thread->free_values(); return index; }
// Set byte codes for interpreted function void Function::set_byte_codes(Instruction* codes, size_t len) { STD_ASSERT(("Byte codes only for the interpreted function.\n", is_being_interpreted())); STD_ASSERT(("There are byte codes existed for this function.\n", m_byte_codes.size() == 0)); m_byte_codes.reserve(len); m_byte_codes.push_back_array(codes, len); }
// Conact two memory list then clear one void ValueList::concat_list(ValueList* list) { size_t list_count = list->get_count(); if (!list_count) // Target list is empry return; // Concat to my list #if USE_LIST_IN_VALUE_LIST while (list->m_container.size() > 0) { auto* node = list->m_container.begin().get_node(); STD_ASSERT(("The value was not owned by the list.", node->owner == list)); // Take off list->m_container.remove_node(node); // Join me node->owner = this; if (m_low > node) m_low = node; if (m_high < node) m_high = node; m_container.append_node(node); } #elif USE_VECTOR_IN_VALUE_LIST auto* head_address = list->get_head_address(); size_t offset = this->get_count(); for (size_t i = 0; i < list_count; i++) { STD_ASSERT(("Bad owner of value in list when concating.", (head_address[i])->owner == list)); auto* p = head_address[i]; p->offset = offset++; if (m_low > p) m_low = p; if (m_high < p) m_high = p; } m_container.push_back_array(head_address, list_count); #else for (auto& it : list->m_container) { STD_ASSERT(("Bad owner of value in list when concating.", it->owner == list)); it->owner = this; if (m_low > it) m_low = it; if (m_high < it) m_high = it; m_container.put(it); } #endif // Clear target list list->reset(); }
t_std_error ndi_packet_rx_register(ndi_packet_rx_type reg_fun) { t_std_error ret_code = STD_ERR_OK; npu_id_t npu_id = ndi_npu_id_get(); nas_ndi_db_t *ndi_db_ptr = ndi_db_ptr_get(npu_id); STD_ASSERT(ndi_db_ptr != NULL); STD_ASSERT(reg_fun != NULL); ndi_db_ptr->switch_notification->packet_rx_cb = reg_fun; return ret_code; }
/** * Turn-off the digital led * * resource_hdl[in] - Handle of the resource * * return t_std_error */ static t_std_error sdi_seven_segment_led_off (void *resource_hdl) { sdi_device_hdl_t digit_led = NULL; sdi_pin_bus_hdl_t led_ctrl_hdl = NULL; STD_ASSERT(resource_hdl != NULL); digit_led = (sdi_device_hdl_t) resource_hdl; led_ctrl_hdl = (sdi_pin_bus_hdl_t)digit_led->private_data; STD_ASSERT(led_ctrl_hdl != NULL); return sdi_pin_write_level(led_ctrl_hdl, SDI_PIN_LEVEL_LOW); }
// Run the function Value Simulator::run() { m_ip = m_byte_codes; for (;;) { if (m_ip->code == Instruction::RET) { GET_P1; return *p1; } // Get index of InstructionInfo for this code size_t index = m_code_map[m_ip->code]; auto *info = &m_instruction_info[index]; m_this_code = m_ip; m_ip++; (this->*info->entry)(); #ifdef _DEBUG { // The return value (p1) must be binded to current domain GET_P1; STD_ASSERT(p1->m_type < REFERENCE_VALUE || (p1->m_reference->attrib & ReferenceImpl::CONSTANT) || p1->m_reference->owner == m_domain->get_value_list()); } #endif } }
// Update program after all programs are loaded void Program::update_program() { m_this_component_size = offsetof(AbstractComponent, m_object_vars) + m_object_vars.size() * sizeof(Value); // Lookup program by name for (auto &it: m_components) { auto* program = Program::find_program_by_name(it.program_name); STD_ASSERT(("Program is not found.", program)); it.program = program; } // Lookup all interpreter components & recalcute the offset & size // Layout of an object (compiled-to-native-class) // Object: // [virtual table] // component 1 : Values x N1 // component 2 : Values x N2 // ... size_t entire_object_size = offsetof(Object, m_object_vars); for (auto &it : m_components) { auto* program = it.program; it.offset = (ComponentOffset)entire_object_size; entire_object_size += program->get_this_component_size(); } m_entire_object_size = entire_object_size; // Update all callees for this program update_callees(); }
// Define the object's size, for compiled_to_native class only void Program::define_object(size_t object_size) { STD_ASSERT(("Don't define size for non compiled-to-native-class object.", is_compiled_to_native())); m_entire_object_size = object_size; throw 0; }
t_std_error ndi_packet_tx (uint8_t* buf, uint32_t len, ndi_packet_attr_t *p_attr) { t_std_error ret_code = STD_ERR_OK; sai_status_t sai_ret = SAI_STATUS_FAILURE; uint32_t attr_idx = 0; sai_attribute_t sai_attr[NDI_MAX_PKT_ATTR]; sai_object_id_t sai_port; sai_size_t buf_len = len; nas_ndi_db_t *ndi_db_ptr = ndi_db_ptr_get(p_attr->npu_id); STD_ASSERT(ndi_db_ptr != NULL); if ((ret_code = ndi_sai_port_id_get(p_attr->npu_id, p_attr->tx_port, &sai_port) != STD_ERR_OK)) { return ret_code; } sai_attr[attr_idx].id = SAI_HOSTIF_PACKET_EGRESS_PORT_OR_LAG; sai_attr[attr_idx].value.oid = sai_port; ++attr_idx; sai_attr[attr_idx].id = SAI_HOSTIF_PACKET_TX_TYPE; sai_attr[attr_idx].value.s32 = SAI_HOSTIF_TX_TYPE_PIPELINE_BYPASS; ++attr_idx; if ((sai_ret = ndi_packet_hostif_api_tbl_get(ndi_db_ptr)->send_packet(SAI_NULL_OBJECT_ID, buf, buf_len, attr_idx, sai_attr)) != SAI_STATUS_SUCCESS) { return STD_ERR(INTERFACE, FAIL, sai_ret); } return ret_code; }
extern "C" t_std_error std_user_chown(const char *path,const char *name, const char *group) { STD_ASSERT(path!=nullptr && name!=nullptr); size_t sz = get_estimated_buff(_SC_GETPW_R_SIZE_MAX); std::unique_ptr<char[]> b(new char [sz]); if (b.get()==nullptr) return STD_ERR(COM,NOMEM,0); struct passwd pass, *_pass=nullptr; if (getpwnam_r(name,&pass,b.get(),sz,&_pass)!=0 || _pass==nullptr) { EV_LOG(ERR,COM,0,"COM-USER-PERM","No such user %s",name); return STD_ERR(COM,FAIL,errno); } uid_t uid = _pass->pw_uid; gid_t gid = -1; if (group!=nullptr) { sz = get_estimated_buff(_SC_GETGR_R_SIZE_MAX); b = std::unique_ptr<char[]>(new char [sz]); struct group grp,*pgrp=nullptr; if (getgrnam_r(group,&grp,b.get(),sz,&pgrp)!=0 || pgrp==nullptr) { EV_LOG(ERR,COM,0,"COM-USER-PERM","No such group %s",group); return STD_ERR(COM,FAIL,errno); } gid = pgrp->gr_gid; } if (chown(path,uid,gid)!=0) { return STD_ERR(COM,FAIL,errno); } return STD_ERR_OK; }
bool derived_obj_t::push_leaf_attr_to_npu (nas_attr_id_t attr_id, npu_id_t npu_id) { t_std_error rc = STD_ERR_OK; switch (attr_id) { case BASE_UT_ATTR1: if ((rc = ndi_ut_obj_attr1_set (npu_id, ndi_obj_id(npu_id), attr1())) != STD_ERR_OK) { throw nas::base_exception {rc, __PRETTY_FUNCTION__, std::string {"NDI Fail: Set Attr1 in NPU "} + std::to_string (npu_id)}; } break; case BASE_UT_ATTR2: if ((rc = ndi_ut_obj_attr2_set (npu_id, ndi_obj_id(npu_id), attr2())) != STD_ERR_OK) { throw nas::base_exception {rc, __PRETTY_FUNCTION__, std::string {"NDI Fail: Set Attr2 in NPU "} + std::to_string (npu_id)}; } break; default: STD_ASSERT (0); } return true; }
/** * Export gpio pin, * Initialize gpio file table with file handle for gpio sysfs * file: value, direction and active_lowi for the gpio pin, * Initialize the gpio pin with default configuration * param[in] bus_hdl - gpio pin handle * return STD_ERR_OK on success, SDI_DEVICE_ERRNO on error. */ static t_std_error sdi_gpio_driver_init(sdi_bus_hdl_t bus_hdl) { sdi_gpio_pin_t *gpio_pin = (sdi_gpio_pin_t *) bus_hdl; t_std_error err = STD_ERR_OK; uint_t gpio_no = 0; STD_ASSERT(gpio_pin != NULL); gpio_no = gpio_pin->gpio_num; err = sdi_export_gpio(gpio_no); if (err != STD_ERR_OK) { return err; } err = sdi_gpio_file_table_init(gpio_no, gpio_pin->gpio_file_tbl); if (err != STD_ERR_OK) { return err; } err = sdi_gpio_default_configuration_set(gpio_pin); if (err != STD_ERR_OK) { return err; } sdi_bus_init_device_list(bus_hdl); return err; }
/** * Write value of the Pin Group * param[in] bus_hdl - gpio pin bus handle * param[in] value - level to be configured in given gpio pin group * return STD_ERR_OK on success, SDI_DEVICE_ERRNO on failure */ static t_std_error sdi_gpio_group_level_write(sdi_pin_group_bus_hdl_t bus_hdl, uint_t value) { sdi_gpio_group_t *gpio_group_hdl = (sdi_gpio_group_t *) bus_hdl; /* bus_hdl is already validated by its caller (sdi_pin_group_write_level) */ uint_t *gpio_group = gpio_group_hdl->gpio_group; uint_t gpio_index = 0; uint_t gpio_cnt = gpio_group_hdl->gpio_count; sdi_pin_bus_level_t gpio_level = SDI_PIN_LEVEL_LOW; t_std_error err = STD_ERR_OK; sdi_gpio_file_fd_tbl_t *gpio_file_tbl = NULL; STD_ASSERT((value < (1 << gpio_cnt))); for (gpio_index = 0; gpio_index < gpio_cnt; gpio_index++) { if (value & ((gpio_cnt - gpio_index ))) { gpio_level = SDI_PIN_LEVEL_HIGH; } else { gpio_level = SDI_PIN_LEVEL_LOW; } gpio_file_tbl = gpio_group_hdl->gpio_file_tbl[gpio_index]; err = sdi_sysfs_gpio_value_write(gpio_file_tbl->level_fd, gpio_level); if (err != STD_ERR_OK) { SDI_DEVICE_ERRMSG_LOG("%s:%d Bus %s GPIO %u level can't be set to %d, err: %d\n", __FUNCTION__, __LINE__, bus_hdl->bus.bus_name, gpio_group[gpio_index], gpio_level, err); return err; } } return err; }
t_std_error ndi_del_ports_from_vlan(npu_id_t npu_id, hal_vlan_id_t vlan_id, \ ndi_port_list_t *p_t_port_list, ndi_port_list_t *p_ut_port_list) { sai_status_t sai_ret = SAI_STATUS_FAILURE; sai_vlan_port_t *p_sai_vlan_port_list = NULL; uint32_t t_port_count = p_t_port_list ? p_t_port_list->port_count : 0 ; uint32_t ut_port_count = p_ut_port_list ? p_ut_port_list->port_count : 0 ; uint32_t port_count = ut_port_count + t_port_count; nas_ndi_db_t *ndi_db_ptr = ndi_db_ptr_get(npu_id); STD_ASSERT(ndi_db_ptr != NULL); p_sai_vlan_port_list = malloc((sizeof(sai_vlan_port_t)) * port_count); if(p_sai_vlan_port_list == NULL) { return STD_ERR(INTERFACE, NOMEM, 0); } memset(p_sai_vlan_port_list, 0, (sizeof(sai_vlan_port_t) * port_count)); ndi_sai_copy_vlan_ports(p_sai_vlan_port_list, p_t_port_list, p_ut_port_list); if((sai_ret = ndi_sai_vlan_api(ndi_db_ptr)->remove_ports_from_vlan((sai_vlan_id_t)vlan_id, port_count, p_sai_vlan_port_list)) != SAI_STATUS_SUCCESS) { free(p_sai_vlan_port_list); return STD_ERR(INTERFACE, CFG, sai_ret); } free(p_sai_vlan_port_list); return STD_ERR_OK; }
/* Generate element by const value */ AstElement* generate_const_to_element(Lang* context, Value val) { char output[64]; AstElement* element = context->syntax_create_element(); element->is_constant = true; element->type = val.m_type; switch (val.m_type) { case INTEGER: int64_to_string(output, sizeof(output), val.m_int, 10, 1, 0); element->output = output; break; case REAL: snprintf(output, sizeof(output), "%.12g", (double)val.m_real); element->output = output; break; case STRING: element->output = val.m_string; break; default: /* can not be herer */ STD_ASSERT(0); } return element; }
/** * This API will turn-off the LED and it needs to be used on LEDs which are * driving on pin group bus * * resource_hdl[in] - handle of the led * * return t_std_error */ t_std_error sdi_mono_color_pin_group_led_sensor_off (void *resource_hdl) { sdi_device_hdl_t dev_hdl = NULL; mono_color_pin_group_led_t *led = NULL; t_std_error rc = STD_ERR_OK; sdi_pin_group_bus_hdl_t bus_hdl = NULL; STD_ASSERT(resource_hdl != NULL); dev_hdl = (sdi_device_hdl_t) resource_hdl; led = (mono_color_pin_group_led_t *)dev_hdl->private_data; if (led->off_value == SDI_LED_OFF_NOT_SUPPORTED){ return SDI_DEVICE_ERRCODE(EOPNOTSUPP); } bus_hdl = (sdi_pin_group_bus_hdl_t)dev_hdl->bus_hdl; rc = sdi_pin_group_acquire_bus(bus_hdl); if(rc != STD_ERR_OK) { SDI_DEVICE_ERRMSG_LOG("Acquiring lock is failed with errorno : %d", rc); return rc; } rc = sdi_pin_group_write_level(bus_hdl, led->off_value); if (rc != STD_ERR_OK) { SDI_DEVICE_ERRMSG_LOG("Writing the value to pin group bus is failed with rc : %d", rc); } sdi_pin_group_release_bus(bus_hdl); return rc; }
bool nas_acl_table::push_leaf_attr_to_npu (nas_attr_id_t attr_id, npu_id_t npu_id) { t_std_error rc = STD_ERR_OK; switch (attr_id) { case BASE_ACL_TABLE_PRIORITY: if ((rc = ndi_acl_table_set_priority (npu_id, _ndi_obj_ids.at(npu_id), priority())) != STD_ERR_OK) { throw nas::base_exception {rc, __PRETTY_FUNCTION__, std::string {"NDI Fail: Table "} + std::to_string (table_id()) + std::string {" Priority Set Failed for NPU "} + std::to_string (npu_id)}; } NAS_ACL_LOG_DETAIL ("Switch %d: Modified ACL table %ld Priority in NPU %d", get_switch().id(), table_id(), npu_id); break; default: STD_ASSERT (0); } return true; }
extern int std_create_task(const char *name, Vm_task_Id_t *pTaskId, void *entry, void *para) { STD_ASSERT(pTaskId != NULL); STD_ASSERT(entry != NULL); if (! std_multiThreadBoot) STD_FATAL("Can't create any task before multiThreadBoot.\n" "Use std_createTaskSmart() and std_startAllRequestedThreads() instead.\n"); if (pTaskId != NULL) *pTaskId = 0x1255; STD_REFER(para); STD_REFER(name); return 1; }
extern int std_forceReleaseMutex(std_mutex_id_t mutexId) { if (mutexId == STD_NO_MUTEX) /* Return failed for operating empty object */ return 0; /* Not support */ STD_ASSERT(0); return 0; }
/** * This API will turn-on the LED and it needs to be used on LEDs which are * driving on pin-bus * * resource_hdl[in] - handle of the led * * return t_std_error */ t_std_error sdi_mono_color_pin_led_sensor_on (void *resource_hdl) { sdi_device_hdl_t dev_hdl = NULL; STD_ASSERT(resource_hdl != NULL); dev_hdl = (sdi_device_hdl_t) resource_hdl; return sdi_pin_write_level((sdi_pin_bus_hdl_t)dev_hdl->bus_hdl, SDI_PIN_LEVEL_HIGH); }
static t_std_error sdi_pseudo_bus_register (std_config_node_t node, sdi_bus_hdl_t *bus_hdl) { sdi_bus_hdl_t bus = NULL; STD_ASSERT(bus_hdl != NULL); bus = (sdi_bus_hdl_t) calloc(sizeof(sdi_bus_t), 1); STD_ASSERT(bus != NULL); bus->bus_type = SDI_PSEUDO_BUS; bus->bus_id = 0; bus->bus_init = sdi_pseudo_bus_init; safestrncpy(bus->bus_name, std_config_name_get(node), SDI_MAX_NAME_LEN); sdi_bus_register(bus); *bus_hdl = bus; sdi_bus_register_device_list(node, bus); return STD_ERR_OK; }
/* Initialize a critical section */ extern void std_init_critical_section(std_critical_section_t *pSection) { pthread_mutexattr_t attr; STD_ASSERT(pSection != NULL); pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutex_init(&pSection->section, &attr); pthread_mutexattr_destroy(&attr); }
void nas_acl_table::allowed_filters_c_cpy (size_t filter_count, BASE_ACL_MATCH_TYPE_t* filter_list) const noexcept { size_t count = 0; for (auto filter: _allowed_filters) { filter_list[count] = filter; count++; } STD_ASSERT (count <= filter_count); }
/* * Write a byte of data to a specified address. * param[in] bus_hdl - Bus handle on which port data to be written is attached. * param[in] addr - Port address * param[in] buffer - Data to be written to port offset address * return STD_ERR_OK for success and the respective error code in case of failure. */ t_std_error sdi_io_write_byte(sdi_bus_hdl_t bus_hdl, uint16_t addr, uint8_t buffer) { t_std_error rc = STD_ERR_OK; STD_ASSERT(bus_hdl != NULL); STD_ASSERT(bus_hdl->bus_type == SDI_IO_BUS); /** * @todo: needs to set the permission as part of device init */ rc = ioperm(addr, BYTE_SIZE, IO_PORT_PERM_ENABLE); if (rc != STD_ERR_OK) { SDI_ERRMSG_LOG("%s:%d IO Permission %s failed with error %d\n", __FUNCTION__, __LINE__, bus_hdl->bus_name, rc); return rc; } outb(buffer, addr); return rc; }
void Simulator::xLDMULX() { GET_P1; GET_P2; GET_P3; // P1 must be local for LDMULX STD_ASSERT(("p1 must be local variables for LDMULX.\n", m_this_code->t1 == Instruction::LOCAL)); if (m_this_code->p1 + p3->m_int > m_localn) throw_error("Overflow when copy values (%lld) to local (offset = %lld).\n", (Int64)p3->m_int, (Int64)m_this_code->p1); memcpy(p1, p2, sizeof(Value) * p3->m_int); }
// Invoke a function in program // ATTENTION: args[0..n) should be in local stack (see call_other) Value Program::invoke(Thread* thread, ObjectId oid, const Value& function_name, Value* args, ArgNo n) const { CalleeInfo callee; // Make sure args in local stack ([0..64K] from &thread) STD_ASSERT(!args || (void*)args > (void*)&thread); STD_ASSERT(!args || (char*)args - (char*)&thread < 65536); if (function_name.m_type != ValueType::STRING) // Bad type of function name return NIL; if (!get_public_callee_by_name((String*)&function_name, &callee)) // No such function return NIL; if (!thread->try_switch_object_by_id(thread, oid, args, n, Thread::get_stack_pointer_func()())) // The object is not existed or just destructed return NIL; // Call auto* object = Object::get_object_by_id(oid); auto component_no = callee.component_no; ComponentOffset offset = m_components[component_no].offset; auto* component_impl = (AbstractComponent*)(((Uint8*)object) + offset); Function::ScriptEntry func = callee.function->m_entry.script_entry; thread->push_call_context(object, callee.function, args, n, component_no); // Push domain context with first argument as start_sp since when do GC, wo need to // scan all arguments // ATTENTION: When program executed here, it should push all registeres before calling // this routine into stack(>=stack pointer). Since the GC will trace all root pointers // in local stack. It will lose root if any registered was not saved now. thread->push_domain_context(args + n); thread->get_current_domain()->check_gc(); // Check target domain GC after copied arguments Value other_ret = (component_impl->*func)(thread, args, n); Value this_ret = thread->pop_domain_context(other_ret); thread->pop_call_context(); thread->get_current_domain()->check_gc(); // Check source domain GC after copied return value return this_ret; // Return value was in this_ret }