value_t assembler_flush(assembler_t *assm) { // Copy the bytecode into a blob object. blob_t code_blob; short_buffer_flush(&assm->code, &code_blob); TRY_DEF(bytecode, new_heap_blob_with_data(assm->runtime, &code_blob)); // Invert the constant pool map into an array. value_t value_pool_map = assm->value_pool; size_t value_pool_size = get_id_hash_map_size(value_pool_map); TRY_DEF(value_pool, new_heap_array(assm->runtime, value_pool_size)); id_hash_map_iter_t iter; id_hash_map_iter_init(&iter, value_pool_map); size_t entries_seen = 0; while (id_hash_map_iter_advance(&iter)) { value_t key; value_t value; id_hash_map_iter_get_current(&iter, &key, &value); size_t index = get_integer_value(value); // Check that the entry hasn't been set already. CHECK_PHYLUM(tpNull, get_array_at(value_pool, index)); set_array_at(value_pool, index, key); entries_seen++; } CHECK_EQ("wrong number of entries", entries_seen, value_pool_size); return new_heap_code_block(assm->runtime, bytecode, value_pool, assm->high_water_mark); }
// Executes a method declaration on the given fragment. static value_t apply_method_declaration(value_t ambience, value_t decl, value_t fragment) { CHECK_FAMILY(ofMethodDeclarationAst, decl); CHECK_FAMILY(ofModuleFragment, fragment); runtime_t *runtime = get_ambience_runtime(ambience); // Look for the :builtin annotation on this method. value_t annots = get_method_declaration_ast_annotations(decl); value_t builtin_name = new_not_found_condition(); for (size_t i = 0; i < get_array_length(annots); i++) { value_t annot = get_array_at(annots, i); TRY_DEF(value, run_expression_until_condition(ambience, fragment, annot)); if (in_family(ofBuiltinMarker, value)) builtin_name = get_builtin_marker_name(value); } // Compile the method whether it's a builtin or not. This way we can reuse // the compilation code for both cases and just patch up the result after // the fact if it's a builtin. value_t method_ast = get_method_declaration_ast_method(decl); TRY_DEF(method, compile_method_ast_to_method(runtime, method_ast, fragment)); if (!in_condition_cause(ccNotFound, builtin_name)) { // This is a builtin so patch the method with the builtin implementation. TRY_DEF(impl, runtime_get_builtin_implementation(runtime, builtin_name)); value_t impl_code = get_builtin_implementation_code(impl); TRY(validate_builtin_method_binding(method, impl)); set_method_code(method, impl_code); value_t impl_flags = get_builtin_implementation_method_flags(impl); set_method_flags(method, impl_flags); } value_t methodspace = get_module_fragment_methodspace(fragment); TRY(add_methodspace_method(runtime, methodspace, method)); return success(); }
static value_t init_empty_module_fragment(runtime_t *runtime, value_t fragment) { TRY_DEF(nspace, new_heap_namespace(runtime, nothing())); TRY_DEF(methodspace, new_heap_methodspace(runtime)); TRY_DEF(imports, new_heap_id_hash_map(runtime, 16)); set_module_fragment_namespace(fragment, nspace); set_module_fragment_methodspace(fragment, methodspace); set_module_fragment_imports(fragment, imports); return success(); }
value_t new_heap_array_buffer(runtime_t *runtime, size_t initial_capacity) { size_t size = kArrayBufferSize; TRY_DEF(elements, new_heap_array(runtime, initial_capacity)); TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, mutable_array_buffer_species))); set_array_buffer_elements(result, elements); set_array_buffer_length(result, 0); return post_create_sanity_check(result, size); }
value_t new_heap_mutable_roots(runtime_t *runtime) { TRY_DEF(argument_map_trie_root, new_heap_argument_map_trie(runtime, ROOT(runtime, empty_array))); size_t size = kMutableRootsSize; TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, mutable_mutable_roots_species))); RAW_MROOT(result, argument_map_trie_root) = argument_map_trie_root; return result; }
// Executes an is declaration on the given fragment. static value_t apply_is_declaration(runtime_t *runtime, value_t decl, value_t fragment) { CHECK_FAMILY(ofIsDeclarationAst, decl); CHECK_FAMILY(ofModuleFragment, fragment); value_t subtype_ast = get_is_declaration_ast_subtype(decl); value_t supertype_ast = get_is_declaration_ast_supertype(decl); TRY_DEF(subtype, quick_and_dirty_evaluate_syntax(runtime, fragment, subtype_ast)); TRY_DEF(supertype, quick_and_dirty_evaluate_syntax(runtime, fragment, supertype_ast)); value_t methodspace = get_module_fragment_methodspace(fragment); TRY(add_methodspace_inheritance(runtime, methodspace, subtype, supertype)); return success(); }
value_t build_bound_module(value_t ambience, value_t unbound_module) { runtime_t *runtime = get_ambience_runtime(ambience); binding_context_t context; binding_context_init(&context, ambience); TRY_SET(context.bound_module_map, new_heap_id_hash_map(runtime, 16)); TRY_DEF(modules, build_transitive_module_array(runtime, unbound_module)); TRY(build_fragment_entry_map(&context, modules)); TRY_DEF(schedule, build_binding_schedule(&context)); TRY(execute_binding_schedule(&context, schedule)); value_t path = get_unbound_module_path(unbound_module); value_t result = get_id_hash_map_at(context.bound_module_map, path); CHECK_FALSE("module missing", in_condition_cause(ccNotFound, result)); return result; }
// Adds a namespace binding based on the given declaration ast in the given // fragment's namespace. static value_t apply_namespace_declaration(value_t ambience, value_t decl, value_t fragment) { CHECK_FAMILY(ofAmbience, ambience); CHECK_FAMILY(ofNamespaceDeclarationAst, decl); CHECK_FAMILY(ofModuleFragment, fragment); runtime_t *runtime = get_ambience_runtime(ambience); value_t value_syntax = get_namespace_declaration_ast_value(decl); TRY_DEF(code_block, compile_expression(runtime, value_syntax, fragment, scope_get_bottom())); TRY_DEF(value, run_code_block_until_condition(ambience, code_block)); value_t nspace = get_module_fragment_namespace(fragment); value_t path = get_namespace_declaration_ast_path(decl); TRY(set_namespace_binding_at(runtime, nspace, path, value)); return success(); }
value_t build_binding_schedule(binding_context_t *context) { runtime_t *runtime = get_ambience_runtime(context->ambience); TRY_DEF(schedule, new_heap_array_buffer(runtime, 16)); TRY_DEF(all_fragments, build_fragment_identifier_array(context)); loop: do { for (size_t i = 0; i < get_array_buffer_length(all_fragments); i++) { value_t ident = get_array_buffer_at(all_fragments, i); if (should_fragment_be_bound(context, schedule, ident)) { TRY(add_to_array_buffer(runtime, schedule, ident)); goto loop; } } } while (false); return schedule; }
static value_t run_expression_until_condition(value_t ambience, value_t fragment, value_t expr) { runtime_t *runtime = get_ambience_runtime(ambience); TRY_DEF(code_block, compile_expression(runtime, expr, fragment, scope_get_bottom())); return run_code_block_until_condition(ambience, code_block); }
// Creates a new empty but suitably initialized bound module fragment. static value_t new_empty_module_fragment(runtime_t *runtime, value_t stage, value_t module) { TRY_DEF(empty_fragment, new_heap_module_fragment(runtime, module, stage, nothing(), nothing(), nothing())); TRY(init_empty_module_fragment(runtime, empty_fragment)); return empty_fragment; }
value_t new_heap_pair(runtime_t *runtime, value_t e0, value_t e1) { TRY_DEF(result, new_heap_array(runtime, 2)); set_array_at(result, 0, e0); set_array_at(result, 1, e1); TRY(ensure_frozen(runtime, result)); return result; }
value_t new_heap_reference(runtime_t *runtime, value_t value) { size_t size = kReferenceSize; TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, mutable_reference_species))); set_reference_value(result, value); return post_create_sanity_check(result, size); }
value_t new_heap_uninitialized_roots(runtime_t *runtime) { size_t size = kRootsSize; TRY_DEF(result, alloc_heap_object(runtime, size, whatever())); for (size_t i = 0; i < kRootCount; i++) *access_heap_object_field(result, HEAP_OBJECT_FIELD_OFFSET(i)) = whatever(); return result; }
// Builds an array buffer containing all the modules that are needed to load // the given unbound module (which is itself added to the array too). static value_t build_transitive_module_array(runtime_t *runtime, value_t unbound_module) { CHECK_FAMILY(ofUnboundModule, unbound_module); TRY_DEF(result, new_heap_array_buffer(runtime, 16)); TRY(ensure_module_in_array(runtime, result, unbound_module)); return result; }
value_t new_heap_string(runtime_t *runtime, string_t *contents) { size_t size = calc_string_size(string_length(contents)); TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, string_species))); set_string_length(result, string_length(contents)); string_copy_to(contents, get_string_chars(result), string_length(contents) + 1); return post_create_sanity_check(result, size); }
value_t new_heap_array(runtime_t *runtime, size_t length) { size_t size = calc_array_size(length); TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, mutable_array_species))); set_array_length(result, length); for (size_t i = 0; i < length; i++) set_array_at(result, i, null()); return post_create_sanity_check(result, size); }
value_t new_heap_array_buffer_with_contents(runtime_t *runtime, value_t elements) { CHECK_FAMILY(ofArray, elements); size_t size = kArrayBufferSize; TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, mutable_array_buffer_species))); set_array_buffer_elements(result, elements); set_array_buffer_length(result, get_array_length(elements)); return post_create_sanity_check(result, size); }
value_t new_heap_triple(runtime_t *runtime, value_t e0, value_t e1, value_t e2) { TRY_DEF(result, new_heap_array(runtime, 3)); set_array_at(result, 0, e0); set_array_at(result, 1, e1); set_array_at(result, 2, e2); TRY(ensure_frozen(runtime, result)); return result; }
value_t new_heap_compact_species(runtime_t *runtime, family_behavior_t *behavior) { size_t bytes = kCompactSpeciesSize; TRY_DEF(result, alloc_heap_object(runtime, bytes, ROOT(runtime, mutable_species_species))); set_species_instance_family(result, behavior->family); set_species_family_behavior(result, behavior); set_species_division_behavior(result, &kCompactSpeciesBehavior); return post_create_sanity_check(result, bytes); }
value_t new_heap_blob_with_data(runtime_t *runtime, blob_t *contents) { // Allocate the blob object to hold the data. TRY_DEF(blob, new_heap_blob(runtime, blob_byte_length(contents))); // Pull out the contents of the heap blob. blob_t blob_data; get_blob_data(blob, &blob_data); // Copy the contents into the heap blob. blob_copy_to(contents, &blob_data); return blob; }
value_t new_heap_blob(runtime_t *runtime, size_t length) { size_t size = calc_blob_size(length); TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, blob_species))); set_blob_length(result, length); blob_t data; get_blob_data(result, &data); blob_fill(&data, 0); return post_create_sanity_check(result, size); }
// Runs the given stack until it hits a condition or completes successfully. static value_t run_stack_until_condition(value_t ambience, value_t stack) { value_t result = run_stack_pushing_signals(ambience, stack); if (in_condition_cause(ccSignal, result)) { runtime_t *runtime = get_ambience_runtime(ambience); frame_t frame = open_stack(stack); TRY_DEF(trace, capture_backtrace(runtime, &frame)); print_ln("%9v", trace); } return result; }
// Checks whether a fragment entry for the given stage and path already exists // and if not creates it. static value_t binding_context_ensure_fragment_entry(binding_context_t *context, value_t stage, value_t path, value_t fragment, bool *created) { CHECK_PHYLUM(tpStageOffset, stage); CHECK_FAMILY(ofPath, path); CHECK_FAMILY_OPT(ofUnboundModuleFragment, fragment); value_t path_map = context->fragment_entry_map; runtime_t *runtime = get_ambience_runtime(context->ambience); if (!has_id_hash_map_at(path_map, path)) { TRY_DEF(stage_map, new_heap_id_hash_map(runtime, 16)); TRY(set_id_hash_map_at(runtime, path_map, path, stage_map)); } value_t stage_map = get_id_hash_map_at(path_map, path); if (!has_id_hash_map_at(stage_map, stage)) { TRY_DEF(imports, new_heap_array_buffer(runtime, 4)); TRY_DEF(ident, new_heap_identifier(runtime, stage, path)); TRY_DEF(entry, new_heap_triple(runtime, fragment, imports, ident)); TRY(set_id_hash_map_at(runtime, stage_map, stage, entry)); *created = true; } return get_id_hash_map_at(stage_map, stage); }
// Reads a library from the given library path and adds the modules to this // loaders set of available modules. static value_t module_loader_read_library(runtime_t *runtime, value_t self, value_t library_path) { // Read the library from the file. string_t library_path_str; get_string_contents(library_path, &library_path_str); TRY_DEF(data, read_file_to_blob(runtime, &library_path_str)); TRY_DEF(library, runtime_plankton_deserialize(runtime, data)); if (!in_family(ofLibrary, library)) return new_invalid_input_condition(); set_library_display_name(library, library_path); // Load all the modules from the library into this module loader. id_hash_map_iter_t iter; id_hash_map_iter_init(&iter, get_library_modules(library)); while (id_hash_map_iter_advance(&iter)) { value_t key; value_t value; id_hash_map_iter_get_current(&iter, &key, &value); TRY(set_id_hash_map_at(runtime, get_module_loader_modules(self), key, value)); } return success(); }
value_t new_heap_modal_species_unchecked(runtime_t *runtime, family_behavior_t *behavior, value_mode_t mode, root_key_t base_root) { size_t size = kModalSpeciesSize; TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, mutable_species_species))); set_species_instance_family(result, behavior->family); set_species_family_behavior(result, behavior); set_species_division_behavior(result, &kModalSpeciesBehavior); set_modal_species_mode(result, mode); set_modal_species_base_root(result, base_root); return result; }
value_t new_heap_instance_species(runtime_t *runtime, value_t primary, value_t manager) { size_t size = kInstanceSpeciesSize; CHECK_FAMILY(ofType, primary); CHECK_FAMILY_OPT(ofInstanceManager, manager); TRY_DEF(result, alloc_heap_object(runtime, size, ROOT(runtime, mutable_species_species))); set_species_instance_family(result, ofInstance); set_species_family_behavior(result, &kInstanceBehavior); set_species_division_behavior(result, &kInstanceSpeciesBehavior); set_instance_species_primary_type_field(result, primary); set_instance_species_manager(result, manager); return post_create_sanity_check(result, size); }
// Given an array of modules map builds a two-level map from paths to stages to // fragment entries. static value_t build_real_fragment_entries(binding_context_t *context, value_t modules) { runtime_t *runtime = get_ambience_runtime(context->ambience); for (size_t mi = 0; mi < get_array_buffer_length(modules); mi++) { value_t module = get_array_buffer_at(modules, mi); value_t path = get_unbound_module_path(module); value_t fragments = get_unbound_module_fragments(module); for (size_t fi = 0; fi < get_array_length(fragments); fi++) { value_t fragment = get_array_at(fragments, fi); value_t stage = get_unbound_module_fragment_stage(fragment); bool dummy = false; TRY_DEF(entry, binding_context_ensure_fragment_entry(context, stage, path, fragment, &dummy)); value_t imports = get_fragment_entry_imports(entry); value_t fragment_imports = get_unbound_module_fragment_imports(fragment); for (size_t ii = 0; ii < get_array_length(fragment_imports); ii++) { value_t import = get_array_at(fragment_imports, ii); TRY_DEF(ident, new_heap_identifier(runtime, present_stage(), import)); TRY(ensure_array_buffer_contains(runtime, imports, ident)); } } } return success(); }
value_t build_call_tags_entries(runtime_t *runtime, value_t tags) { int64_t tag_count = get_array_length(tags); TRY_DEF(result, new_heap_pair_array(runtime, tag_count)); for (int64_t i = 0; i < tag_count; i++) { set_pair_array_first_at(result, i, get_array_at(tags, i)); // The offset is counted backwards because the argument evaluated last will // be at the top of the stack, that is, offset 0, and the first will be at // the bottom so has the highest offset. int64_t offset = tag_count - i - 1; set_pair_array_second_at(result, i, new_integer(offset)); } TRY(co_sort_pair_array(result)); IF_EXPENSIVE_CHECKS_ENABLED(check_call_tags_entries_unique(result)); return result; }
static value_t create_methodspace_selector_slice(runtime_t *runtime, value_t self, value_t selector) { TRY_DEF(result, new_heap_signature_map(runtime)); value_t current = self; while (!is_nothing(current)) { value_t methods = get_methodspace_methods(current); value_t entries = get_signature_map_entries(methods); for (int64_t i = 0; i < get_pair_array_buffer_length(entries); i++) { value_t signature = get_pair_array_buffer_first_at(entries, i); if (can_match_eq(signature, ROOT(runtime, selector_key), selector)) { value_t method = get_pair_array_buffer_second_at(entries, i); TRY(add_to_signature_map(runtime, result, signature, method)); } } current = get_methodspace_parent(current); } return result; }