MachineCode* CompiledCode::internalize(STATE, GCToken gct, const char** reason, int* ip) { MachineCode* mcode = machine_code_; atomic::memory_barrier(); if(mcode) return mcode; CompiledCode* self = this; OnStack<1> os(state, self); self->hard_lock(state, gct); mcode = self->machine_code_; if(!mcode) { { BytecodeVerification bv(self); if(!bv.verify(state)) { if(reason) *reason = bv.failure_reason(); if(ip) *ip = bv.failure_ip(); std::cerr << "Error validating bytecode: " << bv.failure_reason() << "\n"; return 0; } } mcode = new MachineCode(state, self); if(self->resolve_primitive(state)) { mcode->fallback = execute; } else { mcode->setup_argument_handler(); } // We need to have an explicit memory barrier here, because we need to // be sure that mcode is completely initialized before it's set. // Otherwise another thread might see a partially initialized // MachineCode. atomic::write(&self->machine_code_, mcode); set_executor(mcode->fallback); } self->hard_unlock(state, gct); return mcode; }
MachineCode* CompiledCode::internalize(STATE) { timer::StopWatch<timer::microseconds> timer( state->vm()->metrics().machine.bytecode_internalizer_us); atomic::memory_barrier(); MachineCode* mcode = machine_code(); if(mcode) return mcode; { BytecodeVerifier bytecode_verifier(this); bytecode_verifier.verify(state); } mcode = new MachineCode(state, this); if(resolve_primitive(state)) { mcode->fallback = execute; } else { mcode->setup_argument_handler(); } /* There is a race here because another Thread may have run this * CompiledCode instance and internalized it. We attempt to store our * version assuming that we are the only ones to do so and throw away our * work if someone else has beat us to it. */ MachineCode** mcode_ptr = &_machine_code_; if(atomic::compare_and_swap(reinterpret_cast<void**>(mcode_ptr), 0, mcode)) { set_executor(mcode->fallback); return mcode; } else { return machine_code(); } }