[macruby-changes] [4136] MacRuby/trunk
source_changes at macosforge.org
source_changes at macosforge.org
Sun May 23 19:24:59 PDT 2010
Revision: 4136
http://trac.macosforge.org/projects/ruby/changeset/4136
Author: lsansonetti at apple.com
Date: 2010-05-23 19:24:56 -0700 (Sun, 23 May 2010)
Log Message:
-----------
now compile some of the VM primitives into bitcode that will be added to the default compilation module and later inlined
Modified Paths:
--------------
MacRuby/trunk/HACKING.rdoc
MacRuby/trunk/array.c
MacRuby/trunk/array.h
MacRuby/trunk/b.rb
MacRuby/trunk/bignum.c
MacRuby/trunk/bridgesupport.cpp
MacRuby/trunk/bridgesupport.h
MacRuby/trunk/class.h
MacRuby/trunk/compiler.cpp
MacRuby/trunk/compiler.h
MacRuby/trunk/dispatcher.cpp
MacRuby/trunk/exported_symbols_list
MacRuby/trunk/hash.c
MacRuby/trunk/hash.h
MacRuby/trunk/include/ruby/intern.h
MacRuby/trunk/include/ruby/ruby.h
MacRuby/trunk/objc.h
MacRuby/trunk/objc.m
MacRuby/trunk/rakelib/builder/options.rb
MacRuby/trunk/rakelib/builder.rake
MacRuby/trunk/string.c
MacRuby/trunk/vm.cpp
MacRuby/trunk/vm.h
Added Paths:
-----------
MacRuby/trunk/kernel.c
Modified: MacRuby/trunk/HACKING.rdoc
===================================================================
--- MacRuby/trunk/HACKING.rdoc 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/HACKING.rdoc 2010-05-24 02:24:56 UTC (rev 4136)
@@ -124,6 +124,11 @@
* VM_VERIFY_IR: set it to any value to force a LLVM module verification before
the interpreter quits.
+* VM_OPT_LEVEL: set it either to 0, 1, 2 or 3 to change the optimization level
+ of the LLVM code generator.
+
+* VM_DISABLE_INLINING: set it to any value to disable function inlining.
+
* DYLD_LIBRARY_PATH: in case you are debugging a Cocoa application, set this
variable to "." before starting gdb, and you won't have to re-install MacRuby
every time you re-compile it.
Modified: MacRuby/trunk/array.c
===================================================================
--- MacRuby/trunk/array.c 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/array.c 2010-05-24 02:24:56 UTC (rev 4136)
@@ -89,27 +89,6 @@
return item;
}
-void
-rary_store(VALUE ary, long idx, VALUE item)
-{
- if (idx < 0) {
- const long len = RARY(ary)->len;
- idx += len;
- if (idx < 0) {
- rb_raise(rb_eIndexError, "index %ld out of array",
- idx - len);
- }
- }
- if (idx >= RARY(ary)->len) {
- rary_reserve(ary, idx + 1);
- for (size_t i = RARY(ary)->len; i < idx + 1; i++) {
- rary_elt_set(ary, i, Qnil);
- }
- RARY(ary)->len = idx + 1;
- }
- rary_elt_set(ary, idx, item);
-}
-
static void
rary_resize(VALUE ary, size_t newlen)
{
@@ -217,8 +196,6 @@
return rb_ary_new2(ARY_DEFAULT_SIZE);
}
-static void rary_push(VALUE ary, VALUE item);
-
VALUE
rb_ary_new3(long n, ...)
{
@@ -488,14 +465,6 @@
* #=> ["a", "b", "c", "d", "e", "f"]
*/
-static void
-rary_push(VALUE ary, VALUE item)
-{
- rary_reserve(ary, RARY(ary)->len + 1);
- rary_elt_set(ary, RARY(ary)->len, item);
- RARY(ary)->len++;
-}
-
static VALUE
rary_push_m2(VALUE ary, SEL sel, int argc, VALUE *argv)
{
Modified: MacRuby/trunk/array.h
===================================================================
--- MacRuby/trunk/array.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/array.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -89,7 +89,40 @@
return rary_elt(ary, offset);
}
+void rary_reserve(VALUE ary, size_t newlen);
+
static inline void
+rary_store(VALUE ary, long idx, VALUE item)
+{
+ if (idx < 0) {
+ const long len = RARY(ary)->len;
+ idx += len;
+ if (idx < 0) {
+ rb_raise(rb_eIndexError, "index %ld out of array",
+ idx - len);
+ }
+ }
+ size_t uidx = (size_t)idx;
+ if (uidx >= RARY(ary)->len) {
+ rary_reserve(ary, uidx + 1);
+ size_t i;
+ for (i = RARY(ary)->len; i < uidx + 1; i++) {
+ rary_elt_set(ary, i, Qnil);
+ }
+ RARY(ary)->len = uidx + 1;
+ }
+ rary_elt_set(ary, uidx, item);
+}
+
+static inline void
+rary_push(VALUE ary, VALUE item)
+{
+ rary_reserve(ary, RARY(ary)->len + 1);
+ rary_elt_set(ary, RARY(ary)->len, item);
+ RARY(ary)->len++;
+}
+
+static inline void
rb_ary_modify(VALUE ary)
{
if (IS_RARY(ary)) {
@@ -120,7 +153,6 @@
VALUE rary_each(VALUE ary, SEL sel);
VALUE rary_sort(VALUE ary, SEL sel);
VALUE rary_sort_bang(VALUE ary, SEL sel);
-void rary_store(VALUE ary, long idx, VALUE item);
VALUE rary_subseq(VALUE ary, long beg, long len);
void rary_insert(VALUE ary, long idx, VALUE val);
Modified: MacRuby/trunk/b.rb
===================================================================
--- MacRuby/trunk/b.rb 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/b.rb 2010-05-24 02:24:56 UTC (rev 4136)
@@ -1,6 +1,6 @@
def bench(e, options)
puts e
- ['./miniruby', 'ruby19'].each do |r|
+ ['./miniruby', 'ruby1.9'].each do |r|
puts `#{r} -v`.strip
line = File.exist?(e) ? "#{r} \"#{e}\"" : "#{r} -e \"#{e}\""
n = options.include?('--no-rehearsal') ? 1 : 3
Modified: MacRuby/trunk/bignum.c
===================================================================
--- MacRuby/trunk/bignum.c 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/bignum.c 2010-05-24 02:24:56 UTC (rev 4136)
@@ -270,20 +270,6 @@
return big;
}
-VALUE
-rb_uint2inum(VALUE n)
-{
- if (POSFIXABLE(n)) return LONG2FIX(n);
- return rb_uint2big(n);
-}
-
-VALUE
-rb_int2inum(SIGNED_VALUE n)
-{
- if (FIXABLE(n)) return LONG2FIX(n);
- return rb_int2big(n);
-}
-
#ifdef HAVE_LONG_LONG
void
@@ -628,8 +614,8 @@
#if HAVE_LONG_LONG
-static VALUE
-rb_ull2big(unsigned LONG_LONG n)
+VALUE
+rb_ull2big(unsigned long long n)
{
BDIGIT_DBL num = n;
long i = 0;
@@ -649,8 +635,8 @@
return big;
}
-static VALUE
-rb_ll2big(LONG_LONG n)
+VALUE
+rb_ll2big(long long n)
{
long neg = 0;
VALUE big;
@@ -666,20 +652,6 @@
return big;
}
-VALUE
-rb_ull2inum(unsigned LONG_LONG n)
-{
- if (POSFIXABLE(n)) return LONG2FIX(n);
- return rb_ull2big(n);
-}
-
-VALUE
-rb_ll2inum(LONG_LONG n)
-{
- if (FIXABLE(n)) return LONG2FIX(n);
- return rb_ll2big(n);
-}
-
#endif /* HAVE_LONG_LONG */
VALUE
Modified: MacRuby/trunk/bridgesupport.cpp
===================================================================
--- MacRuby/trunk/bridgesupport.cpp 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/bridgesupport.cpp 2010-05-24 02:24:56 UTC (rev 4136)
@@ -701,6 +701,7 @@
return rb_ivar_get(rcv, boxed_ivar_type);
}
+extern "C"
bool
rb_boxed_is_type(VALUE klass, const char *type)
{
@@ -764,6 +765,7 @@
assert(ptr->type_size > 0);
}
+extern "C"
VALUE
rb_pointer_new(const char *type_str, void *val, size_t len)
{
@@ -779,6 +781,7 @@
static VALUE rb_pointer_aset(VALUE rcv, SEL sel, VALUE idx, VALUE val);
+extern "C"
VALUE
rb_pointer_new2(const char *type_str, VALUE rval)
{
@@ -828,6 +831,7 @@
xmalloc(GET_CORE()->get_sizeof(type_str) * rlen), rlen);
}
+extern "C"
void *
rb_pointer_get_data(VALUE rcv, const char *type)
{
@@ -1115,17 +1119,7 @@
if (!CFDictionaryGetValueIfPresent(rb_cObject_dict,
(const void *)name, NULL)) {
- VALUE val;
-#if 0 // this is likely not needed anymore
- if (bs_strconst->nsstring) {
- CFStringRef string = CFStringCreateWithCString(NULL,
- bs_strconst->value, kCFStringEncodingUTF8);
- val = (VALUE)string;
- }
- else {
-#endif
- val = rb_str_new2(bs_strconst->value);
-// }
+ VALUE val = rb_str_new2(bs_strconst->value);
CFDictionarySetValue(rb_cObject_dict, (const void *)name,
(const void *)val);
}
Modified: MacRuby/trunk/bridgesupport.h
===================================================================
--- MacRuby/trunk/bridgesupport.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/bridgesupport.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -10,7 +10,17 @@
#define __BRIDGESUPPORT_H_
#if defined(__cplusplus)
+extern "C" {
+#endif
+void *rb_pointer_get_data(VALUE rcv, const char *type);
+VALUE rb_pointer_new(const char *type_str, void *val, size_t len);
+VALUE rb_pointer_new2(const char *type_str, VALUE val);
+bool rb_boxed_is_type(VALUE klass, const char *type);
+
+#if defined(__cplusplus)
+} // extern "C"
+
#include "bs.h"
typedef struct rb_vm_bs_boxed {
@@ -25,12 +35,6 @@
VALUE klass;
} rb_vm_bs_boxed_t;
-VALUE rb_pointer_new(const char *type_str, void *val, size_t len);
-VALUE rb_pointer_new2(const char *type_str, VALUE val);
-void *rb_pointer_get_data(VALUE rcv, const char *type);
-
-bool rb_boxed_is_type(VALUE klass, const char *type);
-
#endif /* __cplusplus */
#endif /* __BRIDGESUPPORT_H_ */
Modified: MacRuby/trunk/class.h
===================================================================
--- MacRuby/trunk/class.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/class.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -39,6 +39,67 @@
CFMutableDictionaryRef rb_class_ivar_dict_or_create(VALUE);
void rb_class_ivar_set_dict(VALUE, CFMutableDictionaryRef);
+typedef enum {
+ SCOPE_DEFAULT = 0, // public for everything but Object
+ SCOPE_PUBLIC,
+ SCOPE_PRIVATE,
+ SCOPE_PROTECTED,
+ SCOPE_MODULE_FUNC,
+} rb_vm_scope_t;
+
+static inline void
+rb_vm_check_if_module(VALUE mod)
+{
+ switch (TYPE(mod)) {
+ case T_CLASS:
+ case T_MODULE:
+ break;
+
+ default:
+ rb_raise(rb_eTypeError, "%s is not a class/module",
+ RSTRING_PTR(rb_inspect(mod)));
+ }
+}
+
+static inline void
+rb_vm_set_current_scope(VALUE mod, rb_vm_scope_t scope)
+{
+ if (scope == SCOPE_DEFAULT) {
+ scope = mod == rb_cObject ? SCOPE_PRIVATE : SCOPE_PUBLIC;
+ }
+ long v = RCLASS_VERSION(mod);
+ switch (scope) {
+ case SCOPE_PUBLIC:
+ v &= ~RCLASS_SCOPE_PRIVATE;
+ v &= ~RCLASS_SCOPE_PROTECTED;
+ v &= ~RCLASS_SCOPE_MOD_FUNC;
+ break;
+
+ case SCOPE_PRIVATE:
+ v |= RCLASS_SCOPE_PRIVATE;
+ v &= ~RCLASS_SCOPE_PROTECTED;
+ v &= ~RCLASS_SCOPE_MOD_FUNC;
+ break;
+
+ case SCOPE_PROTECTED:
+ v &= ~RCLASS_SCOPE_PRIVATE;
+ v |= RCLASS_SCOPE_PROTECTED;
+ v &= ~RCLASS_SCOPE_MOD_FUNC;
+ break;
+
+ case SCOPE_MODULE_FUNC:
+ v &= ~RCLASS_SCOPE_PRIVATE;
+ v &= ~RCLASS_SCOPE_PROTECTED;
+ v |= RCLASS_SCOPE_MOD_FUNC;
+ break;
+
+ case SCOPE_DEFAULT:
+ abort(); // handled earlier
+ }
+
+ RCLASS_SET_VERSION(mod, v);
+}
+
#if defined(__cplusplus)
} // extern "C"
#endif
Modified: MacRuby/trunk/compiler.cpp
===================================================================
--- MacRuby/trunk/compiler.cpp 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/compiler.cpp 2010-05-24 02:24:56 UTC (rev 4136)
@@ -13,6 +13,7 @@
#endif
#include <llvm/LLVMContext.h>
+#include <llvm/Transforms/Utils/Cloning.h>
#include "llvm.h"
#include "ruby/ruby.h"
@@ -26,6 +27,7 @@
#include "encoding.h"
#include "re.h"
#include "bs.h"
+#include "class.h"
extern "C" const char *ruby_node_name(int node);
@@ -76,47 +78,52 @@
block_declaration = false;
dispatcherFunc = NULL;
- fastPlusFunc = NULL;
- fastMinusFunc = NULL;
- fastMultFunc = NULL;
- fastDivFunc = NULL;
- fastLtFunc = NULL;
- fastLeFunc = NULL;
- fastGtFunc = NULL;
- fastGeFunc = NULL;
- fastEqFunc = NULL;
- fastNeqFunc = NULL;
- fastEqqFunc = NULL;
- whenSplatFunc = NULL;
+ fastPlusFunc = get_function("vm_fast_plus");
+ fastMinusFunc = get_function("vm_fast_minus");
+ fastMultFunc = get_function("vm_fast_mult");
+ fastDivFunc = get_function("vm_fast_div");
+ fastLtFunc = get_function("vm_fast_lt");
+ fastLeFunc = get_function("vm_fast_le");
+ fastGtFunc = get_function("vm_fast_gt");
+ fastGeFunc = get_function("vm_fast_ge");
+ fastEqFunc = get_function("vm_fast_eq");
+ fastNeqFunc = get_function("vm_fast_neq");
+ fastEqqFunc = get_function("vm_fast_eqq");
+ fastArefFunc = get_function("vm_fast_aref");
+ fastAsetFunc = get_function("vm_fast_aset");
+ fastShiftFunc = get_function("vm_fast_shift");
+ whenSplatFunc = get_function("vm_when_splat");
prepareBlockFunc = NULL;
pushBindingFunc = NULL;
getBlockFunc = NULL;
currentBlockObjectFunc = NULL;
- getConstFunc = NULL;
- setConstFunc = NULL;
+ getConstFunc = get_function("vm_get_const");
+ setConstFunc = get_function("vm_set_const");
prepareMethodFunc = NULL;
singletonClassFunc = NULL;
defineClassFunc = NULL;
- prepareIvarSlotFunc = NULL;
- getIvarFunc = NULL;
- setIvarFunc = NULL;
- setKVOIvarFunc = NULL;
+ getIvarFunc = get_function("vm_ivar_get");
+ setIvarFunc = get_function("vm_ivar_set");
+ willChangeValueFunc = NULL;
+ didChangeValueFunc = NULL;
definedFunc = NULL;
undefFunc = NULL;
aliasFunc = NULL;
valiasFunc = NULL;
- newHashFunc = NULL;
- toAFunc = NULL;
- toAryFunc = NULL;
- catArrayFunc = NULL;
- dupArrayFunc = NULL;
- newArrayFunc = NULL;
+ newHashFunc = get_function("vm_rhash_new");
+ storeHashFunc = get_function("vm_rhash_store");
+ toAFunc = get_function("vm_to_a");
+ toAryFunc = get_function("vm_to_ary");
+ catArrayFunc = get_function("vm_ary_cat");
+ dupArrayFunc = get_function("vm_ary_dup");
+ newArrayFunc = get_function("vm_rary_new");
+ asetArrayFunc = get_function("vm_rary_aset");
newStructFunc = NULL;
newOpaqueFunc = NULL;
newPointerFunc = NULL;
getStructFieldsFunc = NULL;
getOpaqueDataFunc = NULL;
- getPointerPtrFunc = NULL;
+ getPointerPtrFunc = get_function("vm_rval_to_cptr");
xmallocFunc = NULL;
checkArityFunc = NULL;
setStructFunc = NULL;
@@ -124,9 +131,10 @@
newRegexpFunc = NULL;
strInternFunc = NULL;
keepVarsFunc = NULL;
- masgnGetElemBeforeSplatFunc = NULL;
- masgnGetElemAfterSplatFunc = NULL;
- masgnGetSplatFunc = NULL;
+ masgnGetElemBeforeSplatFunc =
+ get_function("vm_masgn_get_elem_before_splat");
+ masgnGetElemAfterSplatFunc = get_function("vm_masgn_get_elem_after_splat");
+ masgnGetSplatFunc = get_function("vm_masgn_get_splat");
newStringFunc = NULL;
newString2Func = NULL;
newString3Func = NULL;
@@ -135,25 +143,54 @@
blockEvalFunc = NULL;
gvarSetFunc = NULL;
gvarGetFunc = NULL;
- cvarSetFunc = NULL;
- cvarGetFunc = NULL;
+ cvarSetFunc = get_function("vm_cvar_set");
+ cvarGetFunc = get_function("vm_cvar_get");
currentExceptionFunc = NULL;
popExceptionFunc = NULL;
- getSpecialFunc = NULL;
+ getSpecialFunc = get_function("vm_get_special");
breakFunc = NULL;
returnFromBlockFunc = NULL;
returnedFromBlockFunc = NULL;
checkReturnFromBlockFunc = NULL;
setHasEnsureFunc = NULL;
- longjmpFunc = NULL;
- setjmpFunc = NULL;
- setScopeFunc = NULL;
+ setScopeFunc = get_function("vm_set_current_scope");
setCurrentClassFunc = NULL;
getCacheFunc = NULL;
debugTrapFunc = NULL;
getFFStateFunc = NULL;
setFFStateFunc = NULL;
takeOwnershipFunc = NULL;
+ ocvalToRvalFunc = get_function("vm_ocval_to_rval");
+ charToRvalFunc = get_function("vm_char_to_rval");
+ ucharToRvalFunc = get_function("vm_uchar_to_rval");
+ shortToRvalFunc = get_function("vm_short_to_rval");
+ ushortToRvalFunc = get_function("vm_ushort_to_rval");
+ intToRvalFunc = get_function("vm_int_to_rval");
+ uintToRvalFunc = get_function("vm_uint_to_rval");
+ longToRvalFunc = get_function("vm_long_to_rval");
+ ulongToRvalFunc = get_function("vm_ulong_to_rval");
+ longLongToRvalFunc = get_function("vm_long_long_to_rval");
+ ulongLongToRvalFunc = get_function("vm_ulong_long_to_rval");
+ floatToRvalFunc = get_function("vm_float_to_rval");
+ doubleToRvalFunc = get_function("vm_double_to_rval");
+ selToRvalFunc = get_function("vm_sel_to_rval");
+ charPtrToRvalFunc = get_function("vm_charptr_to_rval");
+ rvalToOcvalFunc = get_function("vm_rval_to_ocval");
+ rvalToBoolFunc = get_function("vm_rval_to_bool");
+ rvalToCharFunc = get_function("vm_rval_to_char");
+ rvalToUcharFunc = get_function("vm_rval_to_uchar");
+ rvalToShortFunc = get_function("vm_rval_to_short");
+ rvalToUshortFunc = get_function("vm_rval_to_ushort");
+ rvalToIntFunc = get_function("vm_rval_to_int");
+ rvalToUintFunc = get_function("vm_rval_to_uint");
+ rvalToLongFunc = get_function("vm_rval_to_long");
+ rvalToUlongFunc = get_function("vm_rval_to_ulong");
+ rvalToLongLongFunc = get_function("vm_rval_to_long_long");
+ rvalToUlongLongFunc = get_function("vm_rval_to_ulong_long");
+ rvalToFloatFunc = get_function("vm_rval_to_float");
+ rvalToDoubleFunc = get_function("vm_rval_to_double");
+ rvalToSelFunc = get_function("vm_rval_to_sel");
+ rvalToCharPtrFunc = get_function("vm_rval_to_charptr");
VoidTy = Type::getVoidTy(context);
Int1Ty = Type::getInt1Ty(context);
@@ -212,7 +249,7 @@
cStandardError_gvar = NULL;
}
-inline SEL
+SEL
RoxorCompiler::mid_to_sel(ID mid, int arity)
{
SEL sel;
@@ -228,24 +265,6 @@
return sel;
}
-inline bool
-RoxorCompiler::unbox_ruby_constant(Value *val, VALUE *rval)
-{
- if (ConstantInt::classof(val)) {
- long tmp = cast<ConstantInt>(val)->getZExtValue();
- *rval = tmp;
- return true;
- }
- return false;
-}
-
-inline ICmpInst *
-RoxorCompiler::is_value_a_fixnum(Value *val)
-{
- Value *andOp = BinaryOperator::CreateAnd(val, oneVal, "", bb);
- return new ICmpInst(*bb, ICmpInst::ICMP_EQ, andOp, oneVal);
-}
-
Instruction *
RoxorCompiler::compile_protected_call(Value *imp, std::vector<Value *> ¶ms)
{
@@ -423,80 +442,10 @@
}
Value *
-RoxorCompiler::compile_fast_op_call(SEL sel, Value *selfVal, Value *otherVal)
-{
- Function *func = NULL;
-
- // VALUE rb_vm_fast_op(struct mcache *cache, VALUE left, VALUE right);
-#define fast_op(storage, name) \
- do { \
- if (storage == NULL) { \
- storage = cast<Function>(module->getOrInsertFunction(name, \
- RubyObjTy, PtrTy, RubyObjTy, RubyObjTy, NULL)); \
- } \
- func = storage; \
- } \
- while (0)
-
- if (sel == selPLUS) {
- fast_op(fastPlusFunc, "rb_vm_fast_plus");
- }
- else if (sel == selMINUS) {
- fast_op(fastMinusFunc, "rb_vm_fast_minus");
- }
- else if (sel == selDIV) {
- fast_op(fastDivFunc, "rb_vm_fast_div");
- }
- else if (sel == selMULT) {
- fast_op(fastMultFunc, "rb_vm_fast_mult");
- }
- else if (sel == selLT) {
- fast_op(fastLtFunc, "rb_vm_fast_lt");
- }
- else if (sel == selLE) {
- fast_op(fastLeFunc, "rb_vm_fast_le");
- }
- else if (sel == selGT) {
- fast_op(fastGtFunc, "rb_vm_fast_gt");
- }
- else if (sel == selGE) {
- fast_op(fastGeFunc, "rb_vm_fast_ge");
- }
- else if (sel == selEq) {
- fast_op(fastEqFunc, "rb_vm_fast_eq");
- }
- else if (sel == selNeq) {
- fast_op(fastNeqFunc, "rb_vm_fast_neq");
- }
- else if (sel == selEqq) {
- fast_op(fastEqqFunc, "rb_vm_fast_eqq");
- }
- else {
- return NULL;
- }
-
- std::vector<Value *> params;
- params.push_back(compile_mcache(sel, false));
- params.push_back(selfVal);
- params.push_back(otherVal);
-
- return compile_protected_call(func, params);
-}
-
-Value *
RoxorCompiler::compile_when_splat(Value *comparedToVal, Value *splatVal)
{
- if (whenSplatFunc == NULL) {
- // VALUE rb_vm_when_splat(struct mcache *cache,
- // unsigned char overriden,
- // VALUE comparedTo, VALUE splat)
- whenSplatFunc = cast<Function>
- (module->getOrInsertFunction("rb_vm_when_splat",
- RubyObjTy, PtrTy, Int1Ty,
- RubyObjTy, RubyObjTy, NULL));
- }
-
std::vector<Value *> params;
+
params.push_back(compile_mcache(selEqq, false));
GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(selEqq, true);
params.push_back(new LoadInst(is_redefined, "", bb));
@@ -667,7 +616,7 @@
: new LoadInst(gvar, "");
}
-inline Value *
+Value *
RoxorCompiler::compile_arity(rb_vm_arity_t &arity)
{
uint64_t v;
@@ -880,37 +829,14 @@
RoxorCompiler::compile_multiple_assignment(NODE *node, Value *val)
{
assert(nd_type(node) == NODE_MASGN);
- if (toAryFunc == NULL) {
- // VALUE rb_vm_to_ary(VALUE ary);
- toAryFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_to_ary",
- RubyObjTy, RubyObjTy, NULL));
- }
- if (masgnGetElemBeforeSplatFunc == NULL) {
- // VALUE rb_vm_masgn_get_elem_before_splat(VALUE ary, int offset);
- masgnGetElemBeforeSplatFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_masgn_get_elem_before_splat",
- RubyObjTy, RubyObjTy, Int32Ty, NULL));
- }
- if (masgnGetElemAfterSplatFunc == NULL) {
- // VALUE rb_vm_masgn_get_elem_after_splat(VALUE ary, int before_splat_count, int after_splat_count, int offset);
- masgnGetElemAfterSplatFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_masgn_get_elem_after_splat",
- RubyObjTy, RubyObjTy, Int32Ty, Int32Ty, Int32Ty, NULL));
- }
- if (masgnGetSplatFunc == NULL) {
- // VALUE rb_vm_masgn_get_splat(VALUE ary, int before_splat_count, int after_splat_count);
- masgnGetSplatFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_masgn_get_splat",
- RubyObjTy, RubyObjTy, Int32Ty, Int32Ty, NULL));
- }
NODE *before_splat = node->nd_head, *after_splat = NULL, *splat = NULL;
assert((before_splat == NULL) || (nd_type(before_splat) == NODE_ARRAY));
// if the splat has no name (a, *, b = 1, 2, 3), its node value is -1
- if ((node->nd_next == (NODE *)-1) || (node->nd_next == NULL) || (nd_type(node->nd_next) != NODE_POSTARG)) {
+ if ((node->nd_next == (NODE *)-1) || (node->nd_next == NULL)
+ || (nd_type(node->nd_next) != NODE_POSTARG)) {
splat = node->nd_next;
}
else {
@@ -929,20 +855,18 @@
++after_splat_count;
}
- {
- std::vector<Value *> params;
- params.push_back(val);
- val = CallInst::Create(toAryFunc, params.begin(),
+ std::vector<Value *> params;
+ params.push_back(val);
+ val = CallInst::Create(toAryFunc, params.begin(),
params.end(), "", bb);
- }
NODE *l = before_splat;
for (int i = 0; l != NULL; ++i) {
std::vector<Value *> params;
params.push_back(val);
params.push_back(ConstantInt::get(Int32Ty, i));
- Value *elt = CallInst::Create(masgnGetElemBeforeSplatFunc, params.begin(),
- params.end(), "", bb);
+ Value *elt = CallInst::Create(masgnGetElemBeforeSplatFunc,
+ params.begin(), params.end(), "", bb);
compile_multiple_assignment_element(l->nd_head, elt);
@@ -967,8 +891,8 @@
params.push_back(ConstantInt::get(Int32Ty, before_splat_count));
params.push_back(ConstantInt::get(Int32Ty, after_splat_count));
params.push_back(ConstantInt::get(Int32Ty, i));
- Value *elt = CallInst::Create(masgnGetElemAfterSplatFunc, params.begin(),
- params.end(), "", bb);
+ Value *elt = CallInst::Create(masgnGetElemAfterSplatFunc,
+ params.begin(), params.end(), "", bb);
compile_multiple_assignment_element(l->nd_head, elt);
@@ -1158,13 +1082,6 @@
Value *
RoxorCompiler::compile_ivar_read(ID vid)
{
- if (getIvarFunc == NULL) {
- // VALUE rb_vm_ivar_get(VALUE obj, ID name, struct icache *cache);
- getIvarFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_ivar_get",
- RubyObjTy, RubyObjTy, IntTy, PtrTy, NULL));
- }
-
std::vector<Value *> params;
params.push_back(current_self);
@@ -1177,14 +1094,6 @@
Value *
RoxorCompiler::compile_ivar_assignment(ID vid, Value *val)
{
- if (setIvarFunc == NULL) {
- // void rb_vm_ivar_set(VALUE obj, ID name, VALUE val,
- // struct icache *cache);
- setIvarFunc =
- cast<Function>(module->getOrInsertFunction("rb_vm_ivar_set",
- VoidTy, RubyObjTy, IntTy, RubyObjTy, PtrTy, NULL));
- }
-
std::vector<Value *> params;
params.push_back(current_self);
@@ -1200,14 +1109,6 @@
Value *
RoxorCompiler::compile_cvar_get(ID id, bool check)
{
- if (cvarGetFunc == NULL) {
- // VALUE rb_vm_cvar_get(VALUE klass, ID id, unsigned char check,
- // unsigned char dynamic_class);
- cvarGetFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_cvar_get",
- RubyObjTy, RubyObjTy, IntTy, Int8Ty, Int8Ty, NULL));
- }
-
std::vector<Value *> params;
params.push_back(compile_current_class());
@@ -1221,14 +1122,6 @@
Value *
RoxorCompiler::compile_cvar_assignment(ID name, Value *val)
{
- if (cvarSetFunc == NULL) {
- // VALUE rb_vm_cvar_set(VALUE klass, ID id, VALUE val,
- // unsigned char dynamic_class);
- cvarSetFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_cvar_set",
- RubyObjTy, RubyObjTy, IntTy, RubyObjTy, Int8Ty, NULL));
- }
-
std::vector<Value *> params;
params.push_back(compile_current_class());
@@ -1261,15 +1154,6 @@
Value *
RoxorCompiler::compile_constant_declaration(NODE *node, Value *val)
{
- if (setConstFunc == NULL) {
- // VALUE rb_vm_set_const(VALUE mod, ID id, VALUE obj,
- // unsigned char dynamic_class);
- setConstFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_set_const",
- VoidTy, RubyObjTy, IntTy, RubyObjTy, Int8Ty,
- NULL));
- }
-
std::vector<Value *> params;
int flags = 0;
@@ -1303,13 +1187,13 @@
return new LoadInst(current_opened_class, "", bb);
}
-inline Value *
+Value *
RoxorCompiler::compile_nsobject(void)
{
return ConstantInt::get(RubyObjTy, rb_cObject);
}
-inline Value *
+Value *
RoxorAOTCompiler::compile_nsobject(void)
{
if (cObject_gvar == NULL) {
@@ -1320,13 +1204,13 @@
return new LoadInst(cObject_gvar, "", bb);
}
-inline Value *
+Value *
RoxorCompiler::compile_standarderror(void)
{
return ConstantInt::get(RubyObjTy, rb_eStandardError);
}
-inline Value *
+Value *
RoxorAOTCompiler::compile_standarderror(void)
{
if (cStandardError_gvar == NULL) {
@@ -1338,7 +1222,7 @@
return new LoadInst(cStandardError_gvar, "", bb);
}
-inline Value *
+Value *
RoxorCompiler::compile_id(ID id)
{
return ConstantInt::get(IntTy, (long)id);
@@ -1371,15 +1255,6 @@
outer_given = false;
}
- if (getConstFunc == NULL) {
- // VALUE rb_vm_get_const(VALUE mod, struct ccache *cache, ID id,
- // int flags);
- getConstFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_get_const",
- RubyObjTy, RubyObjTy, PtrTy, IntTy, Int32Ty,
- NULL));
- }
-
std::vector<Value *> params;
params.push_back(outer);
@@ -2011,233 +1886,7 @@
return CallInst::Create(currentExceptionFunc, "", bb);
}
-typedef struct rb_vm_immediate_val {
- int type;
- union {
- long l;
- double d;
- } v;
- rb_vm_immediate_val(void) { type = 0; }
- bool is_fixnum(void) { return type == T_FIXNUM; }
- bool is_float(void) { return type == T_FLOAT; }
- long long_val(void) { return is_fixnum() ? v.l : (long)v.d; }
- double double_val(void) { return is_float() ? v.d : (double)v.l; }
-} rb_vm_immediate_val_t;
-
-static bool
-unbox_immediate_val(VALUE rval, rb_vm_immediate_val_t *val)
-{
- if (rval != Qundef) {
- if (FIXNUM_P(rval)) {
- val->type = T_FIXNUM;
- val->v.l = FIX2LONG(rval);
- return true;
- }
- else if (FIXFLOAT_P(rval)) {
- val->type = T_FLOAT;
- val->v.d = FIXFLOAT2DBL(rval);
- return true;
- }
- }
- return false;
-}
-
-template <class T> static bool
-optimized_const_immediate_op(SEL sel, T leftVal, T rightVal,
- bool *is_predicate, T *res_p)
-{
- T res;
- if (sel == selPLUS) {
- res = leftVal + rightVal;
- }
- else if (sel == selMINUS) {
- res = leftVal - rightVal;
- }
- else if (sel == selDIV) {
- if (rightVal == 0) {
- return false;
- }
- res = leftVal / rightVal;
- }
- else if (sel == selMULT) {
- res = leftVal * rightVal;
- }
- else {
- *is_predicate = true;
- if (sel == selLT) {
- res = leftVal < rightVal;
- }
- else if (sel == selLE) {
- res = leftVal <= rightVal;
- }
- else if (sel == selGT) {
- res = leftVal > rightVal;
- }
- else if (sel == selGE) {
- res = leftVal >= rightVal;
- }
- else if (sel == selEq || sel == selEqq) {
- res = leftVal == rightVal;
- }
- else if (sel == selNeq) {
- res = leftVal != rightVal;
- }
- else {
- abort();
- }
- }
- *res_p = res;
- return true;
-}
-
Value *
-RoxorCompiler::optimized_immediate_op(SEL sel, Value *leftVal, Value *rightVal,
- bool float_op, bool *is_predicate)
-{
- Value *res;
- if (sel == selPLUS) {
- res = BinaryOperator::CreateAdd(leftVal, rightVal, "", bb);
- }
- else if (sel == selMINUS) {
- res = BinaryOperator::CreateSub(leftVal, rightVal, "", bb);
- }
- else if (sel == selDIV) {
- if (float_op) {
- res = BinaryOperator::CreateFDiv(leftVal, rightVal, "", bb);
- }
- else {
- // Fixnum division in Ruby is not a simple matter of returning the
- // division result. We must round up the result in case one of the
- // operands is negative.
-
- Value *normal_res = BinaryOperator::CreateSDiv(leftVal, rightVal,
- "", bb);
-
- ICmpInst *left_negative = new ICmpInst(*bb, ICmpInst::ICMP_SLT,
- leftVal, zeroVal);
-
- ICmpInst *right_negative = new ICmpInst(*bb, ICmpInst::ICMP_SLT,
- rightVal, zeroVal);
-
- Function *f = bb->getParent();
- BasicBlock *negative_bb = BasicBlock::Create(context, "", f);
- BasicBlock *check_right_bb = BasicBlock::Create(context, "", f);
- BasicBlock *try_right_bb = BasicBlock::Create(context, "", f);
- BasicBlock *hack_res_bb = BasicBlock::Create(context, "", f);
- BasicBlock *merge_bb = BasicBlock::Create(context, "", f);
-
- BranchInst::Create(check_right_bb, try_right_bb, left_negative, bb);
-
- bb = check_right_bb;
- BranchInst::Create(merge_bb, negative_bb, right_negative, bb);
-
- bb = try_right_bb;
- BranchInst::Create(negative_bb, merge_bb, right_negative, bb);
-
- bb = negative_bb;
- Value *rem = BinaryOperator::CreateSRem(leftVal, rightVal,
- "", bb);
- ICmpInst *hack_result = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- rem, zeroVal);
- BranchInst::Create(merge_bb, hack_res_bb, hack_result, bb);
-
- bb = hack_res_bb;
- Value *hacked_res = BinaryOperator::CreateSub(normal_res,
- ConstantInt::get(IntTy, 1), "", bb);
- BranchInst::Create(merge_bb, bb);
-
- bb = merge_bb;
- PHINode *pn = PHINode::Create(IntTy, "", bb);
- pn->addIncoming(hacked_res, hack_res_bb);
- pn->addIncoming(normal_res, check_right_bb);
- pn->addIncoming(normal_res, try_right_bb);
- pn->addIncoming(normal_res, negative_bb);
-
- return pn;
- }
- }
- else if (sel == selMULT) {
- res = BinaryOperator::CreateMul(leftVal, rightVal, "", bb);
- }
- else {
- *is_predicate = true;
-
- CmpInst::Predicate predicate;
-
- if (sel == selLT) {
- predicate = float_op ? FCmpInst::FCMP_OLT : ICmpInst::ICMP_SLT;
- }
- else if (sel == selLE) {
- predicate = float_op ? FCmpInst::FCMP_OLE : ICmpInst::ICMP_SLE;
- }
- else if (sel == selGT) {
- predicate = float_op ? FCmpInst::FCMP_OGT : ICmpInst::ICMP_SGT;
- }
- else if (sel == selGE) {
- predicate = float_op ? FCmpInst::FCMP_OGE : ICmpInst::ICMP_SGE;
- }
- else if (sel == selEq || sel == selEqq) {
- predicate = float_op ? FCmpInst::FCMP_OEQ : ICmpInst::ICMP_EQ;
- }
- else if (sel == selNeq) {
- predicate = float_op ? FCmpInst::FCMP_ONE : ICmpInst::ICMP_NE;
- }
- else {
- abort();
- }
-
- if (float_op) {
- res = new FCmpInst(*bb, predicate, leftVal, rightVal);
- }
- else {
- res = new ICmpInst(*bb, predicate, leftVal, rightVal);
- }
- res = SelectInst::Create(res, trueVal, falseVal, "", bb);
- }
- return res;
-}
-
-Value *
-RoxorCompiler::compile_double_coercion(Value *val, Value *mask,
- BasicBlock *fallback_bb, Function *f)
-{
- Value *is_float = new ICmpInst(*bb, ICmpInst::ICMP_EQ, mask, threeVal);
-
- BasicBlock *is_float_bb = BasicBlock::Create(context, "is_float", f);
- BasicBlock *isnt_float_bb = BasicBlock::Create(context, "isnt_float", f);
- BasicBlock *merge_bb = BasicBlock::Create(context, "merge", f);
-
- BranchInst::Create(is_float_bb, isnt_float_bb, is_float, bb);
-
- bb = is_float_bb;
- Value *is_float_val = BinaryOperator::CreateXor(val, threeVal, "", bb);
-#if __LP64__
- is_float_val = new BitCastInst(is_float_val, DoubleTy, "", bb);
-#else
- is_float_val = new BitCastInst(is_float_val, FloatTy, "", bb);
- is_float_val = new FPExtInst(is_float_val, DoubleTy, "", bb);
-#endif
- BranchInst::Create(merge_bb, bb);
-
- bb = isnt_float_bb;
- Value *is_fixnum = new ICmpInst(*bb, ICmpInst::ICMP_EQ, mask, oneVal);
- BasicBlock *is_fixnum_bb = BasicBlock::Create(context, "is_fixnum", f);
- BranchInst::Create(is_fixnum_bb, fallback_bb, is_fixnum, bb);
-
- bb = is_fixnum_bb;
- Value *is_fixnum_val = BinaryOperator::CreateAShr(val, twoVal, "", bb);
- is_fixnum_val = new SIToFPInst(is_fixnum_val, DoubleTy, "", bb);
- BranchInst::Create(merge_bb, bb);
-
- bb = merge_bb;
- PHINode *pn = PHINode::Create(DoubleTy, "op_tmp", bb);
- pn->addIncoming(is_float_val, is_float_bb);
- pn->addIncoming(is_fixnum_val, is_fixnum_bb);
-
- return pn;
-}
-
-Value *
RoxorCompiler::compile_optimized_dispatch_call(SEL sel, int argc,
std::vector<Value *> ¶ms)
{
@@ -2279,324 +1928,53 @@
return NULL;
}
- GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(sel, true);
-
Value *leftVal = params[2]; // self
Value *rightVal = params.back();
- VALUE leftRVal = Qundef, rightRVal = Qundef;
- const bool leftIsConstant = unbox_ruby_constant(leftVal, &leftRVal);
- const bool rightIsConst = unbox_ruby_constant(rightVal, &rightRVal);
-
- if (leftIsConstant && rightIsConst
- && TYPE(leftRVal) == T_SYMBOL && TYPE(rightRVal) == T_SYMBOL) {
- // Both operands are symbol constants.
- if (sel == selEq || sel == selEqq || sel == selNeq) {
- Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
- Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- is_redefined_val, ConstantInt::getFalse(context));
-
- Function *f = bb->getParent();
-
- BasicBlock *thenBB = BasicBlock::Create(context, "op_not_redefined", f);
- BasicBlock *elseBB = BasicBlock::Create(context, "op_dispatch", f);
- BasicBlock *mergeBB = BasicBlock::Create(context, "op_merge", f);
-
- BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
- Value *thenVal = NULL;
- if (sel == selEq || sel == selEqq) {
- thenVal = leftRVal == rightRVal ? trueVal : falseVal;
- }
- else if (sel == selNeq) {
- thenVal = leftRVal != rightRVal ? trueVal : falseVal;
- }
- else {
- abort();
- }
- BranchInst::Create(mergeBB, thenBB);
-
- bb = elseBB;
- Value *elseVal = compile_dispatch_call(params);
- elseBB = bb;
- BranchInst::Create(mergeBB, elseBB);
-
- PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
- pn->addIncoming(thenVal, thenBB);
- pn->addIncoming(elseVal, elseBB);
- bb = mergeBB;
-
- return pn;
- }
- else {
- return NULL;
- }
+ Function *func = NULL;
+ if (sel == selPLUS) {
+ func = fastPlusFunc;
}
-
- rb_vm_immediate_val_t leftImm, rightImm;
- const bool leftIsImmediateConst = unbox_immediate_val(leftRVal,
- &leftImm);
- const bool rightIsImmediateConst = unbox_immediate_val(rightRVal,
- &rightImm);
-
- if (leftIsImmediateConst && rightIsImmediateConst) {
- Value *res_val = NULL;
-
- if (leftImm.is_fixnum() && rightImm.is_fixnum()) {
- bool result_is_predicate = false;
- long res;
- if (optimized_const_immediate_op<long>(
- sel,
- leftImm.long_val(),
- rightImm.long_val(),
- &result_is_predicate,
- &res)) {
- if (result_is_predicate) {
- res_val = res == 1 ? trueVal : falseVal;
- }
- else if (FIXABLE(res)) {
- if (sel == selDIV) {
- // MRI compliant negative fixnum division.
- long x = leftImm.long_val();
- long y = rightImm.long_val();
- if (((x < 0 && y >= 0) || (x >= 0 && y < 0))
- && (x % y) != 0) {
- res--;
- }
- }
- res_val = ConstantInt::get(RubyObjTy, LONG2FIX(res));
- }
- }
- }
- else {
- bool result_is_predicate = false;
- double res;
- if (optimized_const_immediate_op<double>(
- sel,
- leftImm.double_val(),
- rightImm.double_val(),
- &result_is_predicate,
- &res)) {
- if (result_is_predicate) {
- res_val = res == 1 ? trueVal : falseVal;
- }
- else {
- res_val = ConstantInt::get(RubyObjTy,
- DBL2FIXFLOAT(res));
- }
- }
- }
-
- if (res_val != NULL) {
- Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
- Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- is_redefined_val, ConstantInt::getFalse(context));
-
- Function *f = bb->getParent();
-
- BasicBlock *thenBB = BasicBlock::Create(context, "op_not_redefined", f);
- BasicBlock *elseBB = BasicBlock::Create(context, "op_dispatch", f);
- BasicBlock *mergeBB = BasicBlock::Create(context, "op_merge", f);
-
- BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
- Value *thenVal = res_val;
- BranchInst::Create(mergeBB, thenBB);
-
- bb = elseBB;
- Value *elseVal = compile_dispatch_call(params);
- elseBB = bb;
- BranchInst::Create(mergeBB, elseBB);
-
- PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
- pn->addIncoming(thenVal, thenBB);
- pn->addIncoming(elseVal, elseBB);
- bb = mergeBB;
-
- return pn;
- }
- // Can't optimize, call the dispatcher.
- return NULL;
+ else if (sel == selMINUS) {
+ func = fastMinusFunc;
}
- else {
- // Either one or both is not a constant immediate.
- Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
- Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- is_redefined_val, ConstantInt::getFalse(context));
+ else if (sel == selDIV) {
+ func = fastDivFunc;
+ }
+ else if (sel == selMULT) {
+ func = fastMultFunc;
+ }
+ else if (sel == selLT) {
+ func = fastLtFunc;
+ }
+ else if (sel == selLE) {
+ func = fastLeFunc;
+ }
+ else if (sel == selGT) {
+ func = fastGtFunc;
+ }
+ else if (sel == selGE) {
+ func = fastGeFunc;
+ }
+ else if (sel == selEq) {
+ func = fastEqFunc;
+ }
+ else if (sel == selNeq) {
+ func = fastNeqFunc;
+ }
+ else if (sel == selEqq) {
+ func = fastEqqFunc;
+ }
+ assert(func != NULL);
- Function *f = bb->getParent();
+ std::vector<Value *> params;
+ params.push_back(compile_mcache(sel, false));
+ params.push_back(leftVal);
+ params.push_back(rightVal);
+ GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(sel, true);
+ params.push_back(new LoadInst(is_redefined, "", bb));
- BasicBlock *not_redefined_bb =
- BasicBlock::Create(context, "op_not_redefined", f);
- BasicBlock *optimize_fixnum_bb =
- BasicBlock::Create(context, "op_optimize_fixnum", f);
- BasicBlock *optimize_float_bb =
- BasicBlock::Create(context, "op_optimize_float", f);
- BasicBlock *dispatch_bb =
- BasicBlock::Create( context, "op_dispatch", f);
- BasicBlock *merge_bb = BasicBlock::Create(context, "op_merge", f);
-
- BranchInst::Create(not_redefined_bb, dispatch_bb, isOpRedefined,
- bb);
-
- bb = not_redefined_bb;
-
- Value *leftAndOp = NULL;
- if (!leftIsImmediateConst) {
- leftAndOp = BinaryOperator::CreateAnd(leftVal, threeVal, "",
- bb);
- }
-
- Value *rightAndOp = NULL;
- if (!rightIsImmediateConst) {
- rightAndOp = BinaryOperator::CreateAnd(rightVal, threeVal, "",
- bb);
- }
-
- if (leftAndOp != NULL && rightAndOp != NULL) {
- Value *leftIsFixnum = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- leftAndOp, oneVal);
- BasicBlock *left_is_fixnum_bb =
- BasicBlock::Create(context, "left_fixnum", f);
- BranchInst::Create(left_is_fixnum_bb, optimize_float_bb,
- leftIsFixnum, bb);
-
- bb = left_is_fixnum_bb;
- Value *rightIsFixnum = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- rightAndOp, oneVal);
- BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
- rightIsFixnum, bb);
- }
- else if (leftAndOp != NULL) {
- if (rightImm.is_fixnum()) {
- Value *leftIsFixnum = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- leftAndOp, oneVal);
- BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
- leftIsFixnum, bb);
- }
- else {
- BranchInst::Create(optimize_float_bb, bb);
- }
- }
- else if (rightAndOp != NULL) {
- if (leftImm.is_fixnum()) {
- Value *rightIsFixnum = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- rightAndOp, oneVal);
- BranchInst::Create(optimize_fixnum_bb, optimize_float_bb,
- rightIsFixnum, bb);
- }
- else {
- BranchInst::Create(optimize_float_bb, bb);
- }
- }
-
- bb = optimize_fixnum_bb;
-
- Value *unboxedLeft;
- if (leftIsImmediateConst) {
- unboxedLeft = ConstantInt::get(IntTy, leftImm.long_val());
- }
- else {
- unboxedLeft = BinaryOperator::CreateAShr(leftVal, twoVal, "",
- bb);
- }
-
- Value *unboxedRight;
- if (rightIsImmediateConst) {
- unboxedRight = ConstantInt::get(IntTy, rightImm.long_val());
- }
- else {
- unboxedRight = BinaryOperator::CreateAShr(rightVal, twoVal, "",
- bb);
- }
-
- bool result_is_predicate = false;
- Value *fix_op_res = optimized_immediate_op(sel, unboxedLeft,
- unboxedRight, false, &result_is_predicate);
-
- if (!result_is_predicate) {
- // Box the fixnum.
- Value *shift = BinaryOperator::CreateShl(fix_op_res, twoVal, "",
- bb);
- Value *boxed_op_res = BinaryOperator::CreateOr(shift, oneVal,
- "", bb);
-
- // Is result fixable?
- Value *fixnumMax = ConstantInt::get(IntTy, FIXNUM_MAX + 1);
- Value *isFixnumMaxOk = new ICmpInst(*bb, ICmpInst::ICMP_SLT,
- fix_op_res, fixnumMax);
-
- BasicBlock *fixable_max_bb =
- BasicBlock::Create(context, "op_fixable_max", f);
-
- BranchInst::Create(fixable_max_bb, dispatch_bb, isFixnumMaxOk,
- bb);
-
- bb = fixable_max_bb;
- Value *fixnumMin = ConstantInt::get(IntTy, FIXNUM_MIN);
- Value *isFixnumMinOk = new ICmpInst(*bb, ICmpInst::ICMP_SGE,
- fix_op_res, fixnumMin);
-
- BranchInst::Create(merge_bb, dispatch_bb, isFixnumMinOk, bb);
- fix_op_res = boxed_op_res;
- optimize_fixnum_bb = fixable_max_bb;
- }
- else {
- BranchInst::Create(merge_bb, bb);
- }
-
- bb = optimize_float_bb;
-
- if (leftIsImmediateConst) {
- unboxedLeft = ConstantFP::get(DoubleTy, leftImm.double_val());
- }
- else {
- unboxedLeft = compile_double_coercion(leftVal, leftAndOp,
- dispatch_bb, f);
- }
-
- if (rightIsImmediateConst) {
- unboxedRight = ConstantFP::get(DoubleTy, rightImm.double_val());
- }
- else {
- unboxedRight = compile_double_coercion(rightVal, rightAndOp,
- dispatch_bb, f);
- }
-
- result_is_predicate = false;
- Value *flp_op_res = optimized_immediate_op(sel, unboxedLeft,
- unboxedRight, true, &result_is_predicate);
-
- if (!result_is_predicate) {
- // Box the float.
-#if !__LP64__
- flp_op_res = new FPTruncInst(flp_op_res, FloatTy, "", bb);
-#endif
- flp_op_res = new BitCastInst(flp_op_res, RubyObjTy, "", bb);
- flp_op_res = BinaryOperator::CreateOr(flp_op_res, threeVal,
- "", bb);
- }
- optimize_float_bb = bb;
- BranchInst::Create(merge_bb, bb);
-
- bb = dispatch_bb;
- Value *dispatch_val = compile_fast_op_call(sel, leftVal, rightVal);
- if (dispatch_val == NULL) {
- dispatch_val = compile_dispatch_call(params);
- }
- dispatch_bb = bb;
- BranchInst::Create(merge_bb, bb);
-
- bb = merge_bb;
- PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", bb);
- pn->addIncoming(fix_op_res, optimize_fixnum_bb);
- pn->addIncoming(flp_op_res, optimize_float_bb);
- pn->addIncoming(dispatch_val, dispatch_bb);
-
-// if (sel == selEqq) {
-// pn->addIncoming(fastEqqVal, fastEqqBB);
-// }
-
- return pn;
- }
+ return compile_protected_call(func, params);
}
// Other operators (#<< or #[] or #[]=)
else if (sel == selLTLT || sel == selAREF || sel == selASET) {
@@ -2612,24 +1990,17 @@
return NULL;
}
- Function *opt_func = NULL;
-
+ Function *func = NULL;
if (sel == selLTLT) {
- opt_func = cast<Function>(module->getOrInsertFunction("rb_vm_fast_shift",
- RubyObjTy, RubyObjTy, RubyObjTy, PtrTy, Int1Ty, NULL));
+ func = fastShiftFunc;
}
else if (sel == selAREF) {
- opt_func = cast<Function>(module->getOrInsertFunction("rb_vm_fast_aref",
- RubyObjTy, RubyObjTy, RubyObjTy, PtrTy, Int1Ty, NULL));
+ func = fastArefFunc;
}
else if (sel == selASET) {
- opt_func = cast<Function>(module->getOrInsertFunction("rb_vm_fast_aset",
- RubyObjTy, RubyObjTy, RubyObjTy, RubyObjTy, PtrTy,
- Int1Ty, NULL));
+ func = fastAsetFunc;
}
- else {
- abort();
- }
+ assert(func != NULL);
std::vector<Value *> new_params;
new_params.push_back(params[2]); // self
@@ -2644,7 +2015,7 @@
GlobalVariable *is_redefined = GET_CORE()->redefined_op_gvar(sel, true);
new_params.push_back(new LoadInst(is_redefined, "", bb));
- return compile_protected_call(opt_func, new_params);
+ return compile_protected_call(func, new_params);
}
// #send or #__send__
else if (sel == selSend || sel == sel__send__) {
@@ -2666,7 +2037,7 @@
Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
Value *isOpRedefined = new ICmpInst(*bb, ICmpInst::ICMP_EQ,
- is_redefined_val, ConstantInt::getFalse(context));
+ is_redefined_val, ConstantInt::get(Int8Ty, 0));
Function *f = bb->getParent();
@@ -2705,118 +2076,6 @@
return pn;
}
-#if 0
- // XXX this optimization is disabled because it's buggy and not really
- // interesting
- // #eval
- else if (sel == selEval) {
-
- if (current_block_func != NULL || argc != 1) {
- return NULL;
- }
- Value *strVal = params.back();
- if (!ConstantInt::classof(strVal)) {
- return NULL;
- }
- VALUE str = cast<ConstantInt>(strVal)->getZExtValue();
- if (TYPE(str) != T_STRING) {
- return NULL;
- }
- // FIXME:
- // - pass the real file/line arguments
- // - catch potential parsing exceptions
- NODE *new_node = rb_compile_string("", str, 0);
- if (new_node == NULL) {
- return NULL;
- }
- if (nd_type(new_node) != NODE_SCOPE || new_node->nd_body == NULL) {
- return NULL;
- }
-
- GlobalVariable *is_redefined = GET_VM()->redefined_op_gvar(sel, true);
-
- Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
- Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ,
- is_redefined_val, ConstantInt::getFalse(), "", bb);
-
- Function *f = bb->getParent();
-
- BasicBlock *thenBB = BasicBlock::Create("op_not_redefined", f);
- BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
- BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
-
- BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
-
- bb = thenBB;
- Value *thenVal = compile_node(new_node->nd_body);
- thenBB = bb;
- BranchInst::Create(mergeBB, thenBB);
-
- bb = elseBB;
- Value *elseVal = compile_dispatch_call(params);
- BranchInst::Create(mergeBB, elseBB);
-
- bb = mergeBB;
- PHINode *pn = PHINode::Create(RubyObjTy, "op_tmp", mergeBB);
- pn->addIncoming(thenVal, thenBB);
- pn->addIncoming(elseVal, elseBB);
-
- return pn;
-
- }
-#endif
-#if 0
- // TODO: block inlining optimization
- else if (current_block_func != NULL) {
- static SEL selTimes = 0;
- if (selTimes == 0) {
- selTimes = rb_intern("times");
- }
-
- if (sel == selTimes && argc == 0) {
- Value *val = params[1]; // self
-
- long valLong;
- if (unbox_fixnum_constant(val, &valLong)) {
- GlobalVariable *is_redefined = redefined_op_gvar(sel, true);
-
- Value *is_redefined_val = new LoadInst(is_redefined, "", bb);
- Value *isOpRedefined = new ICmpInst(ICmpInst::ICMP_EQ, is_redefined_val, ConstantInt::getFalse(), "", bb);
-
- Function *f = bb->getParent();
-
- BasicBlock *thenBB = BasicBlock::Create("op_not_redefined", f);
- BasicBlock *elseBB = BasicBlock::Create("op_dispatch", f);
- BasicBlock *mergeBB = BasicBlock::Create("op_merge", f);
-
- BranchInst::Create(thenBB, elseBB, isOpRedefined, bb);
- bb = thenBB;
-
-
-
-// Val *mem = new AllocaInst(RubyObjTy, "", bb);
-// new StoreInst(zeroVal, mem, "", bb);
-// Val *i = LoadInst(mem, "", bb);
-
-
-
- Value *thenVal = val;
- BranchInst::Create(mergeBB, thenBB);
-
- Value *elseVal = dispatchCall;
- elseBB->getInstList().push_back(dispatchCall);
- BranchInst::Create(mergeBB, elseBB);
-
- PHINode *pn = PHINode::Create(Type::Int32Ty, "op_tmp", mergeBB);
- pn->addIncoming(thenVal, thenBB);
- pn->addIncoming(elseVal, elseBB);
- bb = mergeBB;
-
- return pn;
- }
- }
- }
-#endif
return NULL;
}
@@ -2978,14 +2237,8 @@
void
RoxorCompiler::compile_set_current_scope(Value *klass, Value *scope)
{
- if (setScopeFunc == NULL) {
- // void rb_vm_set_current_scope(VALUE mod, int scope)
- setScopeFunc = cast<Function>(
- module->getOrInsertFunction("rb_vm_set_current_scope",
- VoidTy, RubyObjTy, Int32Ty, NULL));
- }
-
std::vector<Value *> params;
+
params.push_back(klass);
params.push_back(scope);
@@ -3048,6 +2301,35 @@
BranchInst::Create(mergeBB, bb);
}
+bool
+RoxorCompiler::should_inline_function(Function *f)
+{
+ return f->getName().startswith("vm_");
+}
+
+void
+RoxorCompiler::inline_function_calls(Function *f)
+{
+ std::vector<CallInst *> insns;
+
+ for (Function::iterator fi = f->begin(); fi != f->end(); ++fi) {
+ for (BasicBlock::iterator bi = fi->begin(); bi != fi->end(); ++bi) {
+ CallInst *insn = dyn_cast<CallInst>(bi);
+ if (insn != NULL) {
+ Function *called = insn->getCalledFunction();
+ if (called != NULL && should_inline_function(called)) {
+ insns.push_back(insn);
+ }
+ }
+ }
+ }
+
+ for (std::vector<CallInst *>::iterator i = insns.begin();
+ i != insns.end(); ++i) {
+ InlineFunction(*i);
+ }
+}
+
Function *
RoxorCompiler::compile_scope(NODE *node)
{
@@ -4410,36 +3692,25 @@
return compile_const(node->nd_vid, NULL);
case NODE_CDECL:
- {
- assert(node->nd_value != NULL);
- return compile_constant_declaration(node, compile_node(node->nd_value));
- }
- break;
+ assert(node->nd_value != NULL);
+ return compile_constant_declaration(node,
+ compile_node(node->nd_value));
case NODE_IASGN:
case NODE_IASGN2:
- {
- assert(node->nd_vid > 0);
- assert(node->nd_value != NULL);
- return compile_ivar_assignment(node->nd_vid,
- compile_node(node->nd_value));
- }
- break;
+ assert(node->nd_vid > 0);
+ assert(node->nd_value != NULL);
+ return compile_ivar_assignment(node->nd_vid,
+ compile_node(node->nd_value));
case NODE_IVAR:
- {
- assert(node->nd_vid > 0);
- return compile_ivar_read(node->nd_vid);
- }
- break;
+ assert(node->nd_vid > 0);
+ return compile_ivar_read(node->nd_vid);
case NODE_LIT:
case NODE_STR:
- {
- assert(node->nd_lit != 0);
- return compile_literal(node->nd_lit);
- }
- break;
+ assert(node->nd_lit != 0);
+ return compile_literal(node->nd_lit);
case NODE_ARGSCAT:
case NODE_ARGSPUSH:
@@ -4447,12 +3718,6 @@
assert(node->nd_head != NULL);
Value *ary = compile_node(node->nd_head);
- if (dupArrayFunc == NULL) {
- dupArrayFunc = cast<Function>(
- module->getOrInsertFunction("rb_ary_dup",
- RubyObjTy, RubyObjTy, NULL));
- }
-
std::vector<Value *> params;
params.push_back(ary);
@@ -4461,13 +3726,6 @@
assert(node->nd_body != NULL);
Value *other = compile_node(node->nd_body);
- if (catArrayFunc == NULL) {
- // VALUE rb_vm_ary_cat(VALUE obj);
- catArrayFunc = cast<Function>(
- module->getOrInsertFunction("rb_vm_ary_cat",
- RubyObjTy, RubyObjTy, RubyObjTy, NULL));
- }
-
params.clear();
params.push_back(ary);
params.push_back(other);
@@ -4482,13 +3740,6 @@
Value *val = compile_node(node->nd_head);
if (nd_type(node->nd_head) != NODE_ARRAY) {
- if (toAFunc == NULL) {
- // VALUE rb_vm_to_a(VALUE obj);
- toAFunc = cast<Function>(
- module->getOrInsertFunction("rb_vm_to_a",
- RubyObjTy, RubyObjTy, NULL));
- }
-
std::vector<Value *> params;
params.push_back(val);
val = compile_protected_call(toAFunc, params);
@@ -4502,46 +3753,47 @@
case NODE_ZARRAY:
case NODE_VALUES:
{
- if (newArrayFunc == NULL) {
- // VALUE rb_ary_new3(int argc, ...);
- std::vector<const Type *> types;
- types.push_back(Int32Ty);
- FunctionType *ft = FunctionType::get(RubyObjTy, types, true);
- newArrayFunc = cast<Function>(module->getOrInsertFunction(
- "rb_ary_new3", ft));
- }
+ Value *ary;
- std::vector<Value *> params;
-
if (nd_type(node) == NODE_ZARRAY) {
+ std::vector<Value *> params;
params.push_back(ConstantInt::get(Int32Ty, 0));
+
+ ary = CallInst::Create(newArrayFunc, params.begin(),
+ params.end(), "", bb);
}
else {
const int count = node->nd_alen;
- NODE *n = node;
-
+ std::vector<Value *> params;
params.push_back(ConstantInt::get(Int32Ty, count));
+ ary = CallInst::Create(newArrayFunc, params.begin(),
+ params.end(), "", bb);
+
+ NODE *n = node;
for (int i = 0; i < count; i++) {
assert(n->nd_head != NULL);
- params.push_back(compile_node(n->nd_head));
+ Value *elem = compile_node(n->nd_head);
+
+ params.clear();
+ params.push_back(ary);
+ params.push_back(ConstantInt::get(Int32Ty, i));
+ params.push_back(elem);
+
+ CallInst::Create(asetArrayFunc, params.begin(),
+ params.end(), "", bb);
+
n = n->nd_next;
}
}
- return cast<Value>(CallInst::Create(newArrayFunc, params.begin(), params.end(), "", bb));
+ return ary;
}
break;
case NODE_HASH:
{
- if (newHashFunc == NULL) {
- // VALUE rb_hash_new_fast(int argc, ...);
- std::vector<const Type *> types;
- types.push_back(Int32Ty);
- FunctionType *ft = FunctionType::get(RubyObjTy, types, true);
- newHashFunc = cast<Function>(module->getOrInsertFunction("rb_hash_new_fast", ft));
- }
+ Value *hash = CallInst::Create(newHashFunc, "", bb);
std::vector<Value *> params;
@@ -4551,53 +3803,43 @@
assert(count % 2 == 0);
NODE *n = node->nd_head;
- params.push_back(ConstantInt::get(Int32Ty, count));
-
for (int i = 0; i < count; i += 2) {
Value *key = compile_node(n->nd_head);
n = n->nd_next;
Value *val = compile_node(n->nd_head);
n = n->nd_next;
+ std::vector<Value *> params;
+
+ params.push_back(hash);
params.push_back(key);
params.push_back(val);
+
+ CallInst::Create(storeHashFunc, params.begin(),
+ params.end(), "", bb);
}
}
- else {
- params.push_back(ConstantInt::get(Int32Ty, 0));
- }
- return cast<Value>(CallInst::Create(newHashFunc,
- params.begin(), params.end(), "", bb));
+ return hash;
}
break;
case NODE_DOT2:
case NODE_DOT3:
- {
- assert(node->nd_beg != NULL);
- assert(node->nd_end != NULL);
+ assert(node->nd_beg != NULL);
+ assert(node->nd_end != NULL);
+ return compile_range(compile_node(node->nd_beg),
+ compile_node(node->nd_end), nd_type(node) == NODE_DOT3);
- return compile_range(compile_node(node->nd_beg),
- compile_node(node->nd_end),
- nd_type(node) == NODE_DOT3);
- }
- break;
-
case NODE_FLIP2:
case NODE_FLIP3:
- {
- assert(node->nd_beg != NULL);
- assert(node->nd_end != NULL);
+ assert(node->nd_beg != NULL);
+ assert(node->nd_end != NULL);
- if (nd_type(node) == NODE_FLIP2) {
- return compile_ff2(node);
- }
- else {
- return compile_ff3(node);
- }
+ if (nd_type(node) == NODE_FLIP2) {
+ return compile_ff2(node);
}
- break;
+ return compile_ff3(node);
case NODE_BLOCK:
{
@@ -4606,7 +3848,8 @@
DEBUG_LEVEL_INC();
while (n != NULL && nd_type(n) == NODE_BLOCK) {
- val = n->nd_head == NULL ? nilVal : compile_node(n->nd_head);
+ val = n->nd_head == NULL
+ ? nilVal : compile_node(n->nd_head);
n = n->nd_next;
}
DEBUG_LEVEL_DEC();
@@ -4803,24 +4046,18 @@
case NODE_NTH_REF:
case NODE_BACK_REF:
{
- char code = (char)node->nd_nth;
-
- if (getSpecialFunc == NULL) {
- // VALUE rb_vm_get_special(char code);
- getSpecialFunc =
- cast<Function>(module->getOrInsertFunction("rb_vm_get_special",
- RubyObjTy, Int8Ty, NULL));
- }
-
std::vector<Value *> params;
+ char code = (char)node->nd_nth;
params.push_back(ConstantInt::get(Int8Ty, code));
- return CallInst::Create(getSpecialFunc, params.begin(), params.end(), "", bb);
+ return CallInst::Create(getSpecialFunc, params.begin(),
+ params.end(), "", bb);
}
break;
case NODE_BEGIN:
- return node->nd_body == NULL ? nilVal : compile_node(node->nd_body);
+ return node->nd_body == NULL
+ ? nilVal : compile_node(node->nd_body);
case NODE_RESCUE:
{
@@ -4850,7 +4087,8 @@
rescue_invoke_bb = old_rescue_invoke_bb;
if (node->nd_else != NULL) {
- BasicBlock *else_bb = BasicBlock::Create(context, "else", f);
+ BasicBlock *else_bb = BasicBlock::Create(context, "else",
+ f);
BranchInst::Create(else_bb, bb);
bb = else_bb;
not_rescued_val = compile_node(node->nd_else);
@@ -4859,10 +4097,12 @@
BasicBlock *not_rescued_bb = bb;
BranchInst::Create(merge_bb, not_rescued_bb);
- PHINode *pn = PHINode::Create(RubyObjTy, "rescue_result", merge_bb);
+ PHINode *pn = PHINode::Create(RubyObjTy, "rescue_result",
+ merge_bb);
pn->addIncoming(not_rescued_val, not_rescued_bb);
- if (new_rescue_invoke_bb->use_empty() && new_rescue_rethrow_bb->use_empty()) {
+ if (new_rescue_invoke_bb->use_empty()
+ && new_rescue_rethrow_bb->use_empty()) {
new_rescue_invoke_bb->eraseFromParent();
new_rescue_rethrow_bb->eraseFromParent();
}
@@ -5356,7 +4596,8 @@
if (rb_is_const_id(node->nd_mid)) {
// Constant
assert(node->nd_head != NULL);
- return compile_const(node->nd_mid, compile_node(node->nd_head));
+ return compile_const(node->nd_mid,
+ compile_node(node->nd_head));
}
else {
// Method call
@@ -5562,7 +4803,7 @@
}
// Compile constant caches.
-
+
Function *getConstCacheFunc = cast<Function>(module->getOrInsertFunction(
"rb_vm_get_constant_cache",
PtrTy, PtrTy, NULL));
@@ -5597,11 +4838,8 @@
}
// Compile selectors.
+ Function *registerSelFunc = get_function("sel_registerName");
- Function *registerSelFunc = cast<Function>(module->getOrInsertFunction(
- "sel_registerName",
- PtrTy, PtrTy, NULL));
-
for (std::map<SEL, GlobalVariable *>::iterator i = sels.begin();
i != sels.end();
++i) {
@@ -5624,9 +4862,12 @@
Instruction *call = CallInst::Create(registerSelFunc, params.begin(),
params.end(), "");
- Instruction *assign = new StoreInst(call, gvar, "");
+ Instruction *cast = new BitCastInst(call, PtrTy, "");
+
+ Instruction *assign = new StoreInst(cast, gvar, "");
list.insert(list.begin(), assign);
+ list.insert(list.begin(), cast);
list.insert(list.begin(), call);
list.insert(list.begin(), load);
}
@@ -5878,10 +5119,6 @@
// Compile constant class references.
- Function *objcGetClassFunc = cast<Function>(module->getOrInsertFunction(
- "objc_getClass",
- RubyObjTy, PtrTy, NULL));
-
for (std::vector<GlobalVariable *>::iterator i = class_gvars.begin();
i != class_gvars.end();
++i) {
@@ -5900,7 +5137,7 @@
std::vector<Value *> params;
params.push_back(load);
- Instruction *call = CallInst::Create(objcGetClassFunc, params.begin(),
+ Instruction *call = CallInst::Create(getClassFunc, params.begin(),
params.end(), "");
Instruction *assign = new StoreInst(call, gvar, "");
@@ -5945,10 +5182,8 @@
bb = BasicBlock::Create(context, "EntryBlock", f);
- Value *val = compile_ivar_read(name);
+ ReturnInst::Create(context, compile_ivar_read(name), bb);
- ReturnInst::Create(context, val, bb);
-
return f;
}
@@ -5965,22 +5200,39 @@
bb = BasicBlock::Create(context, "EntryBlock", f);
- if (setKVOIvarFunc == NULL) {
- setKVOIvarFunc =
- cast<Function>(module->getOrInsertFunction("rb_vm_set_kvo_ivar",
- RubyObjTy, RubyObjTy, RubyObjTy, RubyObjTy, PtrTy,
- NULL));
- }
+ Value *val;
+ if (rb_objc_enable_ivar_set_kvo_notifications) {
+ VALUE tmp = rb_id2str(name);
+ VALUE str = rb_str_substr(tmp, 1, rb_str_chars_len(tmp) - 1);
- std::vector<Value *> params;
- params.push_back(current_self);
- params.push_back(compile_id(name));
- params.push_back(new_val);
- params.push_back(compile_slot_cache(name));
+ std::vector<Value *> params;
+ params.push_back(current_self);
+ params.push_back(compile_immutable_literal(str));
- Value *val = CallInst::Create(setKVOIvarFunc,
- params.begin(), params.end(), "", bb);
+ if (willChangeValueFunc == NULL) {
+ willChangeValueFunc =
+ cast<Function>(module->getOrInsertFunction(
+ "rb_objc_willChangeValueForKey",
+ VoidTy, RubyObjTy, RubyObjTy, NULL));
+ }
+ CallInst::Create(willChangeValueFunc, params.begin(), params.end(),
+ "", bb);
+ val = compile_ivar_assignment(name, new_val);
+
+ if (didChangeValueFunc == NULL) {
+ didChangeValueFunc =
+ cast<Function>(module->getOrInsertFunction(
+ "rb_objc_didChangeValueForKey",
+ VoidTy, RubyObjTy, RubyObjTy, NULL));
+ }
+ CallInst::Create(didChangeValueFunc, params.begin(), params.end(),
+ "", bb);
+ }
+ else {
+ val = compile_ivar_assignment(name, new_val);
+ }
+
ReturnInst::Create(context, val, bb);
return f;
@@ -5996,208 +5248,7 @@
type);
}
-extern "C"
void
-rb_vm_rval_to_ocval(VALUE rval, id *ocval)
-{
- *ocval = rval == Qnil ? NULL : RB2OC(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_bool(VALUE rval, BOOL *ocval)
-{
- switch (TYPE(rval)) {
- case T_FALSE:
- case T_NIL:
- *ocval = NO;
- break;
-
- default:
- // All other types should be converted as true, to follow the Ruby
- // semantics (where for example any integer is always true, even 0).
- *ocval = YES;
- break;
- }
-}
-
-static inline const char *
-rval_to_c_str(VALUE rval)
-{
- if (NIL_P(rval)) {
- return NULL;
- }
- else {
- switch (TYPE(rval)) {
- case T_SYMBOL:
- return rb_sym2name(rval);
- }
- if (rb_obj_is_kind_of(rval, rb_cPointer)) {
- return (const char *)rb_pointer_get_data(rval, "^c");
- }
- return StringValueCStr(rval);
- }
-}
-
-extern "C"
-void
-rb_vm_rval_to_ocsel(VALUE rval, SEL *ocval)
-{
- const char *cstr = rval_to_c_str(rval);
- *ocval = cstr == NULL ? NULL : sel_registerName(cstr);
-}
-
-extern "C"
-void
-rb_vm_rval_to_charptr(VALUE rval, const char **ocval)
-{
- *ocval = rval_to_c_str(rval);
-}
-
-static inline long
-bool_to_fix(VALUE rval)
-{
- if (rval == Qtrue) {
- return INT2FIX(1);
- }
- if (rval == Qfalse) {
- return INT2FIX(0);
- }
- return rval;
-}
-
-static inline long
-rval_to_long(VALUE rval)
-{
- return NUM2LONG(rb_Integer(bool_to_fix(rval)));
-}
-
-static inline long long
-rval_to_long_long(VALUE rval)
-{
- return NUM2LL(rb_Integer(bool_to_fix(rval)));
-}
-
-static inline double
-rval_to_double(VALUE rval)
-{
- return RFLOAT_VALUE(rb_Float(bool_to_fix(rval)));
-}
-
-extern "C"
-void
-rb_vm_rval_to_chr(VALUE rval, char *ocval)
-{
- if (TYPE(rval) == T_STRING && RSTRING_LEN(rval) == 1) {
- *ocval = (char)RSTRING_PTR(rval)[0];
- }
- else {
- *ocval = (char)rval_to_long(rval);
- }
-}
-
-extern "C"
-void
-rb_vm_rval_to_uchr(VALUE rval, unsigned char *ocval)
-{
- if (TYPE(rval) == T_STRING && RSTRING_LEN(rval) == 1) {
- *ocval = (unsigned char)RSTRING_PTR(rval)[0];
- }
- else {
- *ocval = (unsigned char)rval_to_long(rval);
- }
-}
-
-extern "C"
-void
-rb_vm_rval_to_short(VALUE rval, short *ocval)
-{
- *ocval = (short)rval_to_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_ushort(VALUE rval, unsigned short *ocval)
-{
- *ocval = (unsigned short)rval_to_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_int(VALUE rval, int *ocval)
-{
- *ocval = (int)rval_to_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_uint(VALUE rval, unsigned int *ocval)
-{
- *ocval = (unsigned int)rval_to_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_long(VALUE rval, long *ocval)
-{
- *ocval = (long)rval_to_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_ulong(VALUE rval, unsigned long *ocval)
-{
- *ocval = (unsigned long)rval_to_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_long_long(VALUE rval, long long *ocval)
-{
- *ocval = (long long)rval_to_long_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_ulong_long(VALUE rval, unsigned long long *ocval)
-{
- *ocval = (unsigned long long)rval_to_long_long(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_double(VALUE rval, double *ocval)
-{
- *ocval = (double)rval_to_double(rval);
-}
-
-extern "C"
-void
-rb_vm_rval_to_float(VALUE rval, float *ocval)
-{
- *ocval = (float)rval_to_double(rval);
-}
-
-extern "C"
-void *
-rb_vm_rval_to_cptr(VALUE rval, const char *type, void **cptr)
-{
- if (NIL_P(rval)) {
- *cptr = NULL;
- }
- else {
- if (TYPE(rval) == T_ARRAY
- || rb_boxed_is_type(CLASS_OF(rval), type + 1)) {
- // A convenience helper so that the user can pass a Boxed or an
- // Array object instead of a Pointer to the object.
- rval = rb_pointer_new2(type + 1, rval);
- }
- *cptr = rb_pointer_get_data(rval, type);
- }
- return *cptr;
-}
-
-void
RoxorCompiler::compile_get_struct_fields(Value *val, Value *buf,
rb_vm_bs_boxed_t *bs_boxed)
{
@@ -6259,13 +5310,8 @@
Value *
RoxorCompiler::compile_get_cptr(Value *val, const char *type, Value *slot)
{
- if (getPointerPtrFunc == NULL) {
- getPointerPtrFunc = cast<Function>(module->getOrInsertFunction(
- "rb_vm_rval_to_cptr",
- PtrTy, RubyObjTy, PtrTy, PtrPtrTy, NULL));
- }
-
std::vector<Value *> params;
+
params.push_back(val);
params.push_back(compile_const_pointer(sel_registerName(type)));
params.push_back(new BitCastInst(slot, PtrPtrTy, "", bb));
@@ -6277,78 +5323,78 @@
RoxorCompiler::compile_conversion_to_c(const char *type, Value *val,
Value *slot)
{
- const char *func_name = NULL;
-
type = SkipTypeModifiers(type);
if (*type == _C_PTR && GET_CORE()->find_bs_cftype(type) != NULL) {
type = "@";
}
+ Function *func = NULL;
+
switch (*type) {
case _C_ID:
case _C_CLASS:
- func_name = "rb_vm_rval_to_ocval";
+ func = rvalToOcvalFunc;
break;
case _C_BOOL:
- func_name = "rb_vm_rval_to_bool";
+ func = rvalToBoolFunc;
break;
case _C_CHR:
- func_name = "rb_vm_rval_to_chr";
+ func = rvalToCharFunc;
break;
case _C_UCHR:
- func_name = "rb_vm_rval_to_uchr";
+ func = rvalToUcharFunc;
break;
case _C_SHT:
- func_name = "rb_vm_rval_to_short";
+ func = rvalToShortFunc;
break;
case _C_USHT:
- func_name = "rb_vm_rval_to_ushort";
+ func = rvalToUshortFunc;
break;
case _C_INT:
- func_name = "rb_vm_rval_to_int";
+ func = rvalToIntFunc;
break;
case _C_UINT:
- func_name = "rb_vm_rval_to_uint";
+ func = rvalToUintFunc;
break;
case _C_LNG:
- func_name = "rb_vm_rval_to_long";
+ func = rvalToLongFunc;
break;
case _C_ULNG:
- func_name = "rb_vm_rval_to_ulong";
+ func = rvalToUlongFunc;
break;
case _C_LNG_LNG:
- func_name = "rb_vm_rval_to_long_long";
+ func = rvalToLongLongFunc;
break;
case _C_ULNG_LNG:
- func_name = "rb_vm_rval_to_ulong_long";
+ func = rvalToUlongLongFunc;
break;
case _C_FLT:
- func_name = "rb_vm_rval_to_float";
+ func = rvalToFloatFunc;
break;
case _C_DBL:
- func_name = "rb_vm_rval_to_double";
+ func = rvalToDoubleFunc;
break;
case _C_SEL:
- func_name = "rb_vm_rval_to_ocsel";
+ func = rvalToSelFunc;
break;
case _C_CHARPTR:
- func_name = "rb_vm_rval_to_charptr";
+ func = rvalToCharPtrFunc;
break;
case _C_STRUCT_B:
@@ -6509,7 +5555,7 @@
break;
}
- if (func_name == NULL) {
+ if (func == NULL) {
rb_raise(rb_eTypeError, "unrecognized compile type `%s' to C", type);
}
@@ -6517,79 +5563,12 @@
params.push_back(val);
params.push_back(slot);
- Function *func = cast<Function>(module->getOrInsertFunction(
- func_name, VoidTy, RubyObjTy,
- PointerType::getUnqual(convert_type(type)), NULL));
-
CallInst::Create(func, params.begin(), params.end(), "", bb);
return new LoadInst(slot, "", bb);
}
extern "C"
VALUE
-rb_vm_ocval_to_rval(id ocval)
-{
- return OC2RB(ocval);
-}
-
-extern "C"
-VALUE
-rb_vm_long_to_rval(long l)
-{
- return INT2NUM(l);
-}
-
-extern "C"
-VALUE
-rb_vm_ulong_to_rval(long l)
-{
- return UINT2NUM(l);
-}
-
-extern "C"
-VALUE
-rb_vm_long_long_to_rval(long long l)
-{
- return LL2NUM(l);
-}
-
-extern "C"
-VALUE
-rb_vm_ulong_long_to_rval(unsigned long long l)
-{
- return ULL2NUM(l);
-}
-
-extern "C"
-VALUE
-rb_vm_sel_to_rval(SEL sel)
-{
- return sel == 0 ? Qnil : ID2SYM(rb_intern(sel_getName(sel)));
-}
-
-extern "C"
-VALUE
-rb_vm_float_to_rval(float f)
-{
- return DOUBLE2NUM(f);
-}
-
-extern "C"
-VALUE
-rb_vm_double_to_rval(double d)
-{
- return DOUBLE2NUM(d);
-}
-
-extern "C"
-VALUE
-rb_vm_charptr_to_rval(const char *ptr)
-{
- return ptr == NULL ? Qnil : rb_str_new2(ptr);
-}
-
-extern "C"
-VALUE
rb_vm_new_struct(VALUE klass, int argc, ...)
{
assert(argc > 0);
@@ -6703,93 +5682,82 @@
RoxorCompiler::compile_conversion_to_ruby(const char *type,
const Type *llvm_type, Value *val)
{
- const char *func_name = NULL;
-
type = SkipTypeModifiers(type);
if (*type == _C_PTR && GET_CORE()->find_bs_cftype(type) != NULL) {
type = "@";
}
+ Function *func = NULL;
+
switch (*type) {
case _C_VOID:
return nilVal;
case _C_BOOL:
- {
- Value *is_true = new ICmpInst(*bb, ICmpInst::ICMP_EQ, val,
- ConstantInt::get(Int8Ty, 1));
- return SelectInst::Create(is_true, trueVal, falseVal, "", bb);
- }
+ val = new ICmpInst(*bb, ICmpInst::ICMP_EQ, val,
+ ConstantInt::get(Int8Ty, 1));
+ return SelectInst::Create(val, trueVal, falseVal, "", bb);
case _C_ID:
case _C_CLASS:
- func_name = "rb_vm_ocval_to_rval";
+ func = ocvalToRvalFunc;
break;
case _C_CHR:
- case _C_SHT:
- case _C_INT:
-#if !__LP64__
- if (*type != _C_INT)
-#endif
- val = new SExtInst(val, RubyObjTy, "", bb);
- val = BinaryOperator::CreateShl(val, twoVal, "", bb);
- val = BinaryOperator::CreateOr(val, oneVal, "", bb);
- return val;
+ func = charToRvalFunc;
+ break;
case _C_UCHR:
+ func = ucharToRvalFunc;
+ break;
+
+ case _C_SHT:
+ func = shortToRvalFunc;
+ break;
+
case _C_USHT:
+ func = ushortToRvalFunc;
+ break;
+
+ case _C_INT:
+ func = intToRvalFunc;
+ break;
+
case _C_UINT:
-#if !__LP64__
- if (*type != _C_UINT)
-#endif
- val = new ZExtInst(val, RubyObjTy, "", bb);
- val = BinaryOperator::CreateShl(val, twoVal, "", bb);
- val = BinaryOperator::CreateOr(val, oneVal, "", bb);
- return val;
+ func = uintToRvalFunc;
+ break;
case _C_LNG:
- func_name = "rb_vm_long_to_rval";
+ func = longToRvalFunc;
break;
case _C_ULNG:
- func_name = "rb_vm_ulong_to_rval";
+ func = ulongToRvalFunc;
break;
case _C_LNG_LNG:
- func_name = "rb_vm_long_long_to_rval";
+ func = longLongToRvalFunc;
break;
case _C_ULNG_LNG:
- func_name = "rb_vm_ulong_long_to_rval";
+ func = ulongLongToRvalFunc;
break;
-#if __LP64__
case _C_FLT:
- val = new FPExtInst(val, DoubleTy, "", bb);
- // fall through
- case _C_DBL:
- val = new BitCastInst(val, RubyObjTy, "", bb);
- val = BinaryOperator::CreateOr(val, threeVal, "", bb);
- return val;
-#else
- // TODO inline the right code for the 32-bit fixfloat optimization
- case _C_FLT:
- func_name = "rb_vm_float_to_rval";
+ func = floatToRvalFunc;
break;
case _C_DBL:
- func_name = "rb_vm_double_to_rval";
+ func = doubleToRvalFunc;
break;
-#endif
case _C_SEL:
- func_name = "rb_vm_sel_to_rval";
+ func = selToRvalFunc;
break;
case _C_CHARPTR:
- func_name = "rb_vm_charptr_to_rval";
+ func = charPtrToRvalFunc;
break;
case _C_STRUCT_B:
@@ -6839,18 +5807,17 @@
break;
}
- if (func_name == NULL) {
+ if (func == NULL) {
rb_raise(rb_eTypeError, "unrecognized compile type `%s' to Ruby", type);
abort();
}
std::vector<Value *> params;
+
params.push_back(val);
- Function *func = cast<Function>(module->getOrInsertFunction(
- func_name, RubyObjTy, llvm_type, NULL));
-
- return CallInst::Create(func, params.begin(), params.end(), "", bb);
+ return CallInst::Create(func, params.begin(),
+ params.end(), "", bb);
}
const Type *
Modified: MacRuby/trunk/compiler.h
===================================================================
--- MacRuby/trunk/compiler.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/compiler.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -9,8 +9,6 @@
#ifndef __COMPILER_H_
#define __COMPILER_H_
-#if defined(__cplusplus)
-
// For the dispatcher.
#define DISPATCH_VCALL 1 // no receiver, no argument
#define DISPATCH_FCALL 2 // no receiver, one or more arguments
@@ -31,6 +29,8 @@
#define DEFINED_SUPER 6
#define DEFINED_METHOD 7
+#if defined(__cplusplus)
+
class RoxorCompiler {
public:
static llvm::Module *module;
@@ -60,6 +60,8 @@
Function *compile_block_caller(rb_vm_block_t *block);
Function *compile_mri_stub(void *imp, const int arity);
+ void inline_function_calls(Function *f);
+
const Type *convert_type(const char *type);
bool is_inside_eval(void) { return inside_eval; }
@@ -138,6 +140,9 @@
Function *fastEqFunc;
Function *fastNeqFunc;
Function *fastEqqFunc;
+ Function *fastArefFunc;
+ Function *fastAsetFunc;
+ Function *fastShiftFunc;
Function *whenSplatFunc;
Function *prepareBlockFunc;
Function *pushBindingFunc;
@@ -151,17 +156,20 @@
Function *prepareIvarSlotFunc;
Function *getIvarFunc;
Function *setIvarFunc;
- Function *setKVOIvarFunc;
+ Function *willChangeValueFunc;
+ Function *didChangeValueFunc;
Function *definedFunc;
Function *undefFunc;
Function *aliasFunc;
Function *valiasFunc;
Function *newHashFunc;
+ Function *storeHashFunc;
Function *toAFunc;
Function *toAryFunc;
Function *catArrayFunc;
Function *dupArrayFunc;
Function *newArrayFunc;
+ Function *asetArrayFunc;
Function *newStructFunc;
Function *newOpaqueFunc;
Function *newPointerFunc;
@@ -196,8 +204,6 @@
Function *returnedFromBlockFunc;
Function *checkReturnFromBlockFunc;
Function *setHasEnsureFunc;
- Function *longjmpFunc;
- Function *setjmpFunc;
Function *setScopeFunc;
Function *setCurrentClassFunc;
Function *getCacheFunc;
@@ -205,6 +211,37 @@
Function *getFFStateFunc;
Function *setFFStateFunc;
Function *takeOwnershipFunc;
+ Function *ocvalToRvalFunc;
+ Function *charToRvalFunc;
+ Function *ucharToRvalFunc;
+ Function *shortToRvalFunc;
+ Function *ushortToRvalFunc;
+ Function *intToRvalFunc;
+ Function *uintToRvalFunc;
+ Function *longToRvalFunc;
+ Function *ulongToRvalFunc;
+ Function *longLongToRvalFunc;
+ Function *ulongLongToRvalFunc;
+ Function *floatToRvalFunc;
+ Function *doubleToRvalFunc;
+ Function *selToRvalFunc;
+ Function *charPtrToRvalFunc;
+ Function *rvalToOcvalFunc;
+ Function *rvalToBoolFunc;
+ Function *rvalToCharFunc;
+ Function *rvalToUcharFunc;
+ Function *rvalToShortFunc;
+ Function *rvalToUshortFunc;
+ Function *rvalToIntFunc;
+ Function *rvalToUintFunc;
+ Function *rvalToLongFunc;
+ Function *rvalToUlongFunc;
+ Function *rvalToLongLongFunc;
+ Function *rvalToUlongLongFunc;
+ Function *rvalToFloatFunc;
+ Function *rvalToDoubleFunc;
+ Function *rvalToSelFunc;
+ Function *rvalToCharPtrFunc;
Constant *zeroVal;
Constant *oneVal;
@@ -239,6 +276,16 @@
void compile_node_error(const char *msg, NODE *node);
+ Function *
+ get_function(const char *name) {
+ Function *f = module->getFunction(name);
+ if (f == NULL) {
+ printf("function %s cannot be found!\n", name);
+ abort();
+ }
+ return f;
+ }
+
virtual Constant *
compile_const_pointer(void *ptr, const PointerType *type=NULL) {
if (type == NULL) {
@@ -258,6 +305,8 @@
return compile_const_pointer(ptr, PtrPtrTy);
}
+ bool should_inline_function(Function *f);
+
Function *compile_scope(NODE *node);
Instruction *compile_protected_call(Value *imp,
std::vector<Value *> ¶ms);
@@ -276,7 +325,6 @@
NODE *body);
Value *compile_dispatch_call(std::vector<Value *> ¶ms);
Value *compile_when_splat(Value *comparedToVal, Value *splatVal);
- Value *compile_fast_op_call(SEL sel, Value *selfVal, Value *comparedToVal);
Value *compile_attribute_assign(NODE *node, Value *extra_val);
virtual Value *compile_prepare_block_args(Function *func, int *flags);
Value *compile_block_create(void);
@@ -353,26 +401,19 @@
Value *compile_xmalloc(size_t len);
Value *compile_conversion_to_c(const char *type, Value *val,
- Value *slot);
+ Value *slot);
Value *compile_conversion_to_ruby(const char *type,
- const Type *llvm_type, Value *val);
+ const Type *llvm_type, Value *val);
void compile_debug_trap(void);
virtual Value *compile_slot_cache(ID id);
- ICmpInst *is_value_a_fixnum(Value *val);
- void compile_ivar_slots(Value *klass, BasicBlock::InstListType &list,
- BasicBlock::InstListType::iterator iter);
- bool unbox_ruby_constant(Value *val, VALUE *rval);
- Value *optimized_immediate_op(SEL sel, Value *leftVal, Value *rightVal,
- bool float_op, bool *is_predicate);
- Value *compile_double_coercion(Value *val, Value *mask,
- BasicBlock *fallback_bb, Function *f);
void compile_keep_vars(BasicBlock *startBB, BasicBlock *mergeBB);
SEL mid_to_sel(ID mid, int arity);
Value *compile_get_ffstate(GlobalVariable *ffstate);
- Value *compile_set_ffstate(Value *val, Value *expected, GlobalVariable *ffstate, BasicBlock *mergeBB, Function *f);
+ Value *compile_set_ffstate(Value *val, Value *expected,
+ GlobalVariable *ffstate, BasicBlock *mergeBB, Function *f);
Value *compile_ff2(NODE *current_node);
Value *compile_ff3(NODE *current_node);
Modified: MacRuby/trunk/dispatcher.cpp
===================================================================
--- MacRuby/trunk/dispatcher.cpp 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/dispatcher.cpp 2010-05-24 02:24:56 UTC (rev 4136)
@@ -1100,305 +1100,6 @@
(Class)klass, sel, block, DISPATCH_FCALL, argc, argv);
}
-// The rb_vm_fast_* functions don't check if the selector has been redefined or
-// not, because this is already handled by the compiler.
-// Also, fixnums and floats are already handled.
-
-extern "C" {
- VALUE rb_fix_plus(VALUE x, VALUE y);
- VALUE rb_fix_minus(VALUE x, VALUE y);
- VALUE rb_fix_div(VALUE x, VALUE y);
- VALUE rb_fix_mul(VALUE x, VALUE y);
- VALUE rb_flo_plus(VALUE x, VALUE y);
- VALUE rb_flo_minus(VALUE x, VALUE y);
- VALUE rb_flo_div(VALUE x, VALUE y);
- VALUE rb_flo_mul(VALUE x, VALUE y);
- VALUE rb_nu_plus(VALUE x, VALUE y);
- VALUE rb_nu_minus(VALUE x, VALUE y);
- VALUE rb_nu_div(VALUE x, VALUE y);
- VALUE rb_nu_mul(VALUE x, VALUE y);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_plus(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- // TODO: Array, String
- case T_BIGNUM:
- return rb_big_plus(self, other);
- case T_FIXNUM:
- return rb_fix_plus(self, other);
- case T_FLOAT:
- return rb_flo_plus(self, other);
- case T_COMPLEX:
- return rb_nu_plus(self, other);
- }
- return rb_vm_dispatch(cache, 0, self, selPLUS, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_minus(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- // TODO: Array, String
- case T_BIGNUM:
- return rb_big_minus(self, other);
- case T_FIXNUM:
- return rb_fix_minus(self, other);
- case T_FLOAT:
- return rb_flo_minus(self, other);
- case T_COMPLEX:
- return rb_nu_minus(self, other);
- }
- return rb_vm_dispatch(cache, 0, self, selMINUS, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_div(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- case T_BIGNUM:
- return rb_big_div(self, other);
- case T_FIXNUM:
- return rb_fix_div(self, other);
- case T_FLOAT:
- return rb_flo_div(self, other);
- case T_COMPLEX:
- return rb_nu_div(self, other);
- }
- return rb_vm_dispatch(cache, 0, self, selDIV, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_mult(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- // TODO: Array, String
- case T_BIGNUM:
- return rb_big_mul(self, other);
- case T_FIXNUM:
- return rb_fix_mul(self, other);
- case T_FLOAT:
- return rb_flo_mul(self, other);
- case T_COMPLEX:
- return rb_nu_mul(self, other);
- }
- return rb_vm_dispatch(cache, 0, self, selMULT, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_lt(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- case T_BIGNUM:
- return FIX2INT(rb_big_cmp(self, other)) < 0 ? Qtrue : Qfalse;
- }
- return rb_vm_dispatch(cache, 0, self, selLT, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_le(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- case T_BIGNUM:
- return FIX2INT(rb_big_cmp(self, other)) <= 0 ? Qtrue : Qfalse;
- }
- return rb_vm_dispatch(cache, 0, self, selLE, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_gt(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- case T_BIGNUM:
- return FIX2INT(rb_big_cmp(self, other)) > 0 ? Qtrue : Qfalse;
- }
- return rb_vm_dispatch(cache, 0, self, selGT, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_ge(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- case T_BIGNUM:
- return FIX2INT(rb_big_cmp(self, other)) >= 0 ? Qtrue : Qfalse;
- }
- return rb_vm_dispatch(cache, 0, self, selGE, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_eq(struct mcache *cache, VALUE self, VALUE other)
-{
- const int self_type = TYPE(self);
- switch (self_type) {
- case T_SYMBOL:
- return self == other ? Qtrue : Qfalse;
-
- case T_STRING:
- if (self == other) {
- return Qtrue;
- }
- if (TYPE(other) != self_type) {
- return Qfalse;
- }
- return rb_str_equal(self, other);
-
- case T_ARRAY:
- if (self == other) {
- return Qtrue;
- }
- if (TYPE(other) != self_type) {
- return Qfalse;
- }
- return rb_ary_equal(self, other);
-
- case T_HASH:
- if (self == other) {
- return Qtrue;
- }
- if (TYPE(other) != self_type) {
- return Qfalse;
- }
- return rb_hash_equal(self, other);
-
- case T_BIGNUM:
- return rb_big_eq(self, other);
- }
- return rb_vm_dispatch(cache, 0, self, selEq, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_neq(struct mcache *cache, VALUE self, VALUE other)
-{
- // TODO
- return rb_vm_dispatch(cache, 0, self, selNeq, NULL, 0, 1, other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_eqq(struct mcache *cache, VALUE self, VALUE other)
-{
- switch (TYPE(self)) {
- // TODO: Range
- case T_STRING:
- if (self == other) {
- return Qtrue;
- }
- return rb_str_equal(self, other);
-
- case T_REGEXP:
- return regexp_eqq(self, selEqq, other);
-
- case T_SYMBOL:
- return (self == other ? Qtrue : Qfalse);
-
- case T_MODULE:
- case T_CLASS:
- return rb_obj_is_kind_of(other, self);
-
- default:
- return rb_vm_dispatch(cache, 0, self, selEqq, NULL, 0, 1, other);
- }
-}
-
-extern "C"
-VALUE
-rb_vm_when_splat(struct mcache *cache, unsigned char overriden,
- VALUE comparedTo, VALUE splat)
-{
- VALUE ary = rb_check_convert_type(splat, T_ARRAY, "Array", "to_a");
- if (NIL_P(ary)) {
- ary = rb_ary_new3(1, splat);
- }
- int count = RARRAY_LEN(ary);
- if (overriden == 0) {
- for (int i = 0; i < count; ++i) {
- VALUE o = RARRAY_AT(ary, i);
- if (RTEST(rb_vm_fast_eqq(cache, o, comparedTo))) {
- return Qtrue;
- }
- }
- }
- else {
- for (int i = 0; i < count; ++i) {
- VALUE o = RARRAY_AT(ary, i);
- if (RTEST(rb_vm_dispatch(cache, 0, o, selEqq, NULL, 0, 1,
- comparedTo))) {
- return Qtrue;
- }
- }
- }
- return Qfalse;
-}
-
-extern "C"
-VALUE
-rb_vm_fast_shift(VALUE obj, VALUE other, struct mcache *cache,
- unsigned char overriden)
-{
- if (overriden == 0) {
- VALUE klass = CLASS_OF(obj);
- if (klass == rb_cRubyArray) {
- return rary_push_m(obj, 0, other);
- }
- else if (klass == rb_cRubyString) {
- return rstr_concat(obj, 0, other);
- }
- }
- return __rb_vm_dispatch(GET_VM(), cache, 0, obj, NULL, selLTLT, NULL, 0, 1,
- &other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_aref(VALUE obj, VALUE other, struct mcache *cache,
- unsigned char overriden)
-{
- if (overriden == 0) {
- VALUE klass = CLASS_OF(obj);
- if (klass == rb_cRubyArray) {
- return rary_aref(obj, 0, 1, &other);
- }
- else if (klass == rb_cRubyHash) {
- return rhash_aref(obj, 0, other);
- }
- }
- return __rb_vm_dispatch(GET_VM(), cache, 0, obj, NULL, selAREF, NULL, 0, 1,
- &other);
-}
-
-extern "C"
-VALUE
-rb_vm_fast_aset(VALUE obj, VALUE other1, VALUE other2, struct mcache *cache,
- unsigned char overriden)
-{
- if (overriden == 0) {
- VALUE klass = CLASS_OF(obj);
- if (klass == rb_cRubyArray) {
- if (TYPE(other1) == T_FIXNUM) {
- rary_store(obj, FIX2LONG(other1), other2);
- return other2;
- }
- }
- else if (klass == rb_cRubyHash) {
- return rhash_aset(obj, 0, other1, other2);
- }
- }
- VALUE args[2] = { other1, other2 };
- return __rb_vm_dispatch(GET_VM(), cache, 0, obj, NULL, selASET, NULL, 0, 2,
- args);
-}
-
static rb_vm_block_t *
dup_block(rb_vm_block_t *src_b)
{
Modified: MacRuby/trunk/exported_symbols_list
===================================================================
--- MacRuby/trunk/exported_symbols_list 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/exported_symbols_list 2010-05-24 02:24:56 UTC (rev 4136)
@@ -4,3 +4,24 @@
.objc_class_name_MacRuby
_LLVMLinkInJIT
___auto_zone
+_st_*
+
+# used by the kernel:
+_rary_reserve
+_rhash_call_default
+_rhash_aset
+_rstr_concat
+_selPLUS
+_selMINUS
+_selDIV
+_selMULT
+_selLT
+_selLE
+_selGT
+_selGE
+_selEq
+_selNeq
+_selEqq
+_selLTLT
+_selAREF
+_selASET
Modified: MacRuby/trunk/hash.c
===================================================================
--- MacRuby/trunk/hash.c 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/hash.c 2010-05-24 02:24:56 UTC (rev 4136)
@@ -428,6 +428,11 @@
*
*/
+VALUE
+rhash_call_default(VALUE hash, VALUE key)
+{
+ return rb_vm_call_with_cache(defaultCache, hash, selDefault, 1, &key);
+}
VALUE
rhash_aref(VALUE hash, SEL sel, VALUE key)
@@ -438,8 +443,7 @@
&& RHASH(hash)->ifnone == Qnil) {
return Qnil;
}
- return rb_vm_call_with_cache(defaultCache, hash, selDefault,
- 1, &key);
+ return rhash_call_default(hash, key);
}
return val;
}
@@ -902,8 +906,8 @@
{
rhash_modify(hash);
if (TYPE(key) == T_STRING) {
- key = rb_str_dup(key);
- OBJ_FREEZE(key);
+ key = rb_str_dup(key);
+ OBJ_FREEZE(key);
}
st_insert(RHASH(hash)->tbl, key, val);
return val;
Modified: MacRuby/trunk/hash.h
===================================================================
--- MacRuby/trunk/hash.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/hash.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -73,6 +73,18 @@
}
static inline VALUE
+rhash_store(VALUE hash, VALUE key, VALUE val)
+{
+ rhash_modify(hash);
+ if (TYPE(key) == T_STRING) {
+ key = rb_str_dup(key);
+ OBJ_FREEZE(key);
+ }
+ st_insert(RHASH(hash)->tbl, key, val);
+ return val;
+}
+
+static inline VALUE
rhash_delete_key(VALUE hash, VALUE key)
{
VALUE val;
@@ -87,6 +99,7 @@
VALUE rhash_aset(VALUE hash, SEL sel, VALUE key, VALUE val);
VALUE rhash_keys(VALUE hash, SEL sel);
VALUE rhash_has_key(VALUE hash, SEL sel, VALUE key);
+VALUE rhash_call_default(VALUE hash, VALUE key);
VALUE rhash_set_default(VALUE hash, SEL sel, VALUE ifnone);
#if defined(__cplusplus)
Modified: MacRuby/trunk/include/ruby/intern.h
===================================================================
--- MacRuby/trunk/include/ruby/intern.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/include/ruby/intern.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -85,10 +85,6 @@
void rb_big_2comp(VALUE);
VALUE rb_big_norm(VALUE);
void rb_big_resize(VALUE big, long len);
-VALUE rb_uint2big(VALUE);
-VALUE rb_int2big(SIGNED_VALUE);
-VALUE rb_uint2inum(VALUE);
-VALUE rb_int2inum(SIGNED_VALUE);
VALUE rb_cstr_to_inum(const char*, int, int);
VALUE rb_str_to_inum(VALUE, int, int);
VALUE rb_cstr2inum(const char*, int);
@@ -102,8 +98,6 @@
VALUE rb_big2ulong(VALUE);
#define rb_big2uint(x) rb_big2ulong(x)
#if HAVE_LONG_LONG
-VALUE rb_ll2inum(LONG_LONG);
-VALUE rb_ull2inum(unsigned LONG_LONG);
LONG_LONG rb_big2ll(VALUE);
unsigned LONG_LONG rb_big2ull(VALUE);
#endif /* HAVE_LONG_LONG */
Modified: MacRuby/trunk/include/ruby/ruby.h
===================================================================
--- MacRuby/trunk/include/ruby/ruby.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/include/ruby/ruby.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -176,11 +176,9 @@
#define INT2FIX(i) ((VALUE)(((SIGNED_VALUE)(i))<<2 | FIXNUM_FLAG))
#define LONG2FIX(i) INT2FIX(i)
#define rb_fix_new(v) INT2FIX(v)
-VALUE rb_int2inum(SIGNED_VALUE);
#define INT2NUM(v) rb_int2inum(v)
#define LONG2NUM(v) INT2NUM(v)
#define rb_int_new(v) rb_int2inum(v)
-VALUE rb_uint2inum(VALUE);
#define UINT2NUM(v) rb_uint2inum(v)
#define ULONG2NUM(v) UINT2NUM(v)
#define rb_uint_new(v) rb_uint2inum(v)
@@ -188,9 +186,7 @@
#define TIMET2NUM(t) LONG2NUM(t)
#ifdef HAVE_LONG_LONG
-VALUE rb_ll2inum(LONG_LONG);
#define LL2NUM(v) rb_ll2inum(v)
-VALUE rb_ull2inum(unsigned LONG_LONG);
#define ULL2NUM(v) rb_ull2inum(v)
#endif
@@ -238,7 +234,6 @@
#define IMMEDIATE_P(x) ((VALUE)(x) & IMMEDIATE_MASK)
-
#if __LP64__
#define VOODOO_DOUBLE(d) (*(VALUE*)(&d))
#define DBL2FIXFLOAT(d) (VOODOO_DOUBLE(d) | FIXFLOAT_FLAG)
@@ -274,7 +269,8 @@
// We can't directly cast a void* to a double, so we cast it to a union
// and then extract its double member. Hacky, but effective.
-static inline double coerce_ptr_to_double(VALUE v)
+static inline double
+coerce_ptr_to_double(VALUE v)
{
union {
VALUE val;
@@ -301,6 +297,47 @@
#define CLASS_OF(v) rb_class_of((VALUE)(v))
+VALUE rb_uint2big(VALUE);
+VALUE rb_int2big(SIGNED_VALUE);
+VALUE rb_ull2big(unsigned long long n);
+VALUE rb_ll2big(long long n);
+
+static inline VALUE
+rb_uint2inum(VALUE n)
+{
+ if (POSFIXABLE(n)) {
+ return LONG2FIX(n);
+ }
+ return rb_uint2big(n);
+}
+
+static inline VALUE
+rb_int2inum(SIGNED_VALUE n)
+{
+ if (FIXABLE(n)) {
+ return LONG2FIX(n);
+ }
+ return rb_int2big(n);
+}
+
+static inline VALUE
+rb_ull2inum(unsigned long long n)
+{
+ if (POSFIXABLE(n)) {
+ return LONG2FIX(n);
+ }
+ return rb_ull2big(n);
+}
+
+static inline VALUE
+rb_ll2inum(long long n)
+{
+ if (FIXABLE(n)) {
+ return LONG2FIX(n);
+ }
+ return rb_ll2big(n);
+}
+
enum ruby_value_type {
RUBY_T_NONE = 0x00,
@@ -426,7 +463,12 @@
#ifdef HAVE_LONG_LONG
LONG_LONG rb_num2ll(VALUE);
unsigned LONG_LONG rb_num2ull(VALUE);
-# define NUM2LL(x) (FIXNUM_P(x)?FIX2LONG(x):rb_num2ll((VALUE)x))
+static inline long long
+__num2ll(VALUE obj)
+{
+ return FIXNUM_P(obj) ? FIX2LONG(obj) : rb_num2ll(obj);
+}
+# define NUM2LL(x) __num2ll((VALUE)x)
# define NUM2ULL(x) rb_num2ull((VALUE)x)
#endif
Added: MacRuby/trunk/kernel.c
===================================================================
--- MacRuby/trunk/kernel.c (rev 0)
+++ MacRuby/trunk/kernel.c 2010-05-24 02:24:56 UTC (rev 4136)
@@ -0,0 +1,853 @@
+/*
+ * MacRuby kernel. This file is compiled into LLVM bitcode and injected into
+ * the global module. Some of the functions defined here are inlined in the
+ * code MacRuby generates.
+ *
+ * This file is covered by the Ruby license. See COPYING for more details.
+ *
+ * Copyright (C) 2010, Apple Inc. All rights reserved.
+ */
+
+#include "ruby/ruby.h"
+#include "ruby/node.h"
+#include "vm.h"
+#include "compiler.h"
+#include "bridgesupport.h"
+#include "id.h"
+#include "array.h"
+#include "hash.h"
+#include "encoding.h"
+#include "class.h"
+#include "objc.h"
+
+inline VALUE
+vm_ivar_get(VALUE obj, ID name, void *cache_p)
+{
+ struct icache *cache = (struct icache *)cache_p;
+ VALUE klass = 0;
+
+ if (!SPECIAL_CONST_P(obj)) {
+ klass = *(VALUE *)obj;
+ if (klass == cache->klass) {
+ if ((unsigned int)cache->slot < ROBJECT(obj)->num_slots) {
+ rb_object_ivar_slot_t *slot;
+use_slot:
+ slot = &ROBJECT(obj)->slots[cache->slot];
+ if (slot->name == name) {
+ VALUE val = slot->value;
+ if (val == Qundef) {
+ val = Qnil;
+ }
+ return val;
+ }
+ }
+ }
+ }
+
+ if (cache->slot == SLOT_CACHE_VIRGIN) {
+ const int slot = rb_vm_get_ivar_slot(obj, name, true);
+ if (slot >= 0) {
+ cache->klass = *(VALUE *)obj;
+ cache->slot = slot;
+ goto use_slot;
+ }
+ cache->klass = 0;
+ cache->slot = SLOT_CACHE_CANNOT;
+ }
+
+ return rb_ivar_get(obj, name);
+}
+
+inline void
+vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache_p)
+{
+ struct icache *cache = (struct icache *)cache_p;
+ VALUE klass = 0;
+
+ if (!SPECIAL_CONST_P(obj)) {
+ klass = *(VALUE *)obj;
+ if (klass == cache->klass) {
+ if ((unsigned int)cache->slot < ROBJECT(obj)->num_slots) {
+ rb_object_ivar_slot_t *slot;
+use_slot:
+ slot = &ROBJECT(obj)->slots[cache->slot];
+ if (slot->name == name) {
+ if ((ROBJECT(obj)->basic.flags & FL_FREEZE) == FL_FREEZE) {
+ rb_error_frozen("object");
+ }
+ GC_WB(&slot->value, val);
+ return;
+ }
+ }
+ }
+ }
+
+ if (cache->slot == SLOT_CACHE_VIRGIN) {
+ const int slot = rb_vm_get_ivar_slot(obj, name, true);
+ if (slot >= 0) {
+ cache->klass = *(VALUE *)obj;
+ cache->slot = slot;
+ goto use_slot;
+ }
+ cache->slot = SLOT_CACHE_CANNOT;
+ }
+
+ rb_ivar_set(obj, name, val);
+}
+
+inline VALUE
+vm_cvar_get(VALUE klass, ID id, unsigned char check,
+ unsigned char dynamic_class)
+{
+ if (dynamic_class) {
+ Class k = rb_vm_get_current_class();
+ if (k != NULL) {
+ klass = (VALUE)k;
+ }
+ }
+ return rb_cvar_get2(klass, id, check);
+}
+
+inline VALUE
+vm_cvar_set(VALUE klass, ID id, VALUE val, unsigned char dynamic_class)
+{
+ if (dynamic_class) {
+ Class k = rb_vm_get_current_class();
+ if (k != NULL) {
+ klass = (VALUE)k;
+ }
+ }
+ rb_cvar_set(klass, id, val);
+ return val;
+}
+
+inline VALUE
+vm_get_const(VALUE outer, void *cache_p, ID path, int flags)
+{
+ struct ccache *cache = (struct ccache *) cache_p;
+ const bool lexical_lookup = (flags & CONST_LOOKUP_LEXICAL);
+ const bool dynamic_class = (flags & CONST_LOOKUP_DYNAMIC_CLASS);
+
+ if (dynamic_class) {
+ Class k = rb_vm_get_current_class();
+ if (lexical_lookup && k != NULL) {
+ outer = (VALUE)k;
+ }
+ }
+
+ VALUE val;
+ if (cache->outer == outer && cache->val != Qundef) {
+ val = cache->val;
+ }
+ else {
+ val = rb_vm_const_lookup(outer, path, lexical_lookup, false);
+ cache->outer = outer;
+ cache->val = val;
+ }
+
+ return val;
+}
+
+inline void
+vm_set_const(VALUE outer, ID id, VALUE obj, unsigned char dynamic_class)
+{
+ if (dynamic_class) {
+ Class k = rb_vm_get_current_class();
+ if (k != NULL) {
+ outer = (VALUE)k;
+ }
+ }
+ rb_const_set(outer, id, obj);
+}
+
+VALUE rb_vm_dispatch(void *cache, VALUE top, VALUE self, void *sel,
+ void *block, unsigned char opt, int argc, ...);
+
+// Only numeric immediates have their lsb at 1.
+#define NUMERIC_IMM_P(x) ((x & 0x1) == 0x1)
+
+#define IMM2DBL(x) (FIXFLOAT_P(x) ? FIXFLOAT2DBL(x) : FIX2LONG(x))
+
+inline VALUE
+vm_fast_plus(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ const long res = FIX2LONG(left) + FIX2LONG(right);
+ if (FIXABLE(res)) {
+ return LONG2FIX(res);
+ }
+ }
+ else {
+ const double res = IMM2DBL(left) + IMM2DBL(right);
+ return DBL2FIXFLOAT(res);
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selPLUS, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_minus(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ const long res = FIX2LONG(left) - FIX2LONG(right);
+ if (FIXABLE(res)) {
+ return LONG2FIX(res);
+ }
+ }
+ else {
+ const double res = IMM2DBL(left) - IMM2DBL(right);
+ return DBL2FIXFLOAT(res);
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selMINUS, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_mult(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ const long res = FIX2LONG(left) * FIX2LONG(right);
+ if (FIXABLE(res)) {
+ return LONG2FIX(res);
+ }
+ }
+ else {
+ const double res = IMM2DBL(left) * IMM2DBL(right);
+ return DBL2FIXFLOAT(res);
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selMULT, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_div(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ const long x = FIX2LONG(left);
+ const long y = FIX2LONG(right);
+ if (y != 0) {
+ long res = x / y;
+ if (((x < 0 && y >= 0) || (x >= 0 && y < 0))
+ && (x % y) != 0) {
+ res--;
+ }
+ if (FIXABLE(res)) {
+ return LONG2FIX(res);
+ }
+ }
+ }
+ else {
+ const double res = IMM2DBL(left) / IMM2DBL(right);
+ return DBL2FIXFLOAT(res);
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selDIV, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_lt(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ return FIX2LONG(left) < FIX2LONG(right) ? Qtrue : Qfalse;
+ }
+ else {
+ return IMM2DBL(left) < IMM2DBL(right) ? Qtrue : Qfalse;
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selLT, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_le(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ return FIX2LONG(left) <= FIX2LONG(right) ? Qtrue : Qfalse;
+ }
+ else {
+ return IMM2DBL(left) <= IMM2DBL(right) ? Qtrue : Qfalse;
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selLE, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_gt(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ return FIX2LONG(left) > FIX2LONG(right) ? Qtrue : Qfalse;
+ }
+ else {
+ return IMM2DBL(left) > IMM2DBL(right) ? Qtrue : Qfalse;
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selGT, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_ge(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0 && NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ return FIX2LONG(left) >= FIX2LONG(right) ? Qtrue : Qfalse;
+ }
+ else {
+ return IMM2DBL(left) >= IMM2DBL(right) ? Qtrue : Qfalse;
+ }
+ }
+ return rb_vm_dispatch(cache, 0, left, selGE, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_eq(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0) {
+ if (NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ return FIX2LONG(left) == FIX2LONG(right) ? Qtrue : Qfalse;
+ }
+ else {
+ return IMM2DBL(left) == IMM2DBL(right) ? Qtrue : Qfalse;
+ }
+ }
+ if (left == Qtrue || left == Qfalse) {
+ return left == right ? Qtrue : Qfalse;
+ }
+ // TODO: opt for non-immediate types
+ }
+ return rb_vm_dispatch(cache, 0, left, selEq, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_eqq(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0) {
+ if (NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ return FIX2LONG(left) == FIX2LONG(right) ? Qtrue : Qfalse;
+ }
+ else {
+ return IMM2DBL(left) == IMM2DBL(right) ? Qtrue : Qfalse;
+ }
+ }
+ if (left == Qtrue || left == Qfalse) {
+ return left == right ? Qtrue : Qfalse;
+ }
+ // TODO: opt for non-immediate types
+ }
+ return rb_vm_dispatch(cache, 0, left, selEqq, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_neq(void *cache, VALUE left, VALUE right, unsigned char overriden)
+{
+ if (overriden == 0) {
+ if (NUMERIC_IMM_P(left) && NUMERIC_IMM_P(right)) {
+ if (FIXNUM_P(left) && FIXNUM_P(right)) {
+ return FIX2LONG(left) != FIX2LONG(right) ? Qtrue : Qfalse;
+ }
+ else {
+ return IMM2DBL(left) != IMM2DBL(right) ? Qtrue : Qfalse;
+ }
+ }
+ if (left == Qtrue || left == Qfalse) {
+ return left != right ? Qtrue : Qfalse;
+ }
+ // TODO: opt for non-immediate types
+ }
+ return rb_vm_dispatch(cache, 0, left, selNeq, NULL, 0, 1, right);
+}
+
+inline VALUE
+vm_fast_aref(VALUE obj, VALUE other, void *cache, unsigned char overriden)
+{
+ if (overriden == 0 && !SPECIAL_CONST_P(obj)) {
+ VALUE klass = *(VALUE *)obj;
+ if (klass == rb_cRubyArray) {
+ if (FIXNUM_P(other)) {
+ return rary_entry(obj, FIX2LONG(other));
+ }
+ }
+ else if (klass == rb_cRubyHash) {
+ VALUE val = rhash_lookup(obj, other);
+ if (val == Qundef) {
+ if (RHASH(obj)->ifnone == Qnil) {
+ return Qnil;
+ }
+ return rhash_call_default(obj, other);
+ }
+ return val;
+ }
+ }
+ return rb_vm_dispatch(cache, 0, obj, selAREF, NULL, 0, 1, other);
+}
+
+inline VALUE
+vm_fast_aset(VALUE obj, VALUE other1, VALUE other2, void *cache,
+ unsigned char overriden)
+{
+ if (overriden == 0 && !SPECIAL_CONST_P(obj)) {
+ VALUE klass = *(VALUE *)obj;
+ if (klass == rb_cRubyArray) {
+ if (FIXNUM_P(other1)) {
+ rary_store(obj, FIX2LONG(other1), other2);
+ return other2;
+ }
+ }
+ else if (klass == rb_cRubyHash) {
+ return rhash_aset(obj, 0, other1, other2);
+ }
+ }
+ return rb_vm_dispatch(cache, 0, obj, selASET, NULL, 0, 2, other1, other2);
+}
+
+inline VALUE
+vm_fast_shift(VALUE obj, VALUE other, void *cache, unsigned char overriden)
+{
+ if (overriden == 0 && !SPECIAL_CONST_P(obj)) {
+ VALUE klass = *(VALUE *)obj;
+ if (klass == rb_cRubyArray) {
+ rary_modify(obj);
+ rary_push(obj, other);
+ return obj;
+ }
+ else if (klass == rb_cRubyString) {
+ return rstr_concat(obj, 0, other);
+ }
+ }
+ return rb_vm_dispatch(cache, 0, obj, selLTLT, NULL, 0, 1, other);
+}
+
+inline VALUE
+vm_when_splat(void *cache, unsigned char overriden,
+ VALUE comparedTo, VALUE splat)
+{
+ VALUE ary = rb_check_convert_type(splat, T_ARRAY, "Array", "to_a");
+ if (NIL_P(ary)) {
+ ary = rb_ary_new3(1, splat);
+ }
+ long i, count = RARRAY_LEN(ary);
+ for (i = 0; i < count; i++) {
+ VALUE o = RARRAY_AT(ary, i);
+ if (RTEST(vm_fast_eqq(cache, o, comparedTo, overriden))) {
+ return Qtrue;
+ }
+ }
+ return Qfalse;
+}
+
+inline void
+vm_set_current_scope(VALUE mod, int scope)
+{
+ rb_vm_set_current_scope(mod, scope);
+}
+
+inline VALUE
+vm_ocval_to_rval(id ocval)
+{
+ return OC2RB(ocval);
+}
+
+inline VALUE
+vm_char_to_rval(char c)
+{
+ return INT2FIX(c);
+}
+
+inline VALUE
+vm_uchar_to_rval(unsigned char c)
+{
+ return INT2FIX(c);
+}
+
+inline VALUE
+vm_short_to_rval(short c)
+{
+ return INT2FIX(c);
+}
+
+inline VALUE
+vm_ushort_to_rval(unsigned short c)
+{
+ return INT2FIX(c);
+}
+
+inline VALUE
+vm_int_to_rval(int c)
+{
+ return INT2FIX(c);
+}
+
+inline VALUE
+vm_uint_to_rval(unsigned int c)
+{
+ return INT2FIX(c);
+}
+
+inline VALUE
+vm_long_to_rval(long l)
+{
+ return LONG2NUM(l);
+}
+
+inline VALUE
+vm_ulong_to_rval(unsigned long l)
+{
+ return ULONG2NUM(l);
+}
+
+inline VALUE
+vm_long_long_to_rval(long long l)
+{
+ return LL2NUM(l);
+}
+
+inline VALUE
+vm_ulong_long_to_rval(unsigned long long l)
+{
+ return ULL2NUM(l);
+}
+
+inline VALUE
+vm_float_to_rval(float f)
+{
+ return DOUBLE2NUM(f);
+}
+
+inline VALUE
+vm_double_to_rval(double d)
+{
+ return DOUBLE2NUM(d);
+}
+
+inline VALUE
+vm_sel_to_rval(SEL sel)
+{
+ return sel == 0 ? Qnil : ID2SYM(rb_intern(sel_getName(sel)));
+}
+
+inline VALUE
+vm_charptr_to_rval(const char *ptr)
+{
+ return ptr == NULL ? Qnil : rb_str_new2(ptr);
+}
+
+inline void
+vm_rval_to_ocval(VALUE rval, id *ocval)
+{
+ *ocval = rval == Qnil ? NULL : RB2OC(rval);
+}
+
+inline void
+vm_rval_to_bool(VALUE rval, BOOL *ocval)
+{
+ if (rval == Qfalse || rval == Qnil) {
+ *ocval = NO;
+ }
+ else {
+ // All other types should be converted as true, to follow the Ruby
+ // semantics (where for example any integer is always true, even 0).
+ *ocval = YES;
+ }
+}
+
+static inline const char *
+rval_to_c_str(VALUE rval)
+{
+ if (NIL_P(rval)) {
+ return NULL;
+ }
+ else {
+ if (CLASS_OF(rval) == rb_cSymbol) {
+ return rb_sym2name(rval);
+ }
+ if (rb_obj_is_kind_of(rval, rb_cPointer)) {
+ return (const char *)rb_pointer_get_data(rval, "^c");
+ }
+ return StringValueCStr(rval);
+ }
+}
+
+inline void
+vm_rval_to_sel(VALUE rval, SEL *ocval)
+{
+ const char *cstr = rval_to_c_str(rval);
+ *ocval = cstr == NULL ? NULL : sel_registerName(cstr);
+}
+
+inline void
+vm_rval_to_charptr(VALUE rval, const char **ocval)
+{
+ *ocval = rval_to_c_str(rval);
+}
+
+static inline long
+bool_to_fix(VALUE rval)
+{
+ if (rval == Qtrue) {
+ return INT2FIX(1);
+ }
+ if (rval == Qfalse) {
+ return INT2FIX(0);
+ }
+ return rval;
+}
+
+static inline long
+rval_to_long(VALUE rval)
+{
+ return NUM2LONG(rb_Integer(bool_to_fix(rval)));
+}
+
+static inline long long
+rval_to_long_long(VALUE rval)
+{
+ return NUM2LL(rb_Integer(bool_to_fix(rval)));
+}
+
+static inline double
+rval_to_double(VALUE rval)
+{
+ return RFLOAT_VALUE(rb_Float(bool_to_fix(rval)));
+}
+
+inline void
+vm_rval_to_char(VALUE rval, char *ocval)
+{
+ if (TYPE(rval) == T_STRING && RSTRING_LEN(rval) == 1) {
+ *ocval = (char)RSTRING_PTR(rval)[0];
+ }
+ else {
+ *ocval = (char)rval_to_long(rval);
+ }
+}
+
+inline void
+vm_rval_to_uchar(VALUE rval, unsigned char *ocval)
+{
+ if (TYPE(rval) == T_STRING && RSTRING_LEN(rval) == 1) {
+ *ocval = (unsigned char)RSTRING_PTR(rval)[0];
+ }
+ else {
+ *ocval = (unsigned char)rval_to_long(rval);
+ }
+}
+
+inline void
+vm_rval_to_short(VALUE rval, short *ocval)
+{
+ *ocval = (short)rval_to_long(rval);
+}
+
+inline void
+vm_rval_to_ushort(VALUE rval, unsigned short *ocval)
+{
+ *ocval = (unsigned short)rval_to_long(rval);
+}
+
+inline void
+vm_rval_to_int(VALUE rval, int *ocval)
+{
+ *ocval = (int)rval_to_long(rval);
+}
+
+inline void
+vm_rval_to_uint(VALUE rval, unsigned int *ocval)
+{
+ *ocval = (unsigned int)rval_to_long(rval);
+}
+
+inline void
+vm_rval_to_long(VALUE rval, long *ocval)
+{
+ *ocval = (long)rval_to_long(rval);
+}
+
+inline void
+vm_rval_to_ulong(VALUE rval, unsigned long *ocval)
+{
+ *ocval = (unsigned long)rval_to_long(rval);
+}
+
+inline void
+vm_rval_to_long_long(VALUE rval, long long *ocval)
+{
+ *ocval = (long long)rval_to_long_long(rval);
+}
+
+inline void
+vm_rval_to_ulong_long(VALUE rval, unsigned long long *ocval)
+{
+ *ocval = (unsigned long long)rval_to_long_long(rval);
+}
+
+inline void
+vm_rval_to_double(VALUE rval, double *ocval)
+{
+ *ocval = (double)rval_to_double(rval);
+}
+
+inline void
+vm_rval_to_float(VALUE rval, float *ocval)
+{
+ *ocval = (float)rval_to_double(rval);
+}
+
+inline void *
+vm_rval_to_cptr(VALUE rval, const char *type, void **cptr)
+{
+ if (NIL_P(rval)) {
+ *cptr = NULL;
+ }
+ else {
+ if (TYPE(rval) == T_ARRAY
+ || rb_boxed_is_type(CLASS_OF(rval), type + 1)) {
+ // A convenience helper so that the user can pass a Boxed or an
+ // Array object instead of a Pointer to the object.
+ rval = rb_pointer_new2(type + 1, rval);
+ }
+ *cptr = rb_pointer_get_data(rval, type);
+ }
+ return *cptr;
+}
+
+inline VALUE
+vm_to_a(VALUE obj)
+{
+ VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_a");
+ if (NIL_P(ary)) {
+ ary = rb_ary_new3(1, obj);
+ }
+ return ary;
+}
+
+inline VALUE
+vm_to_ary(VALUE obj)
+{
+ VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_ary");
+ if (NIL_P(ary)) {
+ ary = rb_ary_new3(1, obj);
+ }
+ return ary;
+}
+
+inline VALUE
+vm_ary_cat(VALUE ary, VALUE obj)
+{
+ VALUE ary2 = rb_check_convert_type(obj, T_ARRAY, "Array", "to_a");
+ if (!NIL_P(ary2)) {
+ rb_ary_concat(ary, ary2);
+ }
+ else {
+ rb_ary_push(ary, obj);
+ }
+ return ary;
+}
+
+inline VALUE
+vm_ary_dup(VALUE ary)
+{
+ return rb_ary_dup(ary);
+}
+
+inline VALUE
+vm_rary_new(int len)
+{
+ VALUE ary = rb_ary_new2(len);
+ RARY(ary)->len = len;
+ return ary;
+}
+
+inline void
+vm_rary_aset(VALUE ary, int i, VALUE obj)
+{
+ rary_elt_set(ary, i, obj);
+}
+
+inline VALUE
+vm_rhash_new(void)
+{
+ return rb_hash_new();
+}
+
+inline void
+vm_rhash_store(VALUE hash, VALUE key, VALUE obj)
+{
+ rhash_store(hash, key, obj);
+}
+
+inline VALUE
+vm_masgn_get_elem_before_splat(VALUE ary, int offset)
+{
+ if (offset < RARRAY_LEN(ary)) {
+ return RARRAY_AT(ary, offset);
+ }
+ return Qnil;
+}
+
+inline VALUE
+vm_masgn_get_elem_after_splat(VALUE ary, int before_splat_count,
+ int after_splat_count, int offset)
+{
+ const int len = RARRAY_LEN(ary);
+ if (len < before_splat_count + after_splat_count) {
+ offset += before_splat_count;
+ if (offset < len) {
+ return RARRAY_AT(ary, offset);
+ }
+ }
+ else {
+ offset += len - after_splat_count;
+ return RARRAY_AT(ary, offset);
+ }
+ return Qnil;
+}
+
+inline VALUE
+vm_masgn_get_splat(VALUE ary, int before_splat_count, int after_splat_count)
+{
+ const int len = RARRAY_LEN(ary);
+ if (len > before_splat_count + after_splat_count) {
+ return rb_ary_subseq(ary, before_splat_count,
+ len - before_splat_count - after_splat_count);
+ }
+ else {
+ return rb_ary_new();
+ }
+}
+
+inline VALUE
+vm_get_special(char code)
+{
+ VALUE backref = rb_backref_get();
+ if (backref == Qnil) {
+ return Qnil;
+ }
+
+ VALUE val;
+ switch (code) {
+ case '&':
+ val = rb_reg_last_match(backref);
+ break;
+ case '`':
+ val = rb_reg_match_pre(backref);
+ break;
+ case '\'':
+ val = rb_reg_match_post(backref);
+ break;
+ case '+':
+ val = rb_reg_match_last(backref);
+ break;
+ default:
+ // Boundaries check is done in rb_reg_nth_match().
+ val = rb_reg_nth_match((int)code, backref);
+ break;
+ }
+ return val;
+}
Modified: MacRuby/trunk/objc.h
===================================================================
--- MacRuby/trunk/objc.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/objc.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -173,6 +173,9 @@
return arity;
}
+id rb_objc_numeric2nsnumber(VALUE obj);
+VALUE rb_objc_nsnumber2numeric(id obj);
+
static inline id
rb_rval_to_ocid(VALUE obj)
{
@@ -186,39 +189,13 @@
if (obj == Qnil) {
return (id)kCFNull;
}
- if (FIXNUM_P(obj)) {
- // TODO: this could be optimized in case we can fit the fixnum
- // into an immediate NSNumber directly.
- long val = FIX2LONG(obj);
- CFNumberRef number = CFNumberCreate(NULL, kCFNumberLongType, &val);
- CFMakeCollectable(number);
- return (id)number;
+ if (IMMEDIATE_P(obj)) {
+ return rb_objc_numeric2nsnumber(obj);
}
- if (FIXFLOAT_P(obj)) {
- double val = NUM2DBL(obj);
- CFNumberRef number = CFNumberCreate(NULL, kCFNumberDoubleType,
- &val);
- CFMakeCollectable(number);
- return (id)number;
- }
}
return (id)obj;
}
-static inline bool
-rb_objc_obj_is_nsnumber(id obj)
-{
- Class k = object_getClass(obj); // might be an immediate
- do {
- if (k == (Class)rb_cNSNumber) {
- return true;
- }
- k = class_getSuperclass(k);
- }
- while (k != NULL);
- return false;
-}
-
static inline VALUE
rb_ocid_to_rval(id obj)
{
@@ -231,26 +208,7 @@
if (obj == (id)kCFNull || obj == nil) {
return Qnil;
}
-
- if (rb_objc_obj_is_nsnumber(obj)) {
- // TODO: this could be optimized in case the object is an immediate.
- if (CFNumberIsFloatType((CFNumberRef)obj)) {
- double v = 0;
- assert(CFNumberGetValue((CFNumberRef)obj, kCFNumberDoubleType, &v));
- return DOUBLE2NUM(v);
- }
- else {
- long v = 0;
- assert(CFNumberGetValue((CFNumberRef)obj, kCFNumberLongType, &v));
- return LONG2FIX(v);
- }
- }
-
- if (((unsigned long)obj & 0x1) == 0x1) {
- rb_bug("unknown Objective-C immediate: %p\n", obj);
- }
-
- return (VALUE)obj;
+ return rb_objc_nsnumber2numeric(obj);
}
#define RB2OC(obj) (rb_rval_to_ocid((VALUE)obj))
@@ -263,6 +221,8 @@
void rb_objc_force_class_initialize(Class klass);
void rb_objc_fix_relocatable_load_path(void);
+extern bool rb_objc_enable_ivar_set_kvo_notifications;
+
#if defined(__cplusplus)
}
#endif
Modified: MacRuby/trunk/objc.m
===================================================================
--- MacRuby/trunk/objc.m 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/objc.m 2010-05-24 02:24:56 UTC (rev 4136)
@@ -367,7 +367,7 @@
#endif
}
-static bool enable_kvo_notifications = false;
+bool rb_objc_enable_ivar_set_kvo_notifications = false;
VALUE
rb_require_framework(VALUE recv, SEL sel, int argc, VALUE *argv)
@@ -481,7 +481,7 @@
reload_class_constants();
reload_protocols();
- enable_kvo_notifications = true;
+ rb_objc_enable_ivar_set_kvo_notifications = true;
return loaded ? Qfalse : Qtrue;
}
@@ -538,23 +538,6 @@
}
VALUE
-rb_vm_set_kvo_ivar(VALUE obj, ID name, VALUE val, void *cache)
-{
- if (enable_kvo_notifications) {
- NSString *key = [(NSString *)rb_id2str(name) substringFromIndex:1]; // skip '@' prefix
- [(id)obj willChangeValueForKey:key];
-
- rb_vm_ivar_set(obj, name, val, cache);
-
- [(id)obj didChangeValueForKey:key];
- }
- else {
- rb_vm_ivar_set(obj, name, val, cache);
- }
- return val;
-}
-
-VALUE
rb_mod_objc_ib_outlet(VALUE recv, SEL sel, int argc, VALUE *argv)
{
int i;
@@ -666,6 +649,65 @@
reason:[NSString stringWithUTF8String:message] userInfo:nil] raise];
}
+id
+rb_objc_numeric2nsnumber(VALUE obj)
+{
+ if (FIXNUM_P(obj)) {
+ // TODO: this could be optimized in case we can fit the fixnum
+ // into an immediate NSNumber directly.
+ long val = FIX2LONG(obj);
+ CFNumberRef number = CFNumberCreate(NULL, kCFNumberLongType, &val);
+ CFMakeCollectable(number);
+ return (id)number;
+ }
+ if (FIXFLOAT_P(obj)) {
+ double val = NUM2DBL(obj);
+ CFNumberRef number = CFNumberCreate(NULL, kCFNumberDoubleType,
+ &val);
+ CFMakeCollectable(number);
+ return (id)number;
+ }
+ abort();
+}
+
+static inline bool
+rb_objc_obj_is_nsnumber(id obj)
+{
+ Class k = object_getClass(obj); // might be an immediate
+ do {
+ if (k == (Class)rb_cNSNumber) {
+ return true;
+ }
+ k = class_getSuperclass(k);
+ }
+ while (k != NULL);
+ return false;
+}
+
+VALUE
+rb_objc_nsnumber2numeric(id obj)
+{
+ if (rb_objc_obj_is_nsnumber(obj)) {
+ // TODO: this could be optimized in case the object is an immediate.
+ if (CFNumberIsFloatType((CFNumberRef)obj)) {
+ double v = 0;
+ assert(CFNumberGetValue((CFNumberRef)obj, kCFNumberDoubleType, &v));
+ return DOUBLE2NUM(v);
+ }
+ else {
+ long v = 0;
+ assert(CFNumberGetValue((CFNumberRef)obj, kCFNumberLongType, &v));
+ return LONG2FIX(v);
+ }
+ }
+
+ if (((unsigned long)obj & 0x1) == 0x1) {
+ rb_bug("unknown Objective-C immediate: %p\n", obj);
+ }
+
+ return (VALUE)obj;
+}
+
bool
rb_objc_ignore_sel(SEL sel)
{
@@ -748,6 +790,18 @@
}
void
+rb_objc_willChangeValueForKey(id obj, NSString *key)
+{
+ [obj willChangeValueForKey:key];
+}
+
+void
+rb_objc_didChangeValueForKey(id obj, NSString *key)
+{
+ [obj didChangeValueForKey:key];
+}
+
+void
Init_ObjC(void)
{
rb_objc_define_method(rb_mKernel, "load_bridge_support_file",
Modified: MacRuby/trunk/rakelib/builder/options.rb
===================================================================
--- MacRuby/trunk/rakelib/builder/options.rb 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/rakelib/builder/options.rb 2010-05-24 02:24:56 UTC (rev 4136)
@@ -105,7 +105,7 @@
INSTALL_NAME = File.join(FRAMEWORK_USR_LIB, 'lib' + RUBY_SO_NAME + '.dylib')
ARCHFLAGS = ARCHS.map { |a| '-arch ' + a }.join(' ')
-LLVM_MODULES = "core jit nativecodegen bitwriter"
+LLVM_MODULES = "core jit nativecodegen bitwriter bitreader"
EXPORTED_SYMBOLS_LIST = "./exported_symbols_list"
CC = '/usr/bin/gcc-4.2'
Modified: MacRuby/trunk/rakelib/builder.rake
===================================================================
--- MacRuby/trunk/rakelib/builder.rake 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/rakelib/builder.rake 2010-05-24 02:24:56 UTC (rev 4136)
@@ -25,6 +25,28 @@
if !File.exist?('node_name.inc') or File.mtime('include/ruby/node.h') > File.mtime('node_name.inc')
sh("/usr/bin/ruby -n tool/node_name.rb include/ruby/node.h > node_name.inc")
end
+ if !File.exist?('kernel_data.c') or File.mtime('kernel.c') > File.mtime('kernel_data.c')
+ # Locate llvm-gcc...
+ path = ENV['PATH'].split(':')
+ path.unshift('/Developer/usr/bin')
+ llvm_gcc = path.map { |x| File.join(x, 'llvm-gcc') }.find { |x| File.exist?(x) }
+ unless llvm_gcc
+ $stderr.puts "Cannot locate llvm-gcc in given path: #{path}"
+ exit 1
+ end
+ opt = File.join(LLVM_PATH, 'bin/opt')
+ unless File.exist?(opt)
+ $stderr.puts "Cannot locate opt in given LLVM path: #{LLVM_PATH}"
+ end
+ sh "echo '' > kernel_data.c"
+ ARCHS.each do |x|
+ output = "kernel-#{x}.bc"
+ sh "#{llvm_gcc} -arch #{x} -fexceptions -I. -I./include --emit-llvm -c kernel.c -o #{output}"
+ sh "#{opt} -O3 #{output} -o=#{output}"
+ sh "/usr/bin/xxd -i #{output} >> kernel_data.c"
+ sh "/bin/rm #{output}"
+ end
+ end
t = File.exist?('dispatcher.o') ? File.mtime('dispatcher.o') : nil
$builder.build
if t == nil or File.mtime('dispatcher.o') > t
@@ -69,14 +91,6 @@
task :build => :dylib do
$builder.link_executable(RUBY_INSTALL_NAME, ['main', 'gc-stub'], "-L. -l#{RUBY_SO_NAME} -lobjc")
end
-
- # Generates a list of weak symbols in libmacruby.dylib. You must not pass a unexported symbols list to
- # rake when calling this command.
- task :weak_symbols => :dylib do
- sh("nm -m -P -arch i386 libmacruby.1.9.0.dylib | grep 'weak external' | grep -v 'undefined' | egrep -v '__ZT[IS]' | awk '{print$5}' > /tmp/syms-i386")
- sh("nm -m -P -arch x86_64 libmacruby.1.9.0.dylib | grep 'weak external' | grep -v 'undefined' | egrep -v '__ZT[IS]' | awk '{print$5}' > /tmp/syms-x86_64")
- sh("cat /tmp/syms-i386 /tmp/syms-x86_64 | uniq > unexported_symbols.list")
- end
end
DESTDIR = (ENV['DESTDIR'] or "")
@@ -163,7 +177,7 @@
desc "Clean local build files"
task :local do
$builder.clean
- list = ['parse.c', 'lex.c', INSTALLED_LIST, 'Makefile', RUBY_INSTALL_NAME, 'miniruby']
+ list = ['parse.c', 'lex.c', INSTALLED_LIST, 'Makefile', RUBY_INSTALL_NAME, 'miniruby', 'kernel_data.c']
list.concat(Dir['*.inc'])
list.concat(Dir['lib*.{dylib,a}'])
list.each { |x| rm_f(x) }
Modified: MacRuby/trunk/string.c
===================================================================
--- MacRuby/trunk/string.c 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/string.c 2010-05-24 02:24:56 UTC (rev 4136)
@@ -428,7 +428,7 @@
if (self->length_in_bytes == 0) {
return 0;
}
- if (str_is_stored_in_uchars(self)) {
+ if (str_try_making_data_uchars(self)) {
long length;
if (ucs2_mode) {
length = BYTES_TO_UCHARS(self->length_in_bytes);
@@ -4401,6 +4401,9 @@
const long len = str_length(RSTR(str), true);
long width = NUM2LONG(w);
str = rb_str_new3(str);
+ if (str_is_stored_in_uchars(RSTR(padstr))) {
+ str_try_making_data_uchars(RSTR(str));
+ }
if (width < 0 || width <= len) {
return str;
}
Modified: MacRuby/trunk/vm.cpp
===================================================================
--- MacRuby/trunk/vm.cpp 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/vm.cpp 2010-05-24 02:24:56 UTC (rev 4136)
@@ -30,7 +30,8 @@
#include <llvm/Target/TargetSelect.h>
#include <llvm/Transforms/Scalar.h>
#include <llvm/Support/raw_ostream.h>
-#include <llvm/Support/PrettyStackTrace.h> // Including PST to disable it
+#include <llvm/Support/PrettyStackTrace.h>
+#include <llvm/Support/MemoryBuffer.h>
#include <llvm/Intrinsics.h>
#include <llvm/Bitcode/ReaderWriter.h>
#include <llvm/LLVMContext.h>
@@ -302,6 +303,7 @@
{
running = false;
abort_on_exception = false;
+ inlining_enabled = getenv("VM_DISABLE_INLINING") == NULL;
pthread_assert(pthread_mutex_init(&gl, 0));
@@ -326,8 +328,30 @@
InitializeNativeTarget();
+ CodeGenOpt::Level opt = CodeGenOpt::Default;
+ const char *env_str = getenv("VM_OPT_LEVEL");
+ if (env_str != NULL) {
+ const int tmp = atoi(env_str);
+ if (tmp >= 0 && tmp <= 3) {
+ switch (tmp) {
+ case 0:
+ opt = CodeGenOpt::None;
+ break;
+ case 1:
+ opt = CodeGenOpt::Less;
+ break;
+ case 2:
+ opt = CodeGenOpt::Default;
+ break;
+ case 3:
+ opt = CodeGenOpt::Aggressive;
+ break;
+ }
+ }
+ }
+
std::string err;
- ee = ExecutionEngine::createJIT(emp, &err, jmm, CodeGenOpt::None, false);
+ ee = ExecutionEngine::createJIT(emp, &err, jmm, opt, false);
if (ee == NULL) {
fprintf(stderr, "error while creating JIT: %s\n", err.c_str());
abort();
@@ -497,8 +521,17 @@
return s;
}
+void
+RoxorCore::optimize(Function *func)
+{
+ if (inlining_enabled) {
+ RoxorCompiler::shared->inline_function_calls(func);
+ }
+ fpm->run(*func);
+}
+
IMP
-RoxorCore::compile(Function *func)
+RoxorCore::compile(Function *func, bool run_optimize)
{
std::map<Function *, IMP>::iterator iter = JITcache.find(func);
if (iter != JITcache.end()) {
@@ -511,15 +544,19 @@
if (!ruby_aot_compile) {
if (verifyModule(*RoxorCompiler::module, PrintMessageAction)) {
printf("Error during module verification\n");
- exit(1);
+ abort();
}
}
uint64_t start = mach_absolute_time();
#endif
- // Optimize & compile.
- optimize(func);
+ // Optimize if needed.
+ if (run_optimize) {
+ optimize(func);
+ }
+
+ // Compile & cache.
IMP imp = (IMP)ee->getPointerToFunction(func);
JITcache[func] = imp;
@@ -807,7 +844,7 @@
&& ee->getTargetData()->getTypeSizeInBits(type) > LARGE_STRUCT_SIZE;
}
-inline GlobalVariable *
+GlobalVariable *
RoxorCore::redefined_op_gvar(SEL sel, bool create)
{
std::map <SEL, GlobalVariable *>::iterator iter =
@@ -816,10 +853,11 @@
if (iter == redefined_ops_gvars.end()) {
if (create) {
gvar = new GlobalVariable(*RoxorCompiler::module,
- Type::getInt1Ty(context),
+ Type::getInt8Ty(context),
ruby_aot_compile ? true : false,
GlobalValue::InternalLinkage,
- ConstantInt::getFalse(context), "");
+ ConstantInt::get(Type::getInt8Ty(context), 0),
+ "");
assert(gvar != NULL);
redefined_ops_gvars[sel] = gvar;
}
@@ -830,7 +868,7 @@
return gvar;
}
-inline bool
+bool
RoxorCore::should_invalidate_inline_op(SEL sel, Class klass)
{
if (sel == selEq || sel == selEqq || sel == selNeq) {
@@ -899,7 +937,6 @@
}
}
}
-
}
void
@@ -1144,26 +1181,6 @@
GET_CORE()->set_abort_on_exception(flag);
}
-extern "C"
-void
-rb_vm_set_const(VALUE outer, ID id, VALUE obj, unsigned char dynamic_class)
-{
- if (dynamic_class) {
- Class k = GET_VM()->get_current_class();
- if (k != NULL) {
- outer = (VALUE)k;
- }
- }
-#if ROXOR_VM_DEBUG
- printf("define const %s::%s to %p\n",
- class_getName((Class)outer),
- rb_id2name(id),
- (void *)obj);
-#endif
- rb_const_set(outer, id, obj);
- GET_CORE()->const_defined(id);
-}
-
static inline VALUE
rb_const_get_direct(VALUE klass, ID id)
{
@@ -1202,9 +1219,11 @@
return Qundef;
}
-static VALUE
+extern "C"
+VALUE
rb_vm_const_lookup(VALUE outer, ID path, bool lexical, bool defined)
{
+ rb_vm_check_if_module(outer);
if (lexical) {
// Let's do a lexical lookup before a hierarchical one, by looking for
// the given constant in all modules under the given outer.
@@ -1225,52 +1244,7 @@
return defined ? rb_const_defined(outer, path) : rb_const_get(outer, path);
}
-static inline void
-check_if_module(VALUE mod)
-{
- switch (TYPE(mod)) {
- case T_CLASS:
- case T_MODULE:
- break;
-
- default:
- rb_raise(rb_eTypeError, "%s is not a class/module",
- RSTRING_PTR(rb_inspect(mod)));
- }
-}
-
extern "C"
-VALUE
-rb_vm_get_const(VALUE outer, struct ccache *cache, ID path, int flags)
-{
- const bool lexical_lookup = (flags & CONST_LOOKUP_LEXICAL);
- const bool dynamic_class = (flags & CONST_LOOKUP_DYNAMIC_CLASS);
-
- if (dynamic_class) {
- Class k = GET_VM()->get_current_class();
- if (lexical_lookup && k != NULL) {
- outer = (VALUE)k;
- }
- }
-
- assert(cache != NULL);
-
- VALUE val;
- if (cache->outer == outer && cache->val != Qundef) {
- val = cache->val;
- }
- else {
- check_if_module(outer);
- val = rb_vm_const_lookup(outer, path, lexical_lookup, false);
- assert(val != Qundef);
- cache->outer = outer;
- cache->val = val;
- }
-
- return val;
-}
-
-extern "C"
void
rb_vm_const_is_defined(ID path)
{
@@ -1343,7 +1317,7 @@
unsigned char dynamic_class)
{
assert(path > 0);
- check_if_module(outer);
+ rb_vm_check_if_module(outer);
if (dynamic_class) {
Class k = GET_VM()->get_current_class();
@@ -1355,7 +1329,7 @@
VALUE klass = get_klass_const(outer, path, dynamic_class);
if (klass != Qundef) {
// Constant is already defined.
- check_if_module(klass);
+ rb_vm_check_if_module(klass);
if (!(flags & DEFINE_MODULE) && super != 0) {
if (rb_class_real(RCLASS_SUPER(klass), true) != super) {
rb_raise(rb_eTypeError, "superclass mismatch for class %s",
@@ -1424,9 +1398,6 @@
return klass;
}
-#define LIKELY(x) (__builtin_expect((x), 1))
-#define UNLIKELY(x) (__builtin_expect((x), 0))
-
extern "C"
int
rb_vm_get_ivar_slot(VALUE obj, ID name, bool create)
@@ -1454,169 +1425,6 @@
return -1;
}
-extern "C"
-VALUE
-rb_vm_ivar_get(VALUE obj, ID name, struct icache *cache)
-{
- VALUE klass = CLASS_OF(obj);
- if (LIKELY(klass == cache->klass)) {
-use_slot:
- if ((unsigned int)cache->slot < ROBJECT(obj)->num_slots) {
- rb_object_ivar_slot_t *slot = &ROBJECT(obj)->slots[cache->slot];
- if (slot->name == name) {
-#if ROXOR_VM_DEBUG
- printf("get ivar <%s %p> %s slot %d -> %p\n",
- class_getName((Class)CLASS_OF(obj)), (void *)obj,
- rb_id2name(name), cache->slot, (void *)slot->value);
-#endif
- VALUE val = slot->value;
- return val == Qundef ? Qnil : val;
- }
- }
- goto recache;
- }
- else {
- goto recache;
- }
-
- if (cache->slot == SLOT_CACHE_VIRGIN) {
-recache:
- const int slot = rb_vm_get_ivar_slot(obj, name, true);
- if (slot >= 0) {
- cache->klass = klass;
- cache->slot = slot;
- goto use_slot;
- }
- cache->klass = 0;
- cache->slot = SLOT_CACHE_CANNOT;
- }
-
- assert(cache->slot == SLOT_CACHE_CANNOT);
-#if ROXOR_VM_DEBUG
- printf("get ivar <%s %p> %s without slot\n",
- class_getName((Class)CLASS_OF(obj)), (void *)obj, rb_id2name(name));
-#endif
- return rb_ivar_get(obj, name);
-}
-
-extern "C"
-void
-rb_vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache_ptr)
-{
- struct icache *cache = (struct icache *)cache_ptr;
- VALUE klass = CLASS_OF(obj);
- if (LIKELY(klass == cache->klass)) {
-use_slot:
- if ((unsigned int)cache->slot < ROBJECT(obj)->num_slots) {
- rb_object_ivar_slot_t *slot = &ROBJECT(obj)->slots[cache->slot];
- if (slot->name == name) {
- if ((ROBJECT(obj)->basic.flags & FL_FREEZE) == FL_FREEZE) {
- rb_error_frozen("object");
- }
-#if ROXOR_VM_DEBUG
- printf("set ivar <%s %p> %s to %p slot %d\n",
- class_getName((Class)CLASS_OF(obj)), (void *)obj,
- rb_id2name(name), (void *)val, cache->slot);
-#endif
- GC_WB(&slot->value, val);
- return;
- }
- }
- goto recache;
- }
- else {
- goto recache;
- }
-
- if (cache->slot == SLOT_CACHE_VIRGIN) {
-recache:
- const int slot = rb_vm_get_ivar_slot(obj, name, true);
- if (slot >= 0) {
- cache->klass = klass;
- cache->slot = slot;
- goto use_slot;
- }
- cache->slot = SLOT_CACHE_CANNOT;
- }
-
- assert(cache->slot == SLOT_CACHE_CANNOT);
-#if ROXOR_VM_DEBUG
- printf("set ivar <%s %p> %s to %p without slot\n",
- class_getName((Class)CLASS_OF(obj)), (void *)obj,
- rb_id2name(name), (void *)val);
-#endif
- rb_ivar_set(obj, name, val);
-}
-
-extern "C"
-VALUE
-rb_vm_cvar_get(VALUE klass, ID id, unsigned char check,
- unsigned char dynamic_class)
-{
- if (dynamic_class) {
- Class k = GET_VM()->get_current_class();
- if (k != NULL) {
- klass = (VALUE)k;
- }
- }
- return rb_cvar_get2(klass, id, check);
-}
-
-extern "C"
-VALUE
-rb_vm_cvar_set(VALUE klass, ID id, VALUE val, unsigned char dynamic_class)
-{
- if (dynamic_class) {
- Class k = GET_VM()->get_current_class();
- if (k != NULL) {
- klass = (VALUE)k;
- }
- }
- rb_cvar_set(klass, id, val);
- return val;
-}
-
-extern "C"
-VALUE
-rb_vm_ary_cat(VALUE ary, VALUE obj)
-{
- if (TYPE(obj) == T_ARRAY) {
- rb_ary_concat(ary, obj);
- }
- else {
- VALUE ary2 = rb_check_convert_type(obj, T_ARRAY, "Array", "to_a");
- if (!NIL_P(ary2)) {
- rb_ary_concat(ary, ary2);
- }
- else {
- rb_ary_push(ary, obj);
- }
- }
- return ary;
-}
-
-extern "C"
-VALUE
-rb_vm_to_a(VALUE obj)
-{
- VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_a");
- if (NIL_P(ary)) {
- ary = rb_ary_new3(1, obj);
- }
- return ary;
-}
-
-extern "C"
-VALUE
-rb_vm_to_ary(VALUE obj)
-{
- VALUE ary = rb_check_convert_type(obj, T_ARRAY, "Array", "to_ary");
- if (NIL_P(ary)) {
- ary = rb_ary_new3(1, obj);
- }
- return ary;
-}
-
extern "C" void rb_print_undef(VALUE, ID, int);
static void
@@ -1974,7 +1782,7 @@
if (iter == objc_to_ruby_stubs.end()) {
Function *objc_func = RoxorCompiler::shared->compile_objc_stub(func,
imp, arity, types);
- objc_imp = compile(objc_func);
+ objc_imp = compile(objc_func, false);
objc_to_ruby_stubs[imp] = objc_imp;
}
else {
@@ -2690,7 +2498,7 @@
// Not needed!
return imp;
}
- return (void *)GET_CORE()->compile(func);
+ return (void *)GET_CORE()->compile(func, false);
}
void
@@ -2811,46 +2619,6 @@
extern "C"
VALUE
-rb_vm_masgn_get_elem_before_splat(VALUE ary, int offset)
-{
- if (offset < RARRAY_LEN(ary)) {
- return RARRAY_AT(ary, offset);
- }
- return Qnil;
-}
-
-extern "C"
-VALUE
-rb_vm_masgn_get_elem_after_splat(VALUE ary, int before_splat_count, int after_splat_count, int offset)
-{
- int len = RARRAY_LEN(ary);
- if (len < before_splat_count + after_splat_count) {
- offset += before_splat_count;
- if (offset < len) {
- return RARRAY_AT(ary, offset);
- }
- }
- else {
- offset += len - after_splat_count;
- return RARRAY_AT(ary, offset);
- }
- return Qnil;
-}
-
-extern "C"
-VALUE
-rb_vm_masgn_get_splat(VALUE ary, int before_splat_count, int after_splat_count) {
- int len = RARRAY_LEN(ary);
- if (len > before_splat_count + after_splat_count) {
- return rb_ary_subseq(ary, before_splat_count, len - before_splat_count - after_splat_count);
- }
- else {
- return rb_ary_new();
- }
-}
-
-extern "C"
-VALUE
rb_vm_method_missing(VALUE obj, int argc, const VALUE *argv)
{
if (argc == 0 || !SYMBOL_P(argv[0])) {
@@ -2921,7 +2689,7 @@
if (iter == stubs.end()) {
Function *f = RoxorCompiler::shared->compile_long_arity_stub(argc,
is_block);
- stub = (void *)compile(f);
+ stub = (void *)compile(f, false);
stubs.insert(std::make_pair(argc, stub));
}
else {
@@ -3429,41 +3197,6 @@
}
#endif
-extern "C"
-VALUE
-rb_vm_get_special(char code)
-{
- VALUE backref = rb_backref_get();
- if (backref == Qnil) {
- return Qnil;
- }
-
- VALUE val;
- switch (code) {
- case '&':
- val = rb_reg_last_match(backref);
- break;
- case '`':
- val = rb_reg_match_pre(backref);
- break;
- case '\'':
- val = rb_reg_match_post(backref);
- break;
- case '+':
- val = rb_reg_match_last(backref);
- break;
- default:
- {
- const int index = (int)code;
- // Boundaries check is done in rb_reg_nth_match().
- val = rb_reg_nth_match(index, backref);
- }
- break;
- }
-
- return val;
-}
-
static inline void
__vm_raise(void)
{
@@ -3950,7 +3683,7 @@
extern "C"
VALUE
rb_vm_run(const char *fname, NODE *node, rb_vm_binding_t *binding,
- bool inside_eval)
+ bool inside_eval)
{
RoxorVM *vm = GET_VM();
RoxorCompiler *compiler = RoxorCompiler::shared;
@@ -3969,7 +3702,7 @@
vm->pop_current_binding(false);
}
- // JIT compile the function.
+ // Optimize & compile the function.
IMP imp = GET_CORE()->compile(function);
// Register it for symbolication.
@@ -4054,7 +3787,7 @@
// Force a module verification.
if (verifyModule(*RoxorCompiler::module, PrintMessageAction)) {
printf("Error during module verification\n");
- exit(1);
+ abort();
}
// Optimize the IR.
@@ -4813,66 +4546,6 @@
return GET_VM()->get_current_class();
}
-extern "C"
-void
-rb_vm_set_current_scope(VALUE mod, rb_vm_scope_t scope)
-{
- if (scope == SCOPE_DEFAULT) {
- scope = mod == rb_cObject ? SCOPE_PRIVATE : SCOPE_PUBLIC;
- }
- long v = RCLASS_VERSION(mod);
-#if ROXOR_VM_DEBUG
- const char *scope_name = NULL;
-#endif
- switch (scope) {
- case SCOPE_PUBLIC:
-#if ROXOR_VM_DEBUG
- scope_name = "public";
-#endif
- v &= ~RCLASS_SCOPE_PRIVATE;
- v &= ~RCLASS_SCOPE_PROTECTED;
- v &= ~RCLASS_SCOPE_MOD_FUNC;
- break;
-
- case SCOPE_PRIVATE:
-#if ROXOR_VM_DEBUG
- scope_name = "private";
-#endif
- v |= RCLASS_SCOPE_PRIVATE;
- v &= ~RCLASS_SCOPE_PROTECTED;
- v &= ~RCLASS_SCOPE_MOD_FUNC;
- break;
-
- case SCOPE_PROTECTED:
-#if ROXOR_VM_DEBUG
- scope_name = "protected";
-#endif
- v &= ~RCLASS_SCOPE_PRIVATE;
- v |= RCLASS_SCOPE_PROTECTED;
- v &= ~RCLASS_SCOPE_MOD_FUNC;
- break;
-
- case SCOPE_MODULE_FUNC:
-#if ROXOR_VM_DEBUG
- scope_name = "module_func";
-#endif
- v &= ~RCLASS_SCOPE_PRIVATE;
- v &= ~RCLASS_SCOPE_PROTECTED;
- v |= RCLASS_SCOPE_MOD_FUNC;
- break;
-
- case SCOPE_DEFAULT:
- abort(); // handled earlier
- }
-
-#if ROXOR_VM_DEBUG
- printf("changing scope of %s (%p) to %s\n",
- class_getName((Class)mod), (void *)mod, scope_name);
-#endif
-
- RCLASS_SET_VERSION(mod, v);
-}
-
static VALUE
builtin_ostub1(IMP imp, id self, SEL sel, int argc, VALUE *argv)
{
@@ -4933,6 +4606,8 @@
# define TARGET_TRIPLE "i386-apple-darwin"
#endif
+#include "kernel_data.c"
+
extern "C"
void
Init_PreVM(void)
@@ -4946,7 +4621,22 @@
// To not corrupt stack pointer (essential for backtracing).
llvm::NoFramePointerElim = true;
- RoxorCompiler::module = new llvm::Module("Roxor", getGlobalContext());
+ const char *kernel_beg;
+ const char *kernel_end;
+#if __LP64__
+ kernel_beg = (const char *)kernel_x86_64_bc;
+ kernel_end = kernel_beg + kernel_x86_64_bc_len;
+#else
+ kernel_beg = (const char *)kernel_i386_bc;
+ kernel_end = kernel_beg + kernel_i386_bc_len;
+#endif
+
+ MemoryBuffer *mbuf = MemoryBuffer::getMemBuffer(kernel_beg, kernel_end);
+ assert(mbuf != NULL);
+ RoxorCompiler::module = ParseBitcodeFile(mbuf, getGlobalContext());
+ delete mbuf;
+ assert(RoxorCompiler::module != NULL);
+
RoxorCompiler::module->setTargetTriple(TARGET_TRIPLE);
RoxorCore::shared = new RoxorCore();
RoxorVM::main = new RoxorVM();
@@ -5205,12 +4895,11 @@
if (getenv("VM_VERIFY_IR") != NULL) {
- printf("Verifying IR...\n");
if (verifyModule(*RoxorCompiler::module, PrintMessageAction)) {
printf("Error during module verification\n");
- exit(1);
+ abort();
}
- printf("Good!\n");
+ printf("IR verified!\n");
}
// XXX: deleting the core is not safe at this point because there might be
Modified: MacRuby/trunk/vm.h
===================================================================
--- MacRuby/trunk/vm.h 2010-05-24 02:15:12 UTC (rev 4135)
+++ MacRuby/trunk/vm.h 2010-05-24 02:24:56 UTC (rev 4136)
@@ -294,6 +294,7 @@
VALUE rb_vm_top_self(void);
void rb_vm_const_is_defined(ID path);
VALUE rb_vm_resolve_const_value(VALUE val, VALUE klass, ID name);
+VALUE rb_vm_const_lookup(VALUE outer, ID path, bool lexical, bool defined);
bool rb_vm_lookup_method(Class klass, SEL sel, IMP *pimp,
rb_vm_method_node_t **pnode);
bool rb_vm_lookup_method2(Class klass, ID mid, SEL *psel, IMP *pimp,
@@ -329,7 +330,6 @@
VALUE rb_vm_method_missing(VALUE obj, int argc, const VALUE *argv);
void rb_vm_push_methods(VALUE ary, VALUE mod, bool include_objc_methods,
int (*filter) (VALUE, ID, VALUE));
-void rb_vm_ivar_set(VALUE obj, ID name, VALUE val, void *cache);
void rb_vm_set_outer(VALUE klass, VALUE under);
VALUE rb_vm_get_outer(VALUE klass);
VALUE rb_vm_catch(VALUE tag);
@@ -502,16 +502,6 @@
void rb_vm_load_bridge_support(const char *path, const char *framework_path,
int options);
-typedef enum {
- SCOPE_DEFAULT = 0, // public for everything but Object
- SCOPE_PUBLIC,
- SCOPE_PRIVATE,
- SCOPE_PROTECTED,
- SCOPE_MODULE_FUNC,
-} rb_vm_scope_t;
-
-void rb_vm_set_current_scope(VALUE mod, rb_vm_scope_t scope);
-
typedef struct {
VALUE klass;
VALUE objid;
@@ -522,16 +512,21 @@
void rb_vm_unregister_finalizer(rb_vm_finalizer_t *finalizer);
void rb_vm_call_finalizer(rb_vm_finalizer_t *finalizer);
-#if defined(__cplusplus)
-}
-
-#include "bridgesupport.h"
-
struct icache {
VALUE klass;
int slot;
};
+struct ccache {
+ VALUE outer;
+ VALUE val;
+};
+
+#if defined(__cplusplus)
+}
+
+#include "bridgesupport.h"
+
typedef struct {
Function *func;
rb_vm_arity_t arity;
@@ -572,11 +567,6 @@
#define fcache cache->as.fcall
};
-struct ccache {
- VALUE outer;
- VALUE val;
-};
-
// For rb_vm_define_class()
#define DEFINE_MODULE 0x1
#define DEFINE_OUTER 0x2
@@ -620,16 +610,16 @@
pthread_mutex_t gl;
// State.
+ bool inlining_enabled;
bool running;
bool abort_on_exception;
VALUE loaded_features;
VALUE load_path;
VALUE default_random;
- // Signals
+ // Signals.
std::map<int, VALUE> trap_cmd;
- // Safety level at the time trap is set
- std::map<int, int> trap_level;
+ std::map<int, int> trap_level;
// Cache to avoid compiling the same Function twice.
std::map<Function *, IMP> JITcache;
@@ -711,10 +701,8 @@
void register_thread(VALUE thread);
void unregister_thread(VALUE thread);
- void optimize(Function *func) {
- fpm->run(*func);
- }
- IMP compile(Function *func);
+ void optimize(Function *func);
+ IMP compile(Function *func, bool optimize=true);
void delenda(Function *func);
void load_bridge_support(const char *path, const char *framework_path,
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/macruby-changes/attachments/20100523/287da3c5/attachment-0001.html>
More information about the macruby-changes
mailing list