PageRenderTime 375ms CodeModel.GetById 147ms app.highlight 120ms RepoModel.GetById 105ms app.codeStats 0ms

/JIT/opcodes/globals.cc

http://unladen-swallow.googlecode.com/
C++ | 176 lines | 139 code | 24 blank | 13 comment | 8 complexity | e62c0bc7038f313854be5dd95157a809 MD5 | raw file
  1#include "Python.h"
  2
  3#include "JIT/opcodes/globals.h"
  4#include "JIT/llvm_fbuilder.h"
  5
  6#include "llvm/BasicBlock.h"
  7#include "llvm/Function.h"
  8#include "llvm/Instructions.h"
  9
 10using llvm::BasicBlock;
 11using llvm::Function;
 12using llvm::Value;
 13
 14namespace py {
 15
 16OpcodeGlobals::OpcodeGlobals(LlvmFunctionBuilder *fbuilder) :
 17    fbuilder_(fbuilder),
 18    state_(fbuilder->state()),
 19    builder_(fbuilder->builder())
 20{
 21}
 22
 23void OpcodeGlobals::LOAD_GLOBAL(int index)
 24{
 25    // A code object might not have co_watching set if
 26    // a) it was compiled by setting co_optimization, or
 27    // b) we couldn't watch the globals/builtins dicts.
 28    PyObject **watching = this->fbuilder_->code_object()->co_watching;
 29    if (watching && watching[WATCHING_GLOBALS] && watching[WATCHING_BUILTINS])
 30        this->LOAD_GLOBAL_fast(index);
 31    else
 32        this->LOAD_GLOBAL_safe(index);
 33}
 34
 35void OpcodeGlobals::LOAD_GLOBAL_fast(int index)
 36{
 37    PyCodeObject *code = this->fbuilder_->code_object();
 38    assert(code->co_watching != NULL);
 39    assert(code->co_watching[WATCHING_GLOBALS]);
 40    assert(code->co_watching[WATCHING_BUILTINS]);
 41
 42    PyObject *name = PyTuple_GET_ITEM(code->co_names, index);
 43    PyObject *obj = PyDict_GetItem(code->co_watching[WATCHING_GLOBALS], name);
 44    if (obj == NULL) {
 45        obj = PyDict_GetItem(code->co_watching[WATCHING_BUILTINS], name);
 46        if (obj == NULL) {
 47            /* This isn't necessarily an error: it's legal Python
 48               code to refer to globals that aren't yet defined at
 49               compilation time. Is it a bad idea? Almost
 50               certainly. Is it legal? Unfortunatley. */
 51            this->LOAD_GLOBAL_safe(index);
 52            return;
 53        }
 54    }
 55    this->fbuilder_->WatchDict(WATCHING_GLOBALS);
 56    this->fbuilder_->WatchDict(WATCHING_BUILTINS);
 57
 58    BasicBlock *keep_going =
 59        this->state_->CreateBasicBlock("LOAD_GLOBAL_keep_going");
 60    BasicBlock *invalid_assumptions =
 61        this->state_->CreateBasicBlock("LOAD_GLOBAL_invalid_assumptions");
 62
 63#ifdef WITH_TSC
 64    this->state_->LogTscEvent(LOAD_GLOBAL_ENTER_LLVM);
 65#endif
 66    this->builder_.CreateCondBr(this->fbuilder_->GetUseJitCond(),
 67                                keep_going,
 68                                invalid_assumptions);
 69
 70    /* Our assumptions about the state of the globals/builtins no longer hold;
 71       bail back to the interpreter. */
 72    this->builder_.SetInsertPoint(invalid_assumptions);
 73    this->fbuilder_->CreateBailPoint(_PYFRAME_FATAL_GUARD_FAIL);
 74
 75    /* Our assumptions are still valid; encode the result of the lookups as an
 76       immediate in the IR. */
 77    this->builder_.SetInsertPoint(keep_going);
 78    Value *global = this->state_->EmbedPointer<PyObject*>(obj);
 79    this->state_->IncRef(global);
 80    this->fbuilder_->Push(global);
 81
 82#ifdef WITH_TSC
 83    this->state_->LogTscEvent(LOAD_GLOBAL_EXIT_LLVM);
 84#endif
 85}
 86
 87void OpcodeGlobals::LOAD_GLOBAL_safe(int index)
 88{
 89    this->fbuilder_->SetOpcodeArguments(0);
 90    BasicBlock *global_missing =
 91            this->state_->CreateBasicBlock("LOAD_GLOBAL_global_missing");
 92    BasicBlock *global_success =
 93            this->state_->CreateBasicBlock("LOAD_GLOBAL_global_success");
 94    BasicBlock *builtin_missing =
 95            this->state_->CreateBasicBlock("LOAD_GLOBAL_builtin_missing");
 96    BasicBlock *builtin_success =
 97            this->state_->CreateBasicBlock("LOAD_GLOBAL_builtin_success");
 98    BasicBlock *done = this->state_->CreateBasicBlock("LOAD_GLOBAL_done");
 99#ifdef WITH_TSC
100    this->state_->LogTscEvent(LOAD_GLOBAL_ENTER_LLVM);
101#endif
102    Value *name = this->fbuilder_->LookupName(index);
103    Function *pydict_getitem = this->state_->GetGlobalFunction<
104        PyObject *(PyObject *, PyObject *)>("PyDict_GetItem");
105    Value *global = this->state_->CreateCall(
106        pydict_getitem, this->fbuilder_->globals(), name, "global_variable");
107    this->builder_.CreateCondBr(this->state_->IsNull(global),
108                                global_missing, global_success);
109
110    this->builder_.SetInsertPoint(global_success);
111    this->state_->IncRef(global);
112    this->fbuilder_->SetOpcodeResult(0, global);
113    this->builder_.CreateBr(done);
114
115    this->builder_.SetInsertPoint(global_missing);
116    // This ignores any exception set by PyDict_GetItem (and similarly
117    // for the builtins dict below,) but this is what ceval does too.
118    Value *builtin = this->state_->CreateCall(
119        pydict_getitem, this->fbuilder_->builtins(), name, "builtin_variable");
120    this->builder_.CreateCondBr(this->state_->IsNull(builtin),
121                                builtin_missing, builtin_success);
122
123    this->builder_.SetInsertPoint(builtin_missing);
124    Function *do_raise = this->state_->GetGlobalFunction<
125        void(PyObject *)>("_PyEval_RaiseForGlobalNameError");
126    this->state_->CreateCall(do_raise, name);
127    this->fbuilder_->PropagateException();
128
129    this->builder_.SetInsertPoint(builtin_success);
130    this->state_->IncRef(builtin);
131    this->fbuilder_->SetOpcodeResult(0, builtin);
132    this->builder_.CreateBr(done);
133
134    this->builder_.SetInsertPoint(done);
135#ifdef WITH_TSC
136    this->state_->LogTscEvent(LOAD_GLOBAL_EXIT_LLVM);
137#endif
138}
139
140void OpcodeGlobals::STORE_GLOBAL(int index)
141{
142    Value *name = this->fbuilder_->LookupName(index);
143    Value *value = this->fbuilder_->Pop();
144    Function *pydict_setitem = this->state_->GetGlobalFunction<
145        int(PyObject *, PyObject *, PyObject *)>("PyDict_SetItem");
146    Value *result = this->state_->CreateCall(
147        pydict_setitem, this->fbuilder_->globals(), name, value,
148        "STORE_GLOBAL_result");
149    this->state_->DecRef(value);
150    this->fbuilder_->PropagateExceptionOnNonZero(result);
151}
152
153void OpcodeGlobals::DELETE_GLOBAL(int index)
154{
155    BasicBlock *failure =
156        this->state_->CreateBasicBlock("DELETE_GLOBAL_failure");
157    BasicBlock *success =
158        this->state_->CreateBasicBlock("DELETE_GLOBAL_success");
159    Value *name = this->fbuilder_->LookupName(index);
160    Function *pydict_setitem = this->state_->GetGlobalFunction<
161        int(PyObject *, PyObject *)>("PyDict_DelItem");
162    Value *result = this->state_->CreateCall(
163        pydict_setitem, this->fbuilder_->globals(), name, "STORE_GLOBAL_result");
164    this->builder_.CreateCondBr(this->state_->IsNonZero(result),
165                                failure, success);
166
167    this->builder_.SetInsertPoint(failure);
168    Function *do_raise = this->state_->GetGlobalFunction<
169        void(PyObject *)>("_PyEval_RaiseForGlobalNameError");
170    this->state_->CreateCall(do_raise, name);
171    this->fbuilder_->PropagateException();
172
173    this->builder_.SetInsertPoint(success);
174}
175
176}