diff --git a/src/compiler/propagation/concrete_type.h b/src/compiler/propagation/concrete_type.h index 7e6f56824..03b15dad6 100644 --- a/src/compiler/propagation/concrete_type.h +++ b/src/compiler/propagation/concrete_type.h @@ -35,6 +35,9 @@ class ConcreteType { explicit ConcreteType(unsigned id) : data_((id << 1) | 1) {} + explicit ConcreteType(BlockTemplate* block) + : data_(reinterpret_cast(block)) {} + static ConcreteType any() { return ConcreteType(); } bool is_block() const { @@ -72,11 +75,6 @@ class ConcreteType { uword data_; ConcreteType() : data_(ANY) {} - - explicit ConcreteType(BlockTemplate* block) - : data_(reinterpret_cast(block)) {} - - friend class BlockTemplate; }; } // namespace toit::compiler diff --git a/src/compiler/propagation/type_primitive_encoding.cc b/src/compiler/propagation/type_primitive_encoding.cc index f68b10a08..69fed52af 100644 --- a/src/compiler/propagation/type_primitive_encoding.cc +++ b/src/compiler/propagation/type_primitive_encoding.cc @@ -22,8 +22,13 @@ MODULE_TYPES(encoding, MODULE_ENCODING) TYPE_PRIMITIVE_ANY(base64_encode) TYPE_PRIMITIVE_ANY(base64_decode) -TYPE_PRIMITIVE_ANY(tison_encode) TYPE_PRIMITIVE_ANY(tison_decode) +TYPE_PRIMITIVE(tison_encode) { + result.add_byte_array(program); + failure.add_string(program); + failure.add_array(program); +} + } // namespace toit::compiler } // namespace toit diff --git a/src/compiler/propagation/type_primitive_programs_registry.cc b/src/compiler/propagation/type_primitive_programs_registry.cc index 895f6f66c..7ec1c41a3 100644 --- a/src/compiler/propagation/type_primitive_programs_registry.cc +++ b/src/compiler/propagation/type_primitive_programs_registry.cc @@ -21,12 +21,17 @@ namespace compiler { MODULE_TYPES(programs_registry, MODULE_PROGRAMS_REGISTRY) TYPE_PRIMITIVE_ANY(next_group_id) -TYPE_PRIMITIVE_ANY(spawn) TYPE_PRIMITIVE_ANY(is_running) TYPE_PRIMITIVE_ANY(kill) TYPE_PRIMITIVE_ANY(bundled_images) TYPE_PRIMITIVE_ANY(assets) TYPE_PRIMITIVE_ANY(config) +TYPE_PRIMITIVE(spawn) { + result.add_smi(program); + failure.add_string(program); + failure.add_array(program); +} + } // namespace toit::compiler } // namespace toit diff --git a/src/compiler/propagation/type_propagator.cc b/src/compiler/propagation/type_propagator.cc index e27166fcb..355060ac2 100644 --- a/src/compiler/propagation/type_propagator.cc +++ b/src/compiler/propagation/type_propagator.cc @@ -79,7 +79,9 @@ void TypePropagator::ensure_entry_main() { TypeStack* stack = scope.top(); stack->push_instance(Smi::value(program()->task_class_id())); Method target = program()->entry_main(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_entry_main_ = true; } @@ -89,7 +91,9 @@ void TypePropagator::ensure_entry_spawn() { TypeStack* stack = scope.top(); stack->push_instance(Smi::value(program()->task_class_id())); Method target = program()->entry_spawn(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_entry_spawn_ = true; } @@ -99,7 +103,9 @@ void TypePropagator::ensure_entry_task() { TypeStack* stack = scope.top(); stack->push_any(program()); // TODO(kasper): Should be lambda. Method target = program()->entry_task(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_entry_task_ = true; } @@ -113,7 +119,9 @@ void TypePropagator::ensure_lookup_failure() { // to 'lookup_failure' and pass string selectors for those. stack->push_smi(program()); // selector_offset Method target = program()->lookup_failure(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_lookup_failure_ = true; } @@ -127,7 +135,9 @@ void TypePropagator::ensure_as_check_failure() { // 'as_check_failure' and pass string class names for those. stack->push_smi(program()); // bci Method target = program()->as_check_failure(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_as_check_failure_ = true; } @@ -138,7 +148,9 @@ void TypePropagator::ensure_primitive_lookup_failure() { stack->push_smi(program()); // module stack->push_smi(program()); // index Method target = program()->primitive_lookup_failure(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_primitive_lookup_failure_ = true; } @@ -151,7 +163,9 @@ void TypePropagator::ensure_code_failure() { stack->push_smi(program()); // provided stack->push_smi(program()); // bci Method target = program()->code_failure(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_code_failure_ = true; } @@ -161,7 +175,9 @@ void TypePropagator::ensure_program_failure() { TypeStack* stack = scope.top(); stack->push_smi(program()); // bci Method target = program()->program_failure(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_program_failure_ = true; } @@ -179,7 +195,9 @@ void TypePropagator::ensure_run_global_initializer() { stack->push_smi(program()); stack->push_instance(initializer_class_id); Method target = program()->run_global_initializer(); - call_static(null, &scope, null, target); + std::vector worklists; + call_static(null, &scope, null, target, worklists); + ASSERT(worklists.empty()); has_run_global_initializer_ = true; } @@ -382,7 +400,7 @@ void TypePropagator::call_method(MethodTemplate* caller, // and megamorphic types that tend to blow up the analysis. TypeSet type = stack->local(arity - index); if (type.is_block()) { - arguments.push_back(type.block()->pass_as_argument(scope)); + arguments.push_back(ConcreteType(type.block())); call_method(caller, scope, site, target, arguments); arguments.pop_back(); } else if (type.size(words_per_type_) > 5) { @@ -404,11 +422,54 @@ void TypePropagator::call_method(MethodTemplate* caller, } } -void TypePropagator::call_static(MethodTemplate* caller, TypeScope* scope, uint8* site, Method target) { +void TypePropagator::propagate_blocks(MethodTemplate* caller, + TypeScope* scope, + int arity, + std::vector& worklists) { + TypeStack* stack = scope->top(); + int count = 0; + for (int i = 0; i < arity; i++) { + TypeSet type = stack->local(arity - i - 1); + if (!type.is_block()) continue; + BlockTemplate* block = type.block(); + if (scope->is_in_try_block()) block->mark_invoked_from_try_block(); + count++; + } + + // Propagate types through all locally-defined block arguments. + // We cannot handle block arguments outside of ordinary methods, + // so if the caller isn't set, we analyzing a call to a method from + // an entry stub of sorts. + if (!caller || count == 0) return; + Set blocks; + for (int i = 0; i < arity; i++) { + TypeSet type = stack->local(arity - i - 1); + if (!type.is_block()) continue; + BlockTemplate* block = type.block(); + // The block is our own if it is defined inside the same method as the caller. + bool own = block->origin()->method().header_bcp() == caller->method().header_bcp(); + if (own) blocks.insert(block); + } + + bool changed = !blocks.empty(); + while (changed) { + changed = false; + for (BlockTemplate* block : blocks) { + changed = block->propagate(scope, worklists, block->is_invoked_from_try_block()) || changed; + } + } +} + +void TypePropagator::call_static(MethodTemplate* caller, + TypeScope* scope, + uint8* site, + Method target, + std::vector& worklists) { TypeStack* stack = scope->top(); int arity = target.arity(); if (site) add_input(site, stack, arity); + propagate_blocks(caller, scope, arity, worklists); std::vector arguments; stack->push_empty(); @@ -475,11 +536,17 @@ void TypePropagator::call_static(MethodTemplate* caller, TypeScope* scope, uint8 stack->drop_arguments(target.arity()); } -void TypePropagator::call_virtual(MethodTemplate* caller, TypeScope* scope, uint8* site, int arity, word offset) { +void TypePropagator::call_virtual(MethodTemplate* caller, + TypeScope* scope, + uint8* site, + int arity, + word offset, + std::vector& worklists) { TypeStack* stack = scope->top(); TypeSet receiver = stack->local(arity - 1); if (site) add_input(site, stack, arity); + propagate_blocks(caller, scope, arity, worklists); std::vector arguments; stack->push_empty(); @@ -506,7 +573,12 @@ void TypePropagator::call_virtual(MethodTemplate* caller, TypeScope* scope, uint stack->drop_arguments(arity); } -void TypePropagator::call_block(TypeScope* scope, uint8* site, int arity) { +void TypePropagator::call_block(TypeScope* scope, + uint8* site, + int arity, + bool linked, + bool own, + std::vector& worklists) { TypeStack* stack = scope->top(); TypeSet receiver = stack->local(arity - 1); BlockTemplate* block = receiver.block(); @@ -526,6 +598,13 @@ void TypePropagator::call_block(TypeScope* scope, uint8* site, int arity) { } } + if (arity >= block->arity() && own) { + // TODO(kasper): No need to merge it back here. We just want to continue with + // the current scope. We'll probably need to return the scope from call_block + // to make that happen - or overwrite in the passed in scope. + block->propagate(scope, worklists, linked || block->is_invoked_from_try_block()); + } + // Drop the arguments from the stack. for (int i = 0; i < arity; i++) stack->pop(); @@ -545,20 +624,16 @@ void TypePropagator::call_block(TypeScope* scope, uint8* site, int arity) { scope->throw_maybe(); } -void TypePropagator::load_block(MethodTemplate* loader, TypeScope* scope, Method method, bool linked, std::vector& worklists) { +void TypePropagator::load_block(MethodTemplate* loader, TypeScope* scope, Method method) { ASSERT(method.is_block_method()); // Finds or creates a block-template for the given block. // The block's parameters are marked such that a change in their type enqueues this // current method template. // Note that the method template is for a specific combination of parameter types. As // such we evaluate the contained blocks independently too. - BlockTemplate* block = find_block(loader, method, scope->level()); - scope->top()->push_block(block); - // If the block might be used in a try-block, we need to know - // so we can correctly merge the type of outer locals. If we're - // not in a try-block, changes to outer locals cannot be seen - // when we unwind, but potentially being in a try block changes that. - block->propagate(scope, worklists, linked || block->is_invoked_from_try_block()); + TypeStack* top = scope->top(); + BlockTemplate* block = find_block(loader, method, scope->level(), top->sp() + 1); + top->push_block(block); } void TypePropagator::load_lambda(TypeScope* scope, Method method) { @@ -723,17 +798,19 @@ MethodTemplate* TypePropagator::find_method(Method target, std::vectorarguments(), true); auto it = blocks_.find(key); BlockTemplate* head = (it != blocks_.end()) ? it->second : null; for (BlockTemplate* candidate = head; candidate; candidate = candidate->next()) { - if (candidate->matches(target, origin)) { + if (candidate->matches(target, level, origin)) { + ASSERT(candidate->sp() == sp); candidate->use(this, origin); return candidate; } } - BlockTemplate* result = new BlockTemplate(head, target, level, words_per_type()); + BlockTemplate* result = new BlockTemplate(head, origin, target, level, sp, words_per_type()); blocks_[key] = result; result->use(this, origin); return result; @@ -889,8 +966,7 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& OPCODE_BEGIN(LOAD_METHOD); Method inner = Method(program->bytecodes, Utils::read_unaligned_uint32(bcp + 1)); if (inner.is_block_method()) { - bool is_inner_linked = bcp[LOAD_METHOD_LENGTH] == LINK; - propagator->load_block(method, scope, inner, is_inner_linked, worklists); + propagator->load_block(method, scope, inner); } else { propagator->load_lambda(scope, inner); } @@ -912,7 +988,7 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& Instance* initializer = Instance::cast(program->global_variables.at(index)); int method_id = Smi::value(initializer->at(INITIALIZER_ID_INDEX)); Method target(program->bytecodes, method_id); - propagator->call_static(method, scope, null, target); + propagator->call_static(method, scope, null, target, worklists); // Merge the initializer result into the global variable. TypeVariable* variable = propagator->global_variable(index); variable->merge(propagator, stack->local(0)); @@ -1041,14 +1117,14 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& OPCODE_BEGIN(INVOKE_STATIC); S_ARG1(offset); Method target(program->bytecodes, program->dispatch_table[offset]); - propagator->call_static(method, scope, bcp, target); + propagator->call_static(method, scope, bcp, target, worklists); if (stack->top_is_empty()) return scope; OPCODE_END(); OPCODE_BEGIN(INVOKE_STATIC_TAIL); S_ARG1(offset); Method target(program->bytecodes, program->dispatch_table[offset]); - propagator->call_static(method, scope, bcp, target); + propagator->call_static(method, scope, bcp, target, worklists); if (stack->top_is_empty()) return scope; if (scope->level() > 0) { TypeSet receiver = stack->get(0); @@ -1063,7 +1139,10 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& OPCODE_BEGIN(INVOKE_BLOCK); B_ARG1(index); - propagator->call_block(scope, bcp, index); + TypeSet receiver = stack->local(index - 1); + BlockTemplate* block = receiver.block(); + bool own = block->origin()->method().header_bcp() == method->method().header_bcp(); + propagator->call_block(scope, bcp, index, linked, own, worklists); if (stack->top_is_empty()) { if (!linked) return scope; // We've just invoked a try-block that is guaranteed @@ -1083,26 +1162,26 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& OPCODE_BEGIN_WITH_WIDE(INVOKE_VIRTUAL, arity); word offset = Utils::read_unaligned_uint16(bcp + 2); - propagator->call_virtual(method, scope, bcp, arity + 1, offset); + propagator->call_virtual(method, scope, bcp, arity + 1, offset, worklists); if (stack->top_is_empty()) return scope; OPCODE_END(); OPCODE_BEGIN(INVOKE_VIRTUAL_GET); word offset = Utils::read_unaligned_uint16(bcp + 1); - propagator->call_virtual(method, scope, bcp, 1, offset); + propagator->call_virtual(method, scope, bcp, 1, offset, worklists); if (stack->top_is_empty()) return scope; OPCODE_END(); OPCODE_BEGIN(INVOKE_VIRTUAL_SET); word offset = Utils::read_unaligned_uint16(bcp + 1); - propagator->call_virtual(method, scope, bcp, 2, offset); + propagator->call_virtual(method, scope, bcp, 2, offset, worklists); if (stack->top_is_empty()) return scope; OPCODE_END(); #define INVOKE_VIRTUAL_BINARY(opcode) \ OPCODE_BEGIN(opcode); \ word offset = program->invoke_bytecode_offset(opcode); \ - propagator->call_virtual(method, scope, bcp, 2, offset); \ + propagator->call_virtual(method, scope, bcp, 2, offset, worklists); \ if (stack->top_is_empty()) return scope; \ OPCODE_END(); @@ -1130,13 +1209,13 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& OPCODE_BEGIN(INVOKE_AT_PUT); word offset = program->invoke_bytecode_offset(INVOKE_AT_PUT); - propagator->call_virtual(method, scope, bcp, 3, offset); + propagator->call_virtual(method, scope, bcp, 3, offset, worklists); if (stack->top_is_empty()) return scope; OPCODE_END(); OPCODE_BEGIN(INVOKE_SIZE); word offset = program->invoke_bytecode_offset(INVOKE_SIZE); - propagator->call_virtual(method, scope, bcp, 1, offset); + propagator->call_virtual(method, scope, bcp, 1, offset, worklists); if (stack->top_is_empty()) return scope; OPCODE_END(); @@ -1330,7 +1409,8 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& // difference encoded in the bytecode. TypeScope* target_scope = scope->copy_lazy(outer); TypeStack* target_top = target_scope->top(); - for (int i = 0; i < height_diff; i++) target_top->pop(); + int delta = target_top->sp() - block.block()->sp(); + for (int i = 0; i < height_diff + delta; i++) target_top->pop(); // Add the copied scope to the correct outer worklist. If we // already have a scope registered for the branch target, we // will merge into it and end up with a superfluous scope. @@ -1367,6 +1447,10 @@ static TypeScope* process(TypeScope* scope, uint8* bcp, std::vector& OPCODE_END(); OPCODE_BEGIN(UNWIND); + // Here we continue unwinding if an exception was thrown, so + // we must make this as a potential throw site to make sure + // any modifications to outer locals are merged back. + scope->throw_maybe(); // If the try-block is guaranteed to cause unwinding, // we avoid analyzing the bytecodes following this one. TypeSet target = stack->local(1); @@ -1509,8 +1593,9 @@ int BlockTemplate::method_id(Program* program) const { return program->absolute_bci_from_bcp(method_.header_bcp()); } -bool BlockTemplate::matches(Method target, MethodTemplate* user) const { +bool BlockTemplate::matches(Method target, int level, MethodTemplate* user) const { if (target.entry() != method_.entry()) return false; + if (level != level_) return false; return ConcreteType::equals(last_user_->arguments(), user->arguments(), true); } @@ -1531,58 +1616,72 @@ TypeSet BlockTemplate::invoke(TypePropagator* propagator, TypeScope* scope, uint for (auto it : users_) propagator->enqueue(it); } if (scope->is_in_try_block()) { - invoke_from_try_block(); + mark_invoked_from_try_block(); } return result_.use(propagator, scope->method(), site); } -void BlockTemplate::invoke_from_try_block() { +void BlockTemplate::mark_invoked_from_try_block() { if (is_invoked_from_try_block_) return; + is_invoked_from_try_block_ = true; + + // If the block hasn't been invoked yet, we wait for it + // to be invoked before we enqueue the surrounding method + // for analysis again. + if (!is_invoked_) return; + // If we find that this block may have been invoked from // within a try-block, we re-analyze the surrounding // method, so we can track stores to outer locals that // may be visible because of caught exceptions or // stopped unwinding. - is_invoked_from_try_block_ = true; for (auto it : users_) { it->propagator()->enqueue(it); } } -void BlockTemplate::propagate(TypeScope* scope, std::vector& worklists, bool linked) { +bool BlockTemplate::propagate(TypeScope* scope, std::vector& worklists, bool linked) { + if (is_analyzing_) { + // TODO(kasper): We're calling a block while we're already analyzing it. + // The current scope can have different types than we have seen when + // entering the block, so we need to merge the types back in and make sure + // we re-analyze the block with the richer types when we get back to + // the place where we started the analysis. This way, we replace the + // recursive analysis with a fixed point iteration. + return false; + } + // We avoid having empty types on the stack while we analyze // block methods by bailing out if this block hasn't been // invoked yet. - if (!is_invoked_) return; - - // TODO(kasper): It feels wasteful to re-analyze blocks that - // do not depend on the outer local types that were updated - // by an inner block (or the blocks themselves). - while (true) { - // We create a lazy copy of the current scope, so it becomes - // easy to track if an inner block has modified the scope. - // This is very close to how we handle loops, so the lazy - // copy ends up corresponding to the lazy copy we create when - // we re-analyze from the beginning of a loop if the loop - // or any nested loop changes local types. - TypeScope* copy = scope->copy_lazy(); - TypeScope* inner = new TypeScope(this, copy, linked); - - ASSERT(level() == static_cast(worklists.size()) - 1); - Worklist worklist(method_.entry(), inner, this); - worklists.push_back(&worklist); - - while (worklist.has_next()) { - Worklist::Item item = worklist.next(); - TypeScope* scope = process(item.scope, item.bcp, worklists); - delete scope; - } + if (!is_invoked_) return false; + is_analyzing_ = true; + + // We create a lazy copy of the current scope, so it becomes + // easy to track if an inner block has modified the scope. + // This is very close to how we handle loops, so the lazy + // copy ends up corresponding to the lazy copy we create when + // we re-analyze from the beginning of a loop if the loop + // or any nested loop changes local types. + TypeScope* copy = scope->copy_lazy(); + TypeScope* inner = new TypeScope(this, copy, linked); + + ASSERT(level() <= static_cast(worklists.size()) - 1); + Worklist worklist(method_.entry(), inner, this); + worklists.push_back(&worklist); - worklists.pop_back(); - bool done = !scope->merge(copy, TypeScope::MERGE_LOCAL); - delete copy; - if (done) return; + while (worklist.has_next()) { + Worklist::Item item = worklist.next(); + TypeScope* scope = process(item.scope, item.bcp, worklists); + delete scope; } + + worklists.pop_back(); + bool result = scope->merge(copy, TypeScope::MERGE_LOCAL); + delete copy; + + is_analyzing_ = false; + return result; } } // namespace toit::compiler diff --git a/src/compiler/propagation/type_propagator.h b/src/compiler/propagation/type_propagator.h index 0d9d2d323..9467c5caf 100644 --- a/src/compiler/propagation/type_propagator.h +++ b/src/compiler/propagation/type_propagator.h @@ -51,11 +51,11 @@ class TypePropagator { void propagate(TypeDatabase* types); - void call_static(MethodTemplate* caller, TypeScope* scope, uint8* site, Method target); - void call_virtual(MethodTemplate* caller, TypeScope* scope, uint8* site, int arity, word offset); - void call_block(TypeScope* scope, uint8* site, int arity); + void call_static(MethodTemplate* caller, TypeScope* scope, uint8* site, Method target, std::vector& worklists); + void call_virtual(MethodTemplate* caller, TypeScope* scope, uint8* site, int arity, word offset, std::vector& worklists); + void call_block(TypeScope* scope, uint8* site, int arity, bool linked, bool own, std::vector& worklists); - void load_block(MethodTemplate* loader, TypeScope* scope, Method method, bool linked, std::vector& worklists); + void load_block(MethodTemplate* loader, TypeScope* scope, Method method); void load_lambda(TypeScope* scope, Method method); void load_field(MethodTemplate* user, TypeStack* stack, uint8* site, int index); @@ -98,10 +98,19 @@ class TypePropagator { std::unordered_map> fields_; std::vector enqueued_; - void call_method(MethodTemplate* caller, TypeScope* scope, uint8* site, Method target, std::vector& arguments); + void call_method(MethodTemplate* caller, + TypeScope* scope, + uint8* site, + Method target, + std::vector& arguments); + + void propagate_blocks(MethodTemplate* caller, + TypeScope* scope, + int arity, + std::vector& worklists); MethodTemplate* find_method(Method target, std::vector arguments); - BlockTemplate* find_block(MethodTemplate* origin, Method method, int level); + BlockTemplate* find_block(MethodTemplate* origin, Method method, int level, int sp); }; class MethodTemplate { @@ -164,10 +173,12 @@ class MethodTemplate { class BlockTemplate { public: - BlockTemplate(BlockTemplate* next, Method method, int level, int words_per_type) + BlockTemplate(BlockTemplate* next, MethodTemplate* origin, Method method, int level, int sp, int words_per_type) : next_(next) + , origin_(origin) , method_(method) , level_(level) + , sp_(sp) , arguments_(static_cast(malloc(method.arity() * sizeof(TypeVariable*)))) , result_(words_per_type) { // TODO(kasper): It is silly that we keep the receiver in here. @@ -185,24 +196,21 @@ class BlockTemplate { } BlockTemplate* next() const { return next_; } + MethodTemplate* origin() const { return origin_; } Method method() const { return method_; } int method_id(Program* program) const; int level() const { return level_; } + int sp() const { return sp_; } int arity() const { return method_.arity(); } TypeVariable* argument(int index) { return arguments_[index]; } bool is_invoked_from_try_block() const { return is_invoked_from_try_block_; } + bool is_analyzing() const { return is_analyzing_; } - bool matches(Method target, MethodTemplate* user) const; + bool matches(Method target, int level, MethodTemplate* user) const; void use(TypePropagator* propagator, MethodTemplate* user); - ConcreteType pass_as_argument(TypeScope* scope) { - // If we pass a block as an argument inside a try-block, we - // conservatively assume that it is going to be invoked. - if (scope->is_in_try_block()) invoke_from_try_block(); - return ConcreteType(this); - } - TypeSet invoke(TypePropagator* propagator, TypeScope* scope, uint8* site); + void mark_invoked_from_try_block(); void ret(TypePropagator* propagator, TypeStack* stack) { TypeSet top = stack->local(0); @@ -210,7 +218,7 @@ class BlockTemplate { stack->pop(); } - void propagate(TypeScope* scope, std::vector& worklists, bool linked); + bool propagate(TypeScope* scope, std::vector& worklists, bool linked); void collect_block(std::unordered_map>* map); @@ -220,13 +228,16 @@ class BlockTemplate { // to handle hash collisions. BlockTemplate* const next_; + MethodTemplate* const origin_; const Method method_; const int level_; + const int sp_; TypeVariable** const arguments_; TypeVariable result_; bool is_invoked_ = false; bool is_invoked_from_try_block_ = false; + bool is_analyzing_ = false; // All users of this block are various invocations of the same method. // These are the surrounding methods that load the block. @@ -237,8 +248,6 @@ class BlockTemplate { // using it to determine if a BlockTemplate can be reused by // another user in the BlockTemplate::matches function. MethodTemplate* last_user_ = null; - - void invoke_from_try_block(); }; } // namespace toit::compiler diff --git a/src/compiler/propagation/type_scope.cc b/src/compiler/propagation/type_scope.cc index 5c60e400d..059cf63ce 100644 --- a/src/compiler/propagation/type_scope.cc +++ b/src/compiler/propagation/type_scope.cc @@ -113,18 +113,20 @@ TypeScope::~TypeScope() { TypeSet TypeScope::load_outer(TypeSet block, int index) { TypeStack* stack = at(block.block()->level()); - return stack->local(index); + int delta = stack->sp() - block.block()->sp(); + return stack->local(index + delta); } void TypeScope::store_outer(TypeSet block, int index, TypeSet value) { int level = block.block()->level(); uword wrapped = wrapped_[level]; TypeStack* stack = unwrap(wrapped); + int delta = stack->sp() - block.block()->sp(); if (!is_copied(wrapped)) { stack = stack->copy(); wrapped_[level] = wrap(stack, true); } - stack->set_local(index, value); + stack->set_local(index + delta, value); } void TypeScope::throw_maybe() { diff --git a/tests/finally-params-test.toit b/tests/finally-params-test.toit index b3fb71b0b..43446c84d 100644 --- a/tests/finally-params-test.toit +++ b/tests/finally-params-test.toit @@ -13,7 +13,7 @@ test0: expect-null exception test1: - // With local. (shifting the try/finally locals. + // With local (shifting the try/finally locals). was-in-finally := false try: null diff --git a/tests/type_propagation/block-local-test.toit b/tests/type_propagation/block-local-test.toit new file mode 100644 index 000000000..14f90b32b --- /dev/null +++ b/tests/type_propagation/block-local-test.toit @@ -0,0 +1,66 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +main: + test-single + test-multi + test-outer + test-recursive + +test-single: + x := null + b := : id x + x = 1 + b.call + +test-multi: + x := null + b := : id x + x = 1 + b.call + x = "hest" + b.call + id x + +test-outer: + x := null + b := : id x + x = "hest" + 8.repeat: + b.call + 2.repeat: + inner := : + x = it + b.call + inner.call 1 + id x + inner.call 2.2 + id x + inner.call true + id x + id x + +test-recursive: + foo 3: 42 + +foo n/int [block]: + x := null + if n == 0: return block.call + foo n - 1: + id x + x = "hest" + c := block.call + // The current block can be invoked with x as an int, + // because of the recursive call to the block. + x = 123 + c += block.call + id x + return 1 + c + unreachable + +id x: + return x + +pick: + return (random 100) < 50 diff --git a/tests/type_propagation/block-test.toit b/tests/type_propagation/block-test.toit index 907e1cb81..e19fead57 100644 --- a/tests/type_propagation/block-test.toit +++ b/tests/type_propagation/block-test.toit @@ -12,6 +12,7 @@ main: test-modify-outer-nested test-recursion test-dead + test-dependent test-simple: x := 0 @@ -106,6 +107,15 @@ test-dead: ignore: it ignore: | x y | 42 +test-dependent: + x := "hest" + y := null + invoke + (: x = y ) + (: y = 42 ) + id x + id y + recursive-null [block]: if pick: return recursive-null: null return block.call @@ -143,5 +153,9 @@ pick: invoke [block]: return block.call +invoke [b1] [b2] -> none: + b1.call + b2.call + invoke x [block]: return block.call x diff --git a/tests/type_propagation/default-arguments-test.toit b/tests/type_propagation/default-arguments-test.toit new file mode 100644 index 000000000..d8bd25d41 --- /dev/null +++ b/tests/type_propagation/default-arguments-test.toit @@ -0,0 +1,41 @@ +// Copyright (C) 2024 Toitware ApS. +// Use of this source code is governed by a Zero-Clause BSD license that can +// be found in the tests/LICENSE file. + +main: + test-default-true --x + test-default-true --x=false + test-default-true --x=true + test-default-true --no-x + test-default-true --x=null + + test-default-false --x + test-default-false --x=false + test-default-false --x=true + test-default-false --no-x + test-default-false --x=null + + test-non-default --x + test-non-default --x=true + test-non-default --no-x + test-non-default --x=false + + test-non-default-non-literal --x + test-non-default-non-literal --x=true + test-non-default-non-literal --no-x + test-non-default-non-literal --x=false + +test-default-true --x/bool=true: + return x + +test-default-false --x/bool=false: + return x + +test-non-default --x/bool=true: + return x + +test-non-default-non-literal --x/bool=gettrue: + return x + +gettrue: + return true diff --git a/tests/type_propagation/finally-test.toit b/tests/type_propagation/finally-test.toit index c3ba4185b..bdfdf2629 100644 --- a/tests/type_propagation/finally-test.toit +++ b/tests/type_propagation/finally-test.toit @@ -7,6 +7,13 @@ main: test-exception test-catchy test-nlb-out-of-try + test-throw-update-in-finally + test-break-update-in-finally + test-break-update-in-finally-block0 + test-break-update-in-finally-block1 + test-break-update-in-finally-block2 + test-break-update-in-finally-block3 + test-break-update-in-finally-nested test-is-exception: return-is-exception @@ -57,6 +64,85 @@ test-nlb-out-of-try: x = null finally: id x +test-throw-update-in-finally: + x := false + invoke-catch: + try: + throw "ugh" + finally: + x = true + id x + +test-break-update-in-finally: + x := false + while true: + try: + break + finally: + x = true + id x + +test-break-update-in-finally-block0: + x := false + while true: + invoke: + try: + break + finally: + x = true + id x + +test-break-update-in-finally-block1: + x := false + while true: + block := (: break) + try: + block.call + finally: + x = true + id x + +test-break-update-in-finally-block2: + x/any := null + while true: + block := (: break) + try: + block.call + finally: + x = true + try: + block.call + finally: + x = false + id x + +test-break-update-in-finally-block3: + x := false + y := null + while true: + block := (: break) + while true: + try: + if pick: block.call + else: break + finally: + x = true + y = x + id x + id y + +test-break-update-in-finally-nested: + x/any := null + while true: + try: + try: + x = 0 + break + finally: + x = true + finally: + x = "horse" + id x id x: return x @@ -66,3 +152,9 @@ pick: invoke [block]: block.call + +invoke-catch [block]: + try: + block.call + finally: + return diff --git a/tests/type_propagation/gold/block-local-test.gold b/tests/type_propagation/gold/block-local-test.gold new file mode 100644 index 000000000..2fb7b4960 --- /dev/null +++ b/tests/type_propagation/gold/block-local-test.gold @@ -0,0 +1,191 @@ +main tests/type_propagation/block-local-test.toit + 0[053] - invoke static test-single tests/type_propagation/block-local-test.toit // {Null_} + 3[041] - pop 1 + 4[053] - invoke static test-multi tests/type_propagation/block-local-test.toit // {Null_} + 7[041] - pop 1 + 8[053] - invoke static test-outer tests/type_propagation/block-local-test.toit // {Null_} + 11[041] - pop 1 + 12[053] - invoke static test-recursive tests/type_propagation/block-local-test.toit // {Null_} + 15[090] - return null S1 0 + +test-single tests/type_propagation/block-local-test.toit + 0[022] - load null + 1[029] - load method [block] in test-single tests/type_propagation/block-local-test.toit + 6[025] - load smi 1 + 7[004] - store local, pop S2 + 9[038] - load block 0 + 11[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 13[090] - return null S3 0 + +[block] in test-single tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {SmallInteger_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{SmallInteger_}] -> {SmallInteger_} + 6[089] - return S1 1 + +test-multi tests/type_propagation/block-local-test.toit + 0[022] - load null + 1[029] - load method [block] in test-multi tests/type_propagation/block-local-test.toit + 6[025] - load smi 1 + 7[004] - store local, pop S2 + 9[038] - load block 0 + 11[055] - invoke block S1 // [[block]] -> {String_|SmallInteger_} + 13[041] - pop 1 + 14[020] - load literal hest + 16[004] - store local, pop S2 + 18[038] - load block 0 + 20[055] - invoke block S1 // [[block]] -> {String_|SmallInteger_} + 22[002] - pop, load local S1 + 24[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_}] -> {String_} + 27[090] - return null S3 0 + +[block] in test-multi tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {String_|SmallInteger_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|SmallInteger_}] -> {String_|SmallInteger_} + 6[089] - return S1 1 + +test-outer tests/type_propagation/block-local-test.toit + 0[022] - load null + 1[029] - load method [block] in test-outer tests/type_propagation/block-local-test.toit + 6[020] - load literal hest + 8[004] - store local, pop S2 + 10[029] - load method [block] in test-outer tests/type_propagation/block-local-test.toit + 15[026] - load smi 8 + 17[038] - load block 1 + 19[058] - invoke virtual repeat // [{SmallInteger_}, [block]] -> {Null_} + 23[040] - pop 2 + 25[029] - load method [block] in test-outer tests/type_propagation/block-local-test.toit + 30[026] - load smi 2 + 32[038] - load block 1 + 34[058] - invoke virtual repeat // [{SmallInteger_}, [block]] -> {Null_} + 38[041] - pop 1 + 39[002] - pop, load local S1 + 41[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 44[090] - return null S3 0 + +[block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {String_|True|float|SmallInteger_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 6[089] - return S1 1 + +[block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 1 // [block] + 3[055] - invoke block S1 // [[block]] -> {String_|True|float|SmallInteger_} + 5[089] - return S1 1 + +[block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-outer tests/type_propagation/block-local-test.toit + 5[038] - load block 0 + 7[025] - load smi 1 + 8[055] - invoke block S2 // [[block], {SmallInteger_}] -> {String_|True|float|SmallInteger_} + 10[002] - pop, load local S3 + 12[005] - load outer S2 // {String_|True|float|SmallInteger_} + 14[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 17[041] - pop 1 + 18[038] - load block 0 + 20[020] - load literal 2.2000000000000001776 + 22[055] - invoke block S2 // [[block], {float}] -> {String_|True|float|SmallInteger_} + 24[002] - pop, load local S3 + 26[005] - load outer S2 // {String_|True|float|SmallInteger_} + 28[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 31[041] - pop 1 + 32[038] - load block 0 + 34[020] - load literal true + 36[055] - invoke block S2 // [[block], {True}] -> {String_|True|float|SmallInteger_} + 38[002] - pop, load local S3 + 40[005] - load outer S2 // {String_|True|float|SmallInteger_} + 42[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 45[004] - store local, pop S1 + 47[089] - return S1 1 + +[block] in [block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + - argument 1: {True|float|SmallInteger_} + 0[017] - load local 3 + 1[005] - load outer S3 // [block] + 3[017] - load local 3 + 4[006] - store outer S2 + 6[002] - pop, load local S3 + 8[005] - load outer S3 // [block] + 10[039] - load outer block 1 // [block] + 12[055] - invoke block S1 // [[block]] -> {String_|True|float|SmallInteger_} + 14[089] - return S1 2 + +test-recursive tests/type_propagation/block-local-test.toit + 0[029] - load method [block] in test-recursive tests/type_propagation/block-local-test.toit + 5[026] - load smi 3 + 7[038] - load block 1 + 9[053] - invoke static foo tests/type_propagation/block-local-test.toit // [{SmallInteger_}, [block]] -> {LargeInteger_|SmallInteger_} + 12[090] - return null S2 0 + +[block] in test-recursive tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[026] - load smi 42 + 2[089] - return S1 1 + +foo tests/type_propagation/block-local-test.toit + - argument 0: {LargeInteger_|SmallInteger_} + - argument 1: [block] + 0[052] - load local, as class, pop 3 - LargeInteger_(25 - 27) // {True} + 2[022] - load null + 3[018] - load local 4 + 4[023] - load smi 0 + 5[062] - invoke eq // [{LargeInteger_|SmallInteger_}, {SmallInteger_}] -> {True|False} + 6[083] - branch if false T15 + 9[017] - load local 3 + 10[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 12[089] - return S2 2 + 15[029] - load method [block] in foo tests/type_propagation/block-local-test.toit + 20[019] - load local 5 + 21[025] - load smi 1 + 22[074] - invoke sub // [{LargeInteger_|SmallInteger_}, {SmallInteger_}] -> {LargeInteger_|SmallInteger_} + 23[038] - load block 1 + 25[053] - invoke static foo tests/type_propagation/block-local-test.toit // [{LargeInteger_|SmallInteger_}, [block]] -> {} + 28[040] - pop 2 + 30[053] - invoke static unreachable /core/exceptions.toit + 33[040] - pop 2 + +[block] in foo tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {String_|Null_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|Null_}] -> {String_|Null_} + 6[002] - pop, load local S2 + 8[020] - load literal hest + 10[006] - store outer S1 + 12[002] - pop, load local S2 + 14[005] - load outer S4 // [block] + 16[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 18[017] - load local 3 + 19[026] - load smi 123 + 21[006] - store outer S1 + 23[002] - pop, load local S0 + 25[018] - load local 4 + 26[005] - load outer S4 // [block] + 28[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 30[073] - invoke add // [{SmallInteger_}, {SmallInteger_}] -> {LargeInteger_|SmallInteger_} + 31[004] - store local, pop S1 + 33[017] - load local 3 + 34[005] - load outer S1 // {SmallInteger_} + 36[053] - invoke static id tests/type_propagation/block-local-test.toit // [{SmallInteger_}] -> {SmallInteger_} + 39[041] - pop 1 + 40[025] - load smi 1 + 41[015] - load local 1 + 42[073] - invoke add // [{SmallInteger_}, {LargeInteger_|SmallInteger_}] -> {LargeInteger_|SmallInteger_} + 43[018] - load local 4 + 44[091] - non-local return 18 + 46[003] - store local S1 + 48[089] - return S1 1 + +id tests/type_propagation/block-local-test.toit + - argument 0: {String_|Null_|True|float|SmallInteger_} + 0[016] - load local 2 + 1[089] - return S1 1 diff --git a/tests/type_propagation/gold/block-local-test.gold-O2 b/tests/type_propagation/gold/block-local-test.gold-O2 new file mode 100644 index 000000000..176a21f06 --- /dev/null +++ b/tests/type_propagation/gold/block-local-test.gold-O2 @@ -0,0 +1,188 @@ +main tests/type_propagation/block-local-test.toit + 0[053] - invoke static test-single tests/type_propagation/block-local-test.toit // {Null_} + 3[041] - pop 1 + 4[053] - invoke static test-multi tests/type_propagation/block-local-test.toit // {Null_} + 7[041] - pop 1 + 8[053] - invoke static test-outer tests/type_propagation/block-local-test.toit // {Null_} + 11[041] - pop 1 + 12[053] - invoke static test-recursive tests/type_propagation/block-local-test.toit // {Null_} + 15[090] - return null S1 0 + +test-single tests/type_propagation/block-local-test.toit + 0[022] - load null + 1[029] - load method [block] in test-single tests/type_propagation/block-local-test.toit + 6[025] - load smi 1 + 7[004] - store local, pop S2 + 9[038] - load block 0 + 11[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 13[090] - return null S3 0 + +[block] in test-single tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {SmallInteger_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{SmallInteger_}] -> {SmallInteger_} + 6[089] - return S1 1 + +test-multi tests/type_propagation/block-local-test.toit + 0[022] - load null + 1[029] - load method [block] in test-multi tests/type_propagation/block-local-test.toit + 6[025] - load smi 1 + 7[004] - store local, pop S2 + 9[038] - load block 0 + 11[055] - invoke block S1 // [[block]] -> {String_|SmallInteger_} + 13[041] - pop 1 + 14[020] - load literal hest + 16[004] - store local, pop S2 + 18[038] - load block 0 + 20[055] - invoke block S1 // [[block]] -> {String_|SmallInteger_} + 22[002] - pop, load local S1 + 24[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_}] -> {String_} + 27[090] - return null S3 0 + +[block] in test-multi tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {String_|SmallInteger_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|SmallInteger_}] -> {String_|SmallInteger_} + 6[089] - return S1 1 + +test-outer tests/type_propagation/block-local-test.toit + 0[022] - load null + 1[029] - load method [block] in test-outer tests/type_propagation/block-local-test.toit + 6[020] - load literal hest + 8[004] - store local, pop S2 + 10[029] - load method [block] in test-outer tests/type_propagation/block-local-test.toit + 15[026] - load smi 8 + 17[038] - load block 1 + 19[058] - invoke virtual repeat // [{SmallInteger_}, [block]] -> {Null_} + 23[040] - pop 2 + 25[029] - load method [block] in test-outer tests/type_propagation/block-local-test.toit + 30[026] - load smi 2 + 32[038] - load block 1 + 34[058] - invoke virtual repeat // [{SmallInteger_}, [block]] -> {Null_} + 38[041] - pop 1 + 39[002] - pop, load local S1 + 41[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 44[090] - return null S3 0 + +[block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {String_|True|float|SmallInteger_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 6[089] - return S1 1 + +[block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 1 // [block] + 3[055] - invoke block S1 // [[block]] -> {String_|True|float|SmallInteger_} + 5[089] - return S1 1 + +[block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-outer tests/type_propagation/block-local-test.toit + 5[038] - load block 0 + 7[025] - load smi 1 + 8[055] - invoke block S2 // [[block], {SmallInteger_}] -> {String_|True|float|SmallInteger_} + 10[002] - pop, load local S3 + 12[005] - load outer S2 // {String_|True|float|SmallInteger_} + 14[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 17[041] - pop 1 + 18[038] - load block 0 + 20[020] - load literal 2.2000000000000001776 + 22[055] - invoke block S2 // [[block], {float}] -> {String_|True|float|SmallInteger_} + 24[002] - pop, load local S3 + 26[005] - load outer S2 // {String_|True|float|SmallInteger_} + 28[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 31[041] - pop 1 + 32[038] - load block 0 + 34[020] - load literal true + 36[055] - invoke block S2 // [[block], {True}] -> {String_|True|float|SmallInteger_} + 38[002] - pop, load local S3 + 40[005] - load outer S2 // {String_|True|float|SmallInteger_} + 42[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|True|float|SmallInteger_}] -> {String_|True|float|SmallInteger_} + 45[004] - store local, pop S1 + 47[089] - return S1 1 + +[block] in [block] in test-outer tests/type_propagation/block-local-test.toit + - argument 0: [block] + - argument 1: {True|float|SmallInteger_} + 0[017] - load local 3 + 1[005] - load outer S3 // [block] + 3[017] - load local 3 + 4[006] - store outer S2 + 6[002] - pop, load local S3 + 8[005] - load outer S3 // [block] + 10[039] - load outer block 1 // [block] + 12[055] - invoke block S1 // [[block]] -> {String_|True|float|SmallInteger_} + 14[089] - return S1 2 + +test-recursive tests/type_propagation/block-local-test.toit + 0[029] - load method [block] in test-recursive tests/type_propagation/block-local-test.toit + 5[026] - load smi 3 + 7[038] - load block 1 + 9[053] - invoke static foo tests/type_propagation/block-local-test.toit // [{SmallInteger_}, [block]] -> {LargeInteger_|SmallInteger_} + 12[090] - return null S2 0 + +[block] in test-recursive tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[026] - load smi 42 + 2[089] - return S1 1 + +foo tests/type_propagation/block-local-test.toit + - argument 0: {LargeInteger_|SmallInteger_} + - argument 1: [block] + 0[022] - load null + 1[018] - load local 4 + 2[023] - load smi 0 + 3[062] - invoke eq // [{LargeInteger_|SmallInteger_}, {SmallInteger_}] -> {True|False} + 4[083] - branch if false T13 + 7[017] - load local 3 + 8[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 10[089] - return S2 2 + 13[029] - load method [block] in foo tests/type_propagation/block-local-test.toit + 18[019] - load local 5 + 19[025] - load smi 1 + 20[074] - invoke sub // [{LargeInteger_|SmallInteger_}, {SmallInteger_}] -> {LargeInteger_|SmallInteger_} + 21[038] - load block 1 + 23[053] - invoke static foo tests/type_propagation/block-local-test.toit // [{LargeInteger_|SmallInteger_}, [block]] -> {} + 26[040] - pop 2 + +[block] in foo tests/type_propagation/block-local-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S1 // {String_|Null_} + 3[053] - invoke static id tests/type_propagation/block-local-test.toit // [{String_|Null_}] -> {String_|Null_} + 6[002] - pop, load local S2 + 8[020] - load literal hest + 10[006] - store outer S1 + 12[002] - pop, load local S2 + 14[005] - load outer S4 // [block] + 16[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 18[017] - load local 3 + 19[026] - load smi 123 + 21[006] - store outer S1 + 23[002] - pop, load local S0 + 25[018] - load local 4 + 26[005] - load outer S4 // [block] + 28[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 30[073] - invoke add // [{SmallInteger_}, {SmallInteger_}] -> {LargeInteger_|SmallInteger_} + 31[004] - store local, pop S1 + 33[017] - load local 3 + 34[005] - load outer S1 // {SmallInteger_} + 36[053] - invoke static id tests/type_propagation/block-local-test.toit // [{SmallInteger_}] -> {SmallInteger_} + 39[041] - pop 1 + 40[025] - load smi 1 + 41[015] - load local 1 + 42[073] - invoke add // [{SmallInteger_}, {LargeInteger_|SmallInteger_}] -> {LargeInteger_|SmallInteger_} + 43[018] - load local 4 + 44[091] - non-local return 18 + 46[003] - store local S1 + 48[089] - return S1 1 + +id tests/type_propagation/block-local-test.toit + - argument 0: {String_|Null_|True|float|SmallInteger_} + 0[016] - load local 2 + 1[089] - return S1 1 diff --git a/tests/type_propagation/gold/block-test.gold b/tests/type_propagation/gold/block-test.gold index e8174acc5..d05ef43fc 100644 --- a/tests/type_propagation/gold/block-test.gold +++ b/tests/type_propagation/gold/block-test.gold @@ -16,7 +16,9 @@ main tests/type_propagation/block-test.toit 28[053] - invoke static test-recursion tests/type_propagation/block-test.toit // {Null_} 31[041] - pop 1 32[053] - invoke static test-dead tests/type_propagation/block-test.toit // {Null_} - 35[090] - return null S1 0 + 35[041] - pop 1 + 36[053] - invoke static test-dependent tests/type_propagation/block-test.toit // {Null_} + 39[090] - return null S1 0 test-simple tests/type_propagation/block-test.toit 0[023] - load smi 0 @@ -405,6 +407,36 @@ test-dead tests/type_propagation/block-test.toit 31[053] - invoke static ignore tests/type_propagation/block-test.toit // [[block]] -> {Null_} 34[090] - return null S2 0 +test-dependent tests/type_propagation/block-test.toit + 0[020] - load literal hest + 2[022] - load null + 3[029] - load method [block] in test-dependent tests/type_propagation/block-test.toit + 8[029] - load method [block] in test-dependent tests/type_propagation/block-test.toit + 13[038] - load block 1 + 15[038] - load block 1 + 17[053] - invoke static invoke tests/type_propagation/block-test.toit // [[block], [block]] -> {Null_} + 20[040] - pop 3 + 22[015] - load local 1 + 23[053] - invoke static id tests/type_propagation/block-test.toit // [{String_|Null_|SmallInteger_}] -> {String_|Null_|SmallInteger_} + 26[002] - pop, load local S0 + 28[053] - invoke static id tests/type_propagation/block-test.toit // [{Null_|SmallInteger_}] -> {Null_|SmallInteger_} + 31[090] - return null S3 0 + +[block] in test-dependent tests/type_propagation/block-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[017] - load local 3 + 2[005] - load outer S1 // {Null_|SmallInteger_} + 4[006] - store outer S2 + 6[089] - return S1 1 + +[block] in test-dependent tests/type_propagation/block-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[026] - load smi 42 + 3[006] - store outer S2 + 5[089] - return S1 1 + recursive-null tests/type_propagation/block-test.toit - argument 0: [block] 0[053] - invoke static pick tests/type_propagation/block-test.toit // {True|False} @@ -507,6 +539,15 @@ invoke tests/type_propagation/block-test.toit 1[055] - invoke block S1 // [[block]] -> {String_|Null_|True|float|SmallInteger_} 3[089] - return S1 1 +invoke tests/type_propagation/block-test.toit + - argument 0: [block] + - argument 1: [block] + 0[017] - load local 3 + 1[055] - invoke block S1 // [[block]] -> {Null_|SmallInteger_} + 3[002] - pop, load local S2 + 5[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 7[090] - return null S1 2 + invoke tests/type_propagation/block-test.toit - argument 0: {String_|True|SmallInteger_} - argument 1: [block] diff --git a/tests/type_propagation/gold/block-test.gold-O2 b/tests/type_propagation/gold/block-test.gold-O2 index 72ea8b793..b2377427c 100644 --- a/tests/type_propagation/gold/block-test.gold-O2 +++ b/tests/type_propagation/gold/block-test.gold-O2 @@ -16,7 +16,9 @@ main tests/type_propagation/block-test.toit 28[053] - invoke static test-recursion tests/type_propagation/block-test.toit // {Null_} 31[041] - pop 1 32[053] - invoke static test-dead tests/type_propagation/block-test.toit // {Null_} - 35[090] - return null S1 0 + 35[041] - pop 1 + 36[053] - invoke static test-dependent tests/type_propagation/block-test.toit // {Null_} + 39[090] - return null S1 0 test-simple tests/type_propagation/block-test.toit 0[023] - load smi 0 @@ -403,6 +405,36 @@ test-dead tests/type_propagation/block-test.toit 31[053] - invoke static ignore tests/type_propagation/block-test.toit // [[block]] -> {Null_} 34[090] - return null S2 0 +test-dependent tests/type_propagation/block-test.toit + 0[020] - load literal hest + 2[022] - load null + 3[029] - load method [block] in test-dependent tests/type_propagation/block-test.toit + 8[029] - load method [block] in test-dependent tests/type_propagation/block-test.toit + 13[038] - load block 1 + 15[038] - load block 1 + 17[053] - invoke static invoke tests/type_propagation/block-test.toit // [[block], [block]] -> {Null_} + 20[040] - pop 3 + 22[015] - load local 1 + 23[053] - invoke static id tests/type_propagation/block-test.toit // [{String_|Null_|SmallInteger_}] -> {String_|Null_|SmallInteger_} + 26[002] - pop, load local S0 + 28[053] - invoke static id tests/type_propagation/block-test.toit // [{Null_|SmallInteger_}] -> {Null_|SmallInteger_} + 31[090] - return null S3 0 + +[block] in test-dependent tests/type_propagation/block-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[017] - load local 3 + 2[005] - load outer S1 // {Null_|SmallInteger_} + 4[006] - store outer S2 + 6[089] - return S1 1 + +[block] in test-dependent tests/type_propagation/block-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[026] - load smi 42 + 3[006] - store outer S2 + 5[089] - return S1 1 + recursive-null tests/type_propagation/block-test.toit - argument 0: [block] 0[053] - invoke static pick tests/type_propagation/block-test.toit // {True|False} @@ -505,6 +537,15 @@ invoke tests/type_propagation/block-test.toit 1[055] - invoke block S1 // [[block]] -> {String_|Null_|True|float|SmallInteger_} 3[089] - return S1 1 +invoke tests/type_propagation/block-test.toit + - argument 0: [block] + - argument 1: [block] + 0[017] - load local 3 + 1[055] - invoke block S1 // [[block]] -> {Null_|SmallInteger_} + 3[002] - pop, load local S2 + 5[055] - invoke block S1 // [[block]] -> {SmallInteger_} + 7[090] - return null S1 2 + invoke tests/type_propagation/block-test.toit - argument 0: {String_|True|SmallInteger_} - argument 1: [block] diff --git a/tests/type_propagation/gold/default-arguments-test.gold b/tests/type_propagation/gold/default-arguments-test.gold new file mode 100644 index 000000000..2ac301afb --- /dev/null +++ b/tests/type_propagation/gold/default-arguments-test.gold @@ -0,0 +1,107 @@ +main tests/type_propagation/default-arguments-test.toit + 0[020] - load literal true + 2[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 5[041] - pop 1 + 6[020] - load literal false + 8[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 11[041] - pop 1 + 12[020] - load literal true + 14[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 17[041] - pop 1 + 18[020] - load literal false + 20[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 23[041] - pop 1 + 24[022] - load null + 25[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{Null_}] -> {True} + 28[041] - pop 1 + 29[020] - load literal true + 31[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{True}] -> {True|False} + 34[041] - pop 1 + 35[020] - load literal false + 37[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{False}] -> {False} + 40[041] - pop 1 + 41[020] - load literal true + 43[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{True}] -> {True|False} + 46[041] - pop 1 + 47[020] - load literal false + 49[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{False}] -> {False} + 52[041] - pop 1 + 53[022] - load null + 54[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{Null_}] -> {False} + 57[041] - pop 1 + 58[020] - load literal true + 60[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 63[041] - pop 1 + 64[020] - load literal true + 66[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 69[041] - pop 1 + 70[020] - load literal false + 72[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 75[041] - pop 1 + 76[020] - load literal false + 78[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 81[041] - pop 1 + 82[020] - load literal true + 84[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 87[041] - pop 1 + 88[020] - load literal true + 90[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 93[041] - pop 1 + 94[020] - load literal false + 96[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 99[041] - pop 1 +100[020] - load literal false +102[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} +105[090] - return null S1 0 + +test-default-true tests/type_propagation/default-arguments-test.toit + - argument 0: {Null_|True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T10 + 6[020] - load literal true + 8[004] - store local, pop S3 + 10[052] - load local, as class, pop 2 - True(21 - 23) // {True|False} + 12[016] - load local 2 + 13[089] - return S1 1 + +test-default-false tests/type_propagation/default-arguments-test.toit + - argument 0: {Null_|True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T10 + 6[020] - load literal false + 8[004] - store local, pop S3 + 10[052] - load local, as class, pop 2 - True(21 - 23) // {True|False} + 12[016] - load local 2 + 13[089] - return S1 1 + +test-non-default tests/type_propagation/default-arguments-test.toit + - argument 0: {True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T10 + 6[020] - load literal true + 8[004] - store local, pop S3 + 10[052] - load local, as class, pop 2 - True(21 - 23) // {True} + 12[016] - load local 2 + 13[089] - return S1 1 + +test-non-default-non-literal tests/type_propagation/default-arguments-test.toit + - argument 0: {True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T11 + 6[053] - invoke static gettrue tests/type_propagation/default-arguments-test.toit // {True} + 9[004] - store local, pop S3 + 11[052] - load local, as class, pop 2 - True(21 - 23) // {True} + 13[016] - load local 2 + 14[089] - return S1 1 + +gettrue tests/type_propagation/default-arguments-test.toit + 0[020] - load literal true + 2[089] - return S1 0 diff --git a/tests/type_propagation/gold/default-arguments-test.gold-O2 b/tests/type_propagation/gold/default-arguments-test.gold-O2 new file mode 100644 index 000000000..04a1d4215 --- /dev/null +++ b/tests/type_propagation/gold/default-arguments-test.gold-O2 @@ -0,0 +1,105 @@ +main tests/type_propagation/default-arguments-test.toit + 0[020] - load literal true + 2[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 5[041] - pop 1 + 6[020] - load literal false + 8[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 11[041] - pop 1 + 12[020] - load literal true + 14[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 17[041] - pop 1 + 18[020] - load literal false + 20[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 23[041] - pop 1 + 24[022] - load null + 25[053] - invoke static test-default-true tests/type_propagation/default-arguments-test.toit // [{Null_}] -> {True} + 28[041] - pop 1 + 29[020] - load literal true + 31[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{True}] -> {True|False} + 34[041] - pop 1 + 35[020] - load literal false + 37[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{False}] -> {False} + 40[041] - pop 1 + 41[020] - load literal true + 43[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{True}] -> {True|False} + 46[041] - pop 1 + 47[020] - load literal false + 49[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{False}] -> {False} + 52[041] - pop 1 + 53[022] - load null + 54[053] - invoke static test-default-false tests/type_propagation/default-arguments-test.toit // [{Null_}] -> {False} + 57[041] - pop 1 + 58[020] - load literal true + 60[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 63[041] - pop 1 + 64[020] - load literal true + 66[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 69[041] - pop 1 + 70[020] - load literal false + 72[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 75[041] - pop 1 + 76[020] - load literal false + 78[053] - invoke static test-non-default tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 81[041] - pop 1 + 82[020] - load literal true + 84[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 87[041] - pop 1 + 88[020] - load literal true + 90[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{True}] -> {True} + 93[041] - pop 1 + 94[020] - load literal false + 96[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} + 99[041] - pop 1 +100[020] - load literal false +102[053] - invoke static test-non-default-non-literal tests/type_propagation/default-arguments-test.toit // [{False}] -> {True|False} +105[090] - return null S1 0 + +test-default-true tests/type_propagation/default-arguments-test.toit + - argument 0: {Null_|True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T10 + 6[020] - load literal true + 8[004] - store local, pop S3 + 10[052] - load local, as class, pop 2 - True(18 - 20) // {True|False} + 12[016] - load local 2 + 13[089] - return S1 1 + +test-default-false tests/type_propagation/default-arguments-test.toit + - argument 0: {Null_|True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T10 + 6[020] - load literal false + 8[004] - store local, pop S3 + 10[052] - load local, as class, pop 2 - True(18 - 20) // {True|False} + 12[016] - load local 2 + 13[089] - return S1 1 + +test-non-default tests/type_propagation/default-arguments-test.toit + - argument 0: {True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T10 + 6[020] - load literal true + 8[004] - store local, pop S3 + 10[016] - load local 2 + 11[089] - return S1 1 + +test-non-default-non-literal tests/type_propagation/default-arguments-test.toit + - argument 0: {True|False} + 0[016] - load local 2 + 1[022] - load null + 2[094] - identical + 3[083] - branch if false T11 + 6[053] - invoke static gettrue tests/type_propagation/default-arguments-test.toit // {True} + 9[004] - store local, pop S3 + 11[016] - load local 2 + 12[089] - return S1 1 + +gettrue tests/type_propagation/default-arguments-test.toit + 0[020] - load literal true + 2[089] - return S1 0 diff --git a/tests/type_propagation/gold/finally-test.gold b/tests/type_propagation/gold/finally-test.gold index becf1494f..15b0c492e 100644 --- a/tests/type_propagation/gold/finally-test.gold +++ b/tests/type_propagation/gold/finally-test.gold @@ -6,7 +6,21 @@ main tests/type_propagation/finally-test.toit 8[053] - invoke static test-catchy tests/type_propagation/finally-test.toit // {Null_} 11[041] - pop 1 12[053] - invoke static test-nlb-out-of-try tests/type_propagation/finally-test.toit // {Null_} - 15[090] - return null S1 0 + 15[041] - pop 1 + 16[053] - invoke static test-throw-update-in-finally tests/type_propagation/finally-test.toit // {Null_} + 19[041] - pop 1 + 20[053] - invoke static test-break-update-in-finally tests/type_propagation/finally-test.toit // {Null_} + 23[041] - pop 1 + 24[053] - invoke static test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit // {Null_} + 27[041] - pop 1 + 28[053] - invoke static test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit // {Null_} + 31[041] - pop 1 + 32[053] - invoke static test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit // {Null_} + 35[041] - pop 1 + 36[053] - invoke static test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit // {Null_} + 39[041] - pop 1 + 40[053] - invoke static test-break-update-in-finally-nested tests/type_propagation/finally-test.toit // {Null_} + 43[090] - return null S1 0 test-is-exception tests/type_propagation/finally-test.toit 0[053] - invoke static return-is-exception tests/type_propagation/finally-test.toit // {True|False} @@ -196,6 +210,264 @@ test-nlb-out-of-try tests/type_propagation/finally-test.toit 4[091] - non-local return 16 6[089] - return S1 1 +test-throw-update-in-finally tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + 7[038] - load block 0 + 9[053] - invoke static invoke-catch tests/type_propagation/finally-test.toit // [[block]] -> {Null_} + 12[041] - pop 1 + 13[002] - pop, load local S0 + 15[053] - invoke static id tests/type_propagation/finally-test.toit // [{True|False}] -> {True|False} + 18[090] - return null S2 0 + +[block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[000] - load local S6 + 16[020] - load literal true + 18[006] - store outer S1 + 20[041] - pop 1 + 21[097] - unwind + 22[041] - pop 1 + 23[022] - load null + 24[089] - return S1 1 + +[block] in [block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[020] - load literal ugh + 2[053] - invoke static throw /core/exceptions.toit // [{String_}] -> {} + 5[089] - return S1 1 + +test-break-update-in-finally tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-break-update-in-finally tests/type_propagation/finally-test.toit + 7[095] - link try 0 + 9[038] - load block 4 + 11[055] - invoke block S1 // [[block]] -> {} + 13[041] - pop 1 + 14[096] - unlink try 0 + 16[020] - load literal true + 18[004] - store local, pop S5 + 20[097] - unwind + 21[041] - pop 1 + 22[084] - branch back T2 + 27[014] - load local 0 + 28[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 31[090] - return null S2 0 + +[block] in test-break-update-in-finally tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally:27} + 7[089] - return S1 1 + +test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + 7[038] - load block 0 + 9[053] - invoke static invoke tests/type_propagation/finally-test.toit // [[block]] -> {} + 12[040] - pop 2 + 14[084] - branch back T2 + 19[014] - load local 0 + 20[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 23[090] - return null S2 0 + +[block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[000] - load local S6 + 16[020] - load literal true + 18[006] - store outer S1 + 20[041] - pop 1 + 21[097] - unwind + 22[041] - pop 1 + 23[022] - load null + 24[089] - return S1 1 + +[block] in [block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S3 // [block] + 3[093] - non-local branch {test-break-update-in-finally-block0:19} + 9[089] - return S1 1 + +test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + 7[029] - load method [block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + 12[095] - link try 0 + 14[038] - load block 4 + 16[055] - invoke block S1 // [[block]] -> {} + 18[041] - pop 1 + 19[096] - unlink try 0 + 21[020] - load literal true + 23[004] - store local, pop S6 + 25[097] - unwind + 26[040] - pop 2 + 28[084] - branch back T2 + 33[014] - load local 0 + 34[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 37[090] - return null S2 0 + +[block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally-block1:33} + 7[089] - return S1 1 + +[block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 1 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1 + +test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 0[022] - load null + 1[029] - load method [block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 6[029] - load method [block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 11[095] - link try 0 + 13[038] - load block 4 + 15[055] - invoke block S1 // [[block]] -> {} + 17[041] - pop 1 + 18[096] - unlink try 0 + 20[020] - load literal true + 22[004] - store local, pop S6 + 24[029] - load method [block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 29[095] - link try 0 + 31[038] - load block 4 + 33[055] - invoke block S1 // [[block]] -> {} + 35[041] - pop 1 + 36[096] - unlink try 0 + 38[020] - load literal false + 40[004] - store local, pop S10 + 42[097] - unwind + 43[041] - pop 1 + 44[097] - unwind + 45[040] - pop 2 + 47[084] - branch back T1 + 52[014] - load local 0 + 53[053] - invoke static id tests/type_propagation/finally-test.toit // [{Null_|True}] -> {Null_|True} + 56[090] - return null S2 0 + +[block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally-block2:52} + 7[089] - return S1 1 + +[block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 1 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1 + +[block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 5 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1 + +test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[022] - load null + 3[029] - load method [block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + 8[029] - load method [block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + 13[095] - link try 0 + 15[038] - load block 4 + 17[055] - invoke block S1 // [[block]] -> {} + 19[041] - pop 1 + 20[096] - unlink try 0 + 22[020] - load literal true + 24[004] - store local, pop S7 + 26[097] - unwind + 27[041] - pop 1 + 28[084] - branch back T8 + 33[016] - load local 2 + 34[004] - store local, pop S2 + 36[041] - pop 1 + 37[084] - branch back T3 + 42[015] - load local 1 + 43[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 46[002] - pop, load local S0 + 48[053] - invoke static id tests/type_propagation/finally-test.toit // [{Null_|False}] -> {Null_|False} + 51[090] - return null S3 0 + +[block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally-block3:42} + 7[089] - return S1 1 + +[block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[053] - invoke static pick tests/type_propagation/finally-test.toit // {True|False} + 3[083] - branch if false T14 + 6[016] - load local 2 + 7[039] - load outer block 1 // [block] + 9[055] - invoke block S1 // [[block]] -> {} + 11[081] - branch T21 + 14[016] - load local 2 + 15[093] - non-local branch {test-break-update-in-finally-block3:33} + 21[089] - return S1 1 + +test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + 0[022] - load null + 1[029] - load method [block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + 6[095] - link try 0 + 8[038] - load block 4 + 10[055] - invoke block S1 // [[block]] -> {} + 12[041] - pop 1 + 13[096] - unlink try 0 + 15[020] - load literal horse + 17[004] - store local, pop S5 + 19[097] - unwind + 20[041] - pop 1 + 21[084] - branch back T1 + 26[014] - load local 0 + 27[053] - invoke static id tests/type_propagation/finally-test.toit // [{SmallInteger_}] -> {SmallInteger_} + 30[090] - return null S2 0 + +[block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[000] - load local S6 + 16[020] - load literal true + 18[006] - store outer S1 + 20[041] - pop 1 + 21[097] - unwind + 22[041] - pop 1 + 23[022] - load null + 24[089] - return S1 1 + +[block] in [block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S3 // [block] + 3[023] - load smi 0 + 4[006] - store outer S1 + 6[002] - pop, load local S2 + 8[005] - load outer S3 // [block] + 10[093] - non-local branch {test-break-update-in-finally-nested:26} + 16[089] - return S1 1 + id tests/type_propagation/finally-test.toit - argument 0: {String_|Null_|True|False|SmallInteger_|Exception_} 0[016] - load local 2 @@ -213,3 +485,22 @@ invoke tests/type_propagation/finally-test.toit 0[016] - load local 2 1[055] - invoke block S1 // [[block]] -> {} 3[090] - return null S1 1 + +invoke-catch tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in invoke-catch tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[090] - return null S4 1 + 17[097] - unwind + 18[041] - pop 1 + +[block] in invoke-catch tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S3 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1 diff --git a/tests/type_propagation/gold/finally-test.gold-O2 b/tests/type_propagation/gold/finally-test.gold-O2 index 2c124dbf5..5303d2e5b 100644 --- a/tests/type_propagation/gold/finally-test.gold-O2 +++ b/tests/type_propagation/gold/finally-test.gold-O2 @@ -6,7 +6,21 @@ main tests/type_propagation/finally-test.toit 8[053] - invoke static test-catchy tests/type_propagation/finally-test.toit // {Null_} 11[041] - pop 1 12[053] - invoke static test-nlb-out-of-try tests/type_propagation/finally-test.toit // {Null_} - 15[090] - return null S1 0 + 15[041] - pop 1 + 16[053] - invoke static test-throw-update-in-finally tests/type_propagation/finally-test.toit // {Null_} + 19[041] - pop 1 + 20[053] - invoke static test-break-update-in-finally tests/type_propagation/finally-test.toit // {Null_} + 23[041] - pop 1 + 24[053] - invoke static test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit // {Null_} + 27[041] - pop 1 + 28[053] - invoke static test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit // {Null_} + 31[041] - pop 1 + 32[053] - invoke static test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit // {Null_} + 35[041] - pop 1 + 36[053] - invoke static test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit // {Null_} + 39[041] - pop 1 + 40[053] - invoke static test-break-update-in-finally-nested tests/type_propagation/finally-test.toit // {Null_} + 43[090] - return null S1 0 test-is-exception tests/type_propagation/finally-test.toit 0[053] - invoke static return-is-exception tests/type_propagation/finally-test.toit // {True|False} @@ -196,6 +210,264 @@ test-nlb-out-of-try tests/type_propagation/finally-test.toit 4[091] - non-local return 16 6[089] - return S1 1 +test-throw-update-in-finally tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + 7[038] - load block 0 + 9[053] - invoke static invoke-catch tests/type_propagation/finally-test.toit // [[block]] -> {Null_} + 12[041] - pop 1 + 13[002] - pop, load local S0 + 15[053] - invoke static id tests/type_propagation/finally-test.toit // [{True|False}] -> {True|False} + 18[090] - return null S2 0 + +[block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[000] - load local S6 + 16[020] - load literal true + 18[006] - store outer S1 + 20[041] - pop 1 + 21[097] - unwind + 22[041] - pop 1 + 23[022] - load null + 24[089] - return S1 1 + +[block] in [block] in test-throw-update-in-finally tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[020] - load literal ugh + 2[053] - invoke static throw /core/exceptions.toit // [{String_}] -> {} + 5[089] - return S1 1 + +test-break-update-in-finally tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-break-update-in-finally tests/type_propagation/finally-test.toit + 7[095] - link try 0 + 9[038] - load block 4 + 11[055] - invoke block S1 // [[block]] -> {} + 13[041] - pop 1 + 14[096] - unlink try 0 + 16[020] - load literal true + 18[004] - store local, pop S5 + 20[097] - unwind + 21[041] - pop 1 + 22[084] - branch back T2 + 27[014] - load local 0 + 28[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 31[090] - return null S2 0 + +[block] in test-break-update-in-finally tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally:27} + 7[089] - return S1 1 + +test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + 7[038] - load block 0 + 9[053] - invoke static invoke tests/type_propagation/finally-test.toit // [[block]] -> {} + 12[040] - pop 2 + 14[084] - branch back T2 + 19[014] - load local 0 + 20[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 23[090] - return null S2 0 + +[block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[000] - load local S6 + 16[020] - load literal true + 18[006] - store outer S1 + 20[041] - pop 1 + 21[097] - unwind + 22[041] - pop 1 + 23[022] - load null + 24[089] - return S1 1 + +[block] in [block] in test-break-update-in-finally-block0 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S3 // [block] + 3[093] - non-local branch {test-break-update-in-finally-block0:19} + 9[089] - return S1 1 + +test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[029] - load method [block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + 7[029] - load method [block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + 12[095] - link try 0 + 14[038] - load block 4 + 16[055] - invoke block S1 // [[block]] -> {} + 18[041] - pop 1 + 19[096] - unlink try 0 + 21[020] - load literal true + 23[004] - store local, pop S6 + 25[097] - unwind + 26[040] - pop 2 + 28[084] - branch back T2 + 33[014] - load local 0 + 34[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 37[090] - return null S2 0 + +[block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally-block1:33} + 7[089] - return S1 1 + +[block] in test-break-update-in-finally-block1 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 1 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1 + +test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 0[022] - load null + 1[029] - load method [block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 6[029] - load method [block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 11[095] - link try 0 + 13[038] - load block 4 + 15[055] - invoke block S1 // [[block]] -> {} + 17[041] - pop 1 + 18[096] - unlink try 0 + 20[020] - load literal true + 22[004] - store local, pop S6 + 24[029] - load method [block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + 29[095] - link try 0 + 31[038] - load block 4 + 33[055] - invoke block S1 // [[block]] -> {} + 35[041] - pop 1 + 36[096] - unlink try 0 + 38[020] - load literal false + 40[004] - store local, pop S10 + 42[097] - unwind + 43[041] - pop 1 + 44[097] - unwind + 45[040] - pop 2 + 47[084] - branch back T1 + 52[014] - load local 0 + 53[053] - invoke static id tests/type_propagation/finally-test.toit // [{Null_|True}] -> {Null_|True} + 56[090] - return null S2 0 + +[block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally-block2:52} + 7[089] - return S1 1 + +[block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 1 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1 + +[block] in test-break-update-in-finally-block2 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[039] - load outer block 5 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1 + +test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + 0[020] - load literal false + 2[022] - load null + 3[029] - load method [block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + 8[029] - load method [block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + 13[095] - link try 0 + 15[038] - load block 4 + 17[055] - invoke block S1 // [[block]] -> {} + 19[041] - pop 1 + 20[096] - unlink try 0 + 22[020] - load literal true + 24[004] - store local, pop S7 + 26[097] - unwind + 27[041] - pop 1 + 28[084] - branch back T8 + 33[016] - load local 2 + 34[004] - store local, pop S2 + 36[041] - pop 1 + 37[084] - branch back T3 + 42[015] - load local 1 + 43[053] - invoke static id tests/type_propagation/finally-test.toit // [{False}] -> {False} + 46[002] - pop, load local S0 + 48[053] - invoke static id tests/type_propagation/finally-test.toit // [{Null_|False}] -> {Null_|False} + 51[090] - return null S3 0 + +[block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[093] - non-local branch {test-break-update-in-finally-block3:42} + 7[089] - return S1 1 + +[block] in test-break-update-in-finally-block3 tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[053] - invoke static pick tests/type_propagation/finally-test.toit // {True|False} + 3[083] - branch if false T14 + 6[016] - load local 2 + 7[039] - load outer block 1 // [block] + 9[055] - invoke block S1 // [[block]] -> {} + 11[081] - branch T21 + 14[016] - load local 2 + 15[093] - non-local branch {test-break-update-in-finally-block3:33} + 21[089] - return S1 1 + +test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + 0[022] - load null + 1[029] - load method [block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + 6[095] - link try 0 + 8[038] - load block 4 + 10[055] - invoke block S1 // [[block]] -> {} + 12[041] - pop 1 + 13[096] - unlink try 0 + 15[020] - load literal horse + 17[004] - store local, pop S5 + 19[097] - unwind + 20[041] - pop 1 + 21[084] - branch back T1 + 26[014] - load local 0 + 27[053] - invoke static id tests/type_propagation/finally-test.toit // [{SmallInteger_}] -> {SmallInteger_} + 30[090] - return null S2 0 + +[block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in [block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[000] - load local S6 + 16[020] - load literal true + 18[006] - store outer S1 + 20[041] - pop 1 + 21[097] - unwind + 22[041] - pop 1 + 23[022] - load null + 24[089] - return S1 1 + +[block] in [block] in test-break-update-in-finally-nested tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S3 // [block] + 3[023] - load smi 0 + 4[006] - store outer S1 + 6[002] - pop, load local S2 + 8[005] - load outer S3 // [block] + 10[093] - non-local branch {test-break-update-in-finally-nested:26} + 16[089] - return S1 1 + id tests/type_propagation/finally-test.toit - argument 0: {String_|Null_|True|False|SmallInteger_|Exception_} 0[016] - load local 2 @@ -213,3 +485,22 @@ invoke tests/type_propagation/finally-test.toit 0[016] - load local 2 1[055] - invoke block S1 // [[block]] -> {} 3[041] - pop 1 + +invoke-catch tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[029] - load method [block] in invoke-catch tests/type_propagation/finally-test.toit + 5[095] - link try 0 + 7[038] - load block 4 + 9[055] - invoke block S1 // [[block]] -> {} + 11[041] - pop 1 + 12[096] - unlink try 0 + 14[090] - return null S4 1 + 17[097] - unwind + 18[041] - pop 1 + +[block] in invoke-catch tests/type_propagation/finally-test.toit + - argument 0: [block] + 0[016] - load local 2 + 1[005] - load outer S3 // [block] + 3[055] - invoke block S1 // [[block]] -> {} + 5[089] - return S1 1