--- a/halfmoon/generated/InstrFactory_defs_impl.hh
+++ b/halfmoon/generated/InstrFactory_defs_impl.hh
@@ -3,48 +3,51 @@
///
/// shape_reps[] gives the representations of
/// the shapes enumerated by InstrShape.
///
extern const ShapeRep shape_reps[SHAPE_MAX] = {
{ 0, 0, kVarIn }, // GOTOINSTR_SHAPE
{ 0, 0, kVarOut }, // ARMINSTR_SHAPE
+ { 0, 0, kVarOut }, // CATCHBLOCKINSTR_SHAPE
{ 0, 0, kVarOut }, // LABELINSTR_SHAPE
{ 0, 1, kVarNone }, // CONSTANTEXPR_SHAPE
{ 0, 1, kVarOut }, // STARTINSTR_SHAPE
{ 1, 0, kVarIn }, // IFINSTR_SHAPE
{ 1, 0, kVarIn }, // SWITCHINSTR_SHAPE
{ 1, 1, kVarNone }, // UNARYEXPR_SHAPE
{ 2, 1, kVarNone }, // BINARYEXPR_SHAPE
{ 2, 1, kVarNone }, // SETLOCALINSTR_SHAPE
{ 1, 0, kVarIn }, // STOPINSTR_SHAPE
{ 1, 1, kVarIn }, // DEOPTSAFEPOINTINSTR_SHAPE
{ 1, 1, kVarNone }, // DEOPTFINISHINSTR_SHAPE
{ 1, 1, kVarNone }, // VOIDSTMT_SHAPE
{ 1, 2, kVarIn }, // NARYSTMT0_SHAPE
+ { 1, 2, kVarIn }, // SAFEPOINTINSTR_SHAPE
+ { 2, 1, kVarNone }, // DEBUGINSTR_SHAPE
{ 2, 1, kVarNone }, // DEOPTFINISHCALLINSTR_SHAPE
{ 2, 2, kVarIn }, // NARYSTMT1_SHAPE
- { 2, 2, kVarNone }, // SAFEPOINTINSTR_SHAPE
{ 2, 2, kVarNone }, // UNARYSTMT_SHAPE
{ 3, 2, kVarIn }, // CALLSTMT2_SHAPE
{ 3, 2, kVarIn }, // NARYSTMT2_SHAPE
{ 3, 2, kVarNone }, // BINARYSTMT_SHAPE
{ 3, 4, kVarNone }, // HASNEXT2STMT_SHAPE
{ 4, 2, kVarIn }, // CALLSTMT3_SHAPE
{ 4, 2, kVarIn }, // NARYSTMT3_SHAPE
{ 5, 2, kVarIn }, // CALLSTMT4_SHAPE
{ 5, 2, kVarIn }, // NARYSTMT4_SHAPE
};
/// instr_attrs describes the instructions enumerated in InstrKind.
///
extern const InstrAttrs instr_attrs[HR_MAX] = {
{ "start", STARTINSTR_SHAPE, false },
{ "template", STARTINSTR_SHAPE, false },
+ { "catchblock", CATCHBLOCKINSTR_SHAPE, false },
{ "return", STOPINSTR_SHAPE, false },
{ "throw", STOPINSTR_SHAPE, false },
{ "goto", GOTOINSTR_SHAPE, false },
{ "label", LABELINSTR_SHAPE, false },
{ "if", IFINSTR_SHAPE, false },
{ "switch", SWITCHINSTR_SHAPE, false },
{ "arm", ARMINSTR_SHAPE, false },
{ "const", CONSTANTEXPR_SHAPE, false },
@@ -71,16 +74,17 @@ extern const InstrAttrs instr_attrs[HR_M
{ "loadenv_boolean", BINARYEXPR_SHAPE, false },
{ "loadenv_number", BINARYEXPR_SHAPE, false },
{ "loadenv_string", BINARYEXPR_SHAPE, false },
{ "loadenv_interface", BINARYEXPR_SHAPE, false },
{ "loadenv", BINARYEXPR_SHAPE, false },
{ "loadenv_atom", BINARYEXPR_SHAPE, false },
{ "loadinitenv", UNARYEXPR_SHAPE, false },
{ "loadsuperinitenv", UNARYEXPR_SHAPE, false },
+ { "loadenv_env", BINARYEXPR_SHAPE, false },
{ "newobject", NARYSTMT0_SHAPE, false },
{ "newarray", NARYSTMT0_SHAPE, false },
{ "applytype", NARYSTMT0_SHAPE, false },
{ "newinstance", UNARYEXPR_SHAPE, false },
{ "abc_convert_s", UNARYSTMT_SHAPE, false },
{ "abc_esc_xelem", UNARYSTMT_SHAPE, false },
{ "abc_esc_xattr", UNARYSTMT_SHAPE, false },
{ "abc_typeof", UNARYEXPR_SHAPE, false },
@@ -121,23 +125,23 @@ extern const InstrAttrs instr_attrs[HR_M
{ "rshi", BINARYEXPR_SHAPE, false },
{ "rshui", BINARYEXPR_SHAPE, false },
{ "noti", UNARYEXPR_SHAPE, false },
{ "negi", UNARYEXPR_SHAPE, false },
{ "negd", UNARYEXPR_SHAPE, false },
{ "not", UNARYEXPR_SHAPE, false },
{ "newactivation", UNARYSTMT_SHAPE, false },
{ "abc_finddef", BINARYSTMT_SHAPE, false },
- { "abc_findpropstrict", NARYSTMT2_SHAPE, false },
- { "abc_findpropstrictx", NARYSTMT3_SHAPE, false },
- { "abc_findpropstrictns", NARYSTMT3_SHAPE, false },
+ { "abc_findpropstrict", NARYSTMT3_SHAPE, false },
+ { "abc_findpropstrictx", NARYSTMT4_SHAPE, false },
+ { "abc_findpropstrictns", NARYSTMT4_SHAPE, false },
{ "abc_findpropstrictnsx", NARYSTMT4_SHAPE, false },
- { "abc_findproperty", NARYSTMT2_SHAPE, false },
- { "abc_findpropertyx", NARYSTMT3_SHAPE, false },
- { "abc_findpropertyns", NARYSTMT3_SHAPE, false },
+ { "abc_findproperty", NARYSTMT3_SHAPE, false },
+ { "abc_findpropertyx", NARYSTMT4_SHAPE, false },
+ { "abc_findpropertyns", NARYSTMT4_SHAPE, false },
{ "abc_findpropertynsx", NARYSTMT4_SHAPE, false },
{ "newclass", NARYSTMT2_SHAPE, false },
{ "newfunction", NARYSTMT1_SHAPE, false },
{ "abc_getsuper", CALLSTMT2_SHAPE, false },
{ "abc_getsuperx", CALLSTMT3_SHAPE, false },
{ "abc_getsuperns", CALLSTMT3_SHAPE, false },
{ "abc_getsupernsx", CALLSTMT4_SHAPE, false },
{ "abc_getdescendants", CALLSTMT2_SHAPE, false },
@@ -169,29 +173,32 @@ extern const InstrAttrs instr_attrs[HR_M
{ "slottype", BINARYEXPR_SHAPE, false },
{ "getouterscope", BINARYEXPR_SHAPE, false },
{ "safepoint", SAFEPOINTINSTR_SHAPE, false },
{ "setlocal", SETLOCALINSTR_SHAPE, false },
{ "newstate", CONSTANTEXPR_SHAPE, false },
{ "deopt_safepoint", DEOPTSAFEPOINTINSTR_SHAPE, false },
{ "deopt_finish", DEOPTFINISHINSTR_SHAPE, false },
{ "deopt_finishcall", DEOPTFINISHCALLINSTR_SHAPE, false },
+ { "debugline", DEBUGINSTR_SHAPE, false },
+ { "debugfile", DEBUGINSTR_SHAPE, false },
{ "string2atom", UNARYEXPR_SHAPE, false },
{ "double2atom", UNARYEXPR_SHAPE, false },
{ "int2atom", UNARYEXPR_SHAPE, false },
{ "uint2atom", UNARYEXPR_SHAPE, false },
{ "scriptobject2atom", UNARYEXPR_SHAPE, false },
{ "bool2atom", UNARYEXPR_SHAPE, false },
{ "ns2atom", UNARYEXPR_SHAPE, false },
{ "atom2bool", UNARYEXPR_SHAPE, false },
{ "atom2double", UNARYEXPR_SHAPE, false },
{ "atom2string", UNARYEXPR_SHAPE, false },
{ "atom2int", UNARYEXPR_SHAPE, false },
{ "atom2uint", UNARYEXPR_SHAPE, false },
{ "atom2scriptobject", UNARYEXPR_SHAPE, false },
+ { "atom2ns", UNARYEXPR_SHAPE, false },
{ "i2d", UNARYEXPR_SHAPE, false },
{ "u2d", UNARYEXPR_SHAPE, false },
{ "d2i", UNARYEXPR_SHAPE, false },
{ "d2u", UNARYEXPR_SHAPE, false },
{ "toslot", BINARYEXPR_SHAPE, false },
{ "toprimitive", UNARYSTMT_SHAPE, false },
{ "eqi", BINARYEXPR_SHAPE, false },
{ "lti", BINARYEXPR_SHAPE, false },
--- a/halfmoon/generated/InstrFactory_defs_proto.hh
+++ b/halfmoon/generated/InstrFactory_defs_proto.hh
@@ -2,16 +2,17 @@
/// generated by templates.py -- do not edit
///
/// High level intermediate representation (HR) opcodes
///
enum InstrKind {
HR_start, // StartInstr
HR_template, // StartInstr
+ HR_catchblock, // CatchBlockInstr
HR_return, // StopInstr
HR_throw, // StopInstr
HR_goto, // GotoInstr
HR_label, // LabelInstr
HR_if, // IfInstr
HR_switch, // SwitchInstr
HR_arm, // ArmInstr
HR_const, // ConstantExpr
@@ -38,16 +39,17 @@ enum InstrKind {
HR_loadenv_boolean, // BinaryExpr
HR_loadenv_number, // BinaryExpr
HR_loadenv_string, // BinaryExpr
HR_loadenv_interface, // BinaryExpr
HR_loadenv, // BinaryExpr
HR_loadenv_atom, // BinaryExpr
HR_loadinitenv, // UnaryExpr
HR_loadsuperinitenv, // UnaryExpr
+ HR_loadenv_env, // BinaryExpr
HR_newobject, // NaryStmt0
HR_newarray, // NaryStmt0
HR_applytype, // NaryStmt0
HR_newinstance, // UnaryExpr
HR_abc_convert_s, // UnaryStmt
HR_abc_esc_xelem, // UnaryStmt
HR_abc_esc_xattr, // UnaryStmt
HR_abc_typeof, // UnaryExpr
@@ -88,23 +90,23 @@ enum InstrKind {
HR_rshi, // BinaryExpr
HR_rshui, // BinaryExpr
HR_noti, // UnaryExpr
HR_negi, // UnaryExpr
HR_negd, // UnaryExpr
HR_not, // UnaryExpr
HR_newactivation, // UnaryStmt
HR_abc_finddef, // BinaryStmt
- HR_abc_findpropstrict, // NaryStmt2
- HR_abc_findpropstrictx, // NaryStmt3
- HR_abc_findpropstrictns, // NaryStmt3
+ HR_abc_findpropstrict, // NaryStmt3
+ HR_abc_findpropstrictx, // NaryStmt4
+ HR_abc_findpropstrictns, // NaryStmt4
HR_abc_findpropstrictnsx, // NaryStmt4
- HR_abc_findproperty, // NaryStmt2
- HR_abc_findpropertyx, // NaryStmt3
- HR_abc_findpropertyns, // NaryStmt3
+ HR_abc_findproperty, // NaryStmt3
+ HR_abc_findpropertyx, // NaryStmt4
+ HR_abc_findpropertyns, // NaryStmt4
HR_abc_findpropertynsx, // NaryStmt4
HR_newclass, // NaryStmt2
HR_newfunction, // NaryStmt1
HR_abc_getsuper, // CallStmt2
HR_abc_getsuperx, // CallStmt3
HR_abc_getsuperns, // CallStmt3
HR_abc_getsupernsx, // CallStmt4
HR_abc_getdescendants, // CallStmt2
@@ -136,29 +138,32 @@ enum InstrKind {
HR_slottype, // BinaryExpr
HR_getouterscope, // BinaryExpr
HR_safepoint, // SafepointInstr
HR_setlocal, // SetlocalInstr
HR_newstate, // ConstantExpr
HR_deopt_safepoint, // DeoptSafepointInstr
HR_deopt_finish, // DeoptFinishInstr
HR_deopt_finishcall, // DeoptFinishCallInstr
+ HR_debugline, // DebugInstr
+ HR_debugfile, // DebugInstr
HR_string2atom, // UnaryExpr
HR_double2atom, // UnaryExpr
HR_int2atom, // UnaryExpr
HR_uint2atom, // UnaryExpr
HR_scriptobject2atom, // UnaryExpr
HR_bool2atom, // UnaryExpr
HR_ns2atom, // UnaryExpr
HR_atom2bool, // UnaryExpr
HR_atom2double, // UnaryExpr
HR_atom2string, // UnaryExpr
HR_atom2int, // UnaryExpr
HR_atom2uint, // UnaryExpr
HR_atom2scriptobject, // UnaryExpr
+ HR_atom2ns, // UnaryExpr
HR_i2d, // UnaryExpr
HR_u2d, // UnaryExpr
HR_d2i, // UnaryExpr
HR_d2u, // UnaryExpr
HR_toslot, // BinaryExpr
HR_toprimitive, // UnaryStmt
HR_eqi, // BinaryExpr
HR_lti, // BinaryExpr
@@ -370,41 +375,43 @@ struct ShapeRep {
/// InstrShape is an enumeration of HR instruction shapes.
/// The representation details of each InstrShape s is described by
/// shape_reps[s].
///
enum InstrShape {
GOTOINSTR_SHAPE, // 0, 0, kVarIn 1 instrs
ARMINSTR_SHAPE, // 0, 0, kVarOut 1 instrs
+ CATCHBLOCKINSTR_SHAPE, // 0, 0, kVarOut 1 instrs
LABELINSTR_SHAPE, // 0, 0, kVarOut 1 instrs
CONSTANTEXPR_SHAPE, // 0, 1, kVarNone 3 instrs
STARTINSTR_SHAPE, // 0, 1, kVarOut 2 instrs
IFINSTR_SHAPE, // 1, 0, kVarIn 1 instrs
SWITCHINSTR_SHAPE, // 1, 0, kVarIn 1 instrs
- UNARYEXPR_SHAPE, // 1, 1, kVarNone 32 instrs
- BINARYEXPR_SHAPE, // 2, 1, kVarNone 56 instrs
+ UNARYEXPR_SHAPE, // 1, 1, kVarNone 33 instrs
+ BINARYEXPR_SHAPE, // 2, 1, kVarNone 57 instrs
SETLOCALINSTR_SHAPE, // 2, 1, kVarNone 1 instrs
STOPINSTR_SHAPE, // 1, 0, kVarIn 2 instrs
DEOPTSAFEPOINTINSTR_SHAPE, // 1, 1, kVarIn 1 instrs
DEOPTFINISHINSTR_SHAPE, // 1, 1, kVarNone 1 instrs
VOIDSTMT_SHAPE, // 1, 1, kVarNone 0 instrs
NARYSTMT0_SHAPE, // 1, 2, kVarIn 3 instrs
+ SAFEPOINTINSTR_SHAPE, // 1, 2, kVarIn 1 instrs
+ DEBUGINSTR_SHAPE, // 2, 1, kVarNone 2 instrs
DEOPTFINISHCALLINSTR_SHAPE, // 2, 1, kVarNone 1 instrs
NARYSTMT1_SHAPE, // 2, 2, kVarIn 3 instrs
- SAFEPOINTINSTR_SHAPE, // 2, 2, kVarNone 1 instrs
UNARYSTMT_SHAPE, // 2, 2, kVarNone 42 instrs
CALLSTMT2_SHAPE, // 3, 2, kVarIn 39 instrs
- NARYSTMT2_SHAPE, // 3, 2, kVarIn 3 instrs
+ NARYSTMT2_SHAPE, // 3, 2, kVarIn 1 instrs
BINARYSTMT_SHAPE, // 3, 2, kVarNone 73 instrs
HASNEXT2STMT_SHAPE, // 3, 4, kVarNone 1 instrs
CALLSTMT3_SHAPE, // 4, 2, kVarIn 52 instrs
- NARYSTMT3_SHAPE, // 4, 2, kVarIn 4 instrs
+ NARYSTMT3_SHAPE, // 4, 2, kVarIn 2 instrs
CALLSTMT4_SHAPE, // 5, 2, kVarIn 11 instrs
- NARYSTMT4_SHAPE, // 5, 2, kVarIn 2 instrs
+ NARYSTMT4_SHAPE, // 5, 2, kVarIn 6 instrs
SHAPE_MAX = NARYSTMT4_SHAPE + 1
};
/// shape_reps[] gives the representations of
/// the shapes enumerated by InstrShape.
///
extern const ShapeRep shape_reps[SHAPE_MAX];
--- a/halfmoon/generated/InstrFactory_preds_impl.hh
+++ b/halfmoon/generated/InstrFactory_preds_impl.hh
@@ -12,16 +12,21 @@ bool InstrFactory::isGotoInstr(InstrKind
return instr_attrs[k].shape == GOTOINSTR_SHAPE;
}
/// true if given InstrKind is instance of ArmInstr
bool InstrFactory::isArmInstr(InstrKind k) {
return instr_attrs[k].shape == ARMINSTR_SHAPE;
}
+/// true if given InstrKind is instance of CatchBlockInstr
+bool InstrFactory::isCatchBlockInstr(InstrKind k) {
+ return instr_attrs[k].shape == CATCHBLOCKINSTR_SHAPE;
+}
+
/// true if given InstrKind is instance of LabelInstr
bool InstrFactory::isLabelInstr(InstrKind k) {
return instr_attrs[k].shape == LABELINSTR_SHAPE;
}
/// true if given InstrKind is instance of ConstantExpr
bool InstrFactory::isConstantExpr(InstrKind k) {
return instr_attrs[k].shape == CONSTANTEXPR_SHAPE;
@@ -77,31 +82,36 @@ bool InstrFactory::isVoidStmt(InstrKind
return instr_attrs[k].shape == VOIDSTMT_SHAPE;
}
/// true if given InstrKind is instance of NaryStmt0
bool InstrFactory::isNaryStmt0(InstrKind k) {
return instr_attrs[k].shape == NARYSTMT0_SHAPE;
}
+/// true if given InstrKind is instance of SafepointInstr
+bool InstrFactory::isSafepointInstr(InstrKind k) {
+ return instr_attrs[k].shape == SAFEPOINTINSTR_SHAPE;
+}
+
+/// true if given InstrKind is instance of DebugInstr
+bool InstrFactory::isDebugInstr(InstrKind k) {
+ return instr_attrs[k].shape == DEBUGINSTR_SHAPE;
+}
+
/// true if given InstrKind is instance of DeoptFinishCallInstr
bool InstrFactory::isDeoptFinishCallInstr(InstrKind k) {
return instr_attrs[k].shape == DEOPTFINISHCALLINSTR_SHAPE;
}
/// true if given InstrKind is instance of NaryStmt1
bool InstrFactory::isNaryStmt1(InstrKind k) {
return instr_attrs[k].shape == NARYSTMT1_SHAPE;
}
-/// true if given InstrKind is instance of SafepointInstr
-bool InstrFactory::isSafepointInstr(InstrKind k) {
- return instr_attrs[k].shape == SAFEPOINTINSTR_SHAPE;
-}
-
/// true if given InstrKind is instance of UnaryStmt
bool InstrFactory::isUnaryStmt(InstrKind k) {
return instr_attrs[k].shape == UNARYSTMT_SHAPE;
}
/// true if given InstrKind is instance of CallStmt2
bool InstrFactory::isCallStmt2(InstrKind k) {
return instr_attrs[k].shape == CALLSTMT2_SHAPE;
--- a/halfmoon/generated/InstrFactory_preds_proto.hh
+++ b/halfmoon/generated/InstrFactory_preds_proto.hh
@@ -6,16 +6,19 @@
static bool hasTemplate(InstrKind k);
/// true if given InstrKind is instance of GotoInstr
static bool isGotoInstr(InstrKind k);
/// true if given InstrKind is instance of ArmInstr
static bool isArmInstr(InstrKind k);
+/// true if given InstrKind is instance of CatchBlockInstr
+static bool isCatchBlockInstr(InstrKind k);
+
/// true if given InstrKind is instance of LabelInstr
static bool isLabelInstr(InstrKind k);
/// true if given InstrKind is instance of ConstantExpr
static bool isConstantExpr(InstrKind k);
/// true if given InstrKind is instance of StartInstr
static bool isStartInstr(InstrKind k);
@@ -45,25 +48,28 @@ static bool isDeoptSafepointInstr(InstrK
static bool isDeoptFinishInstr(InstrKind k);
/// true if given InstrKind is instance of VoidStmt
static bool isVoidStmt(InstrKind k);
/// true if given InstrKind is instance of NaryStmt0
static bool isNaryStmt0(InstrKind k);
+/// true if given InstrKind is instance of SafepointInstr
+static bool isSafepointInstr(InstrKind k);
+
+/// true if given InstrKind is instance of DebugInstr
+static bool isDebugInstr(InstrKind k);
+
/// true if given InstrKind is instance of DeoptFinishCallInstr
static bool isDeoptFinishCallInstr(InstrKind k);
/// true if given InstrKind is instance of NaryStmt1
static bool isNaryStmt1(InstrKind k);
-/// true if given InstrKind is instance of SafepointInstr
-static bool isSafepointInstr(InstrKind k);
-
/// true if given InstrKind is instance of UnaryStmt
static bool isUnaryStmt(InstrKind k);
/// true if given InstrKind is instance of CallStmt2
static bool isCallStmt2(InstrKind k);
/// true if given InstrKind is instance of NaryStmt2
static bool isNaryStmt2(InstrKind k);
--- a/halfmoon/generated/InstrFactory_signatures_impl.hh
+++ b/halfmoon/generated/InstrFactory_signatures_impl.hh
@@ -9,16 +9,20 @@ const Type** InstrFactory::buildInputSig
case HR_start: {
/* start: () -> (Effect, Top) */
return NULL;
}
case HR_template: {
/* template: () -> (Effect, Top) */
return NULL;
}
+ case HR_catchblock: {
+ /* catchblock: () -> Top */
+ return NULL;
+ }
case HR_return: {
/* return: (Effect, Top) -> () */
const Type* input_sig[] = { EFFECT, TOP };
return copySig(2, input_sig);
}
case HR_throw: {
/* throw: (Effect, Atom) -> () */
const Type* input_sig[] = { EFFECT, lattice_.atom_type[kTypeNullable] };
@@ -179,16 +183,21 @@ const Type** InstrFactory::buildInputSig
case HR_loadinitenv: {
/* loadinitenv: ScriptObject~ -> Env */
return copySig(lattice_.scriptobject_type[kTypeNotNull]);
}
case HR_loadsuperinitenv: {
/* loadsuperinitenv: Env -> Env */
return copySig(ENV);
}
+ case HR_loadenv_env: {
+ /* loadenv_env: (Ord, Env) -> Env */
+ const Type* input_sig[] = { ORDINAL, ENV };
+ return copySig(2, input_sig);
+ }
case HR_newobject: {
/* newobject: (Effect, Atom) -> (Effect, ScriptObject~) */
const Type* input_sig[] = { EFFECT, lattice_.atom_type[kTypeNullable] };
return copySig(2, input_sig);
}
case HR_newarray: {
/* newarray: (Effect, Atom) -> (Effect, Array~) */
const Type* input_sig[] = { EFFECT, lattice_.atom_type[kTypeNullable] };
@@ -423,53 +432,53 @@ const Type** InstrFactory::buildInputSig
return copySig(2, input_sig);
}
case HR_abc_finddef: {
/* abc_finddef: (Effect, Name, Env) -> (Effect, ScriptObject~) */
const Type* input_sig[] = { EFFECT, NAME, ENV };
return copySig(3, input_sig);
}
case HR_abc_findpropstrict: {
- /* abc_findpropstrict: (Effect, Name, Env, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNotNull] };
- return copySig(4, input_sig);
+ /* abc_findpropstrict: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNotNull] };
+ return copySig(5, input_sig);
}
case HR_abc_findpropstrictx: {
- /* abc_findpropstrictx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
- return copySig(5, input_sig);
+ /* abc_findpropstrictx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
+ return copySig(6, input_sig);
}
case HR_abc_findpropstrictns: {
- /* abc_findpropstrictns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
- return copySig(5, input_sig);
+ /* abc_findpropstrictns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
+ return copySig(6, input_sig);
}
case HR_abc_findpropstrictnsx: {
- /* abc_findpropstrictnsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
+ /* abc_findpropstrictnsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
return copySig(6, input_sig);
}
case HR_abc_findproperty: {
- /* abc_findproperty: (Effect, Name, Env, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNotNull] };
- return copySig(4, input_sig);
+ /* abc_findproperty: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNotNull] };
+ return copySig(5, input_sig);
}
case HR_abc_findpropertyx: {
- /* abc_findpropertyx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
- return copySig(5, input_sig);
+ /* abc_findpropertyx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
+ return copySig(6, input_sig);
}
case HR_abc_findpropertyns: {
- /* abc_findpropertyns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
- return copySig(5, input_sig);
+ /* abc_findpropertyns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
+ return copySig(6, input_sig);
}
case HR_abc_findpropertynsx: {
- /* abc_findpropertynsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~) */
- const Type* input_sig[] = { EFFECT, NAME, ENV, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
+ /* abc_findpropertynsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
+ const Type* input_sig[] = { EFFECT, NAME, ENV, ORDINAL, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
return copySig(6, input_sig);
}
case HR_newclass: {
/* newclass: (Effect, Traits~, Class, Atom~) -> (Effect, Class~) */
const Type* input_sig[] = { EFFECT, TRAITS, lattice_.class_type[kTypeNullable], lattice_.atom_type[kTypeNotNull] };
return copySig(4, input_sig);
}
case HR_newfunction: {
@@ -593,32 +602,32 @@ const Type** InstrFactory::buildInputSig
return copySig(5, input_sig);
}
case HR_abc_callsupernsx: {
/* abc_callsupernsx: (Effect, Name, Atom, Atom, Atom~, Atom) -> (Effect, Atom) */
const Type* input_sig[] = { EFFECT, NAME, lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNullable], lattice_.atom_type[kTypeNotNull], lattice_.atom_type[kTypeNullable] };
return copySig(6, input_sig);
}
case HR_callstatic: {
- /* callstatic: (Effect, Ord, TopData, TopData) -> (Effect, TopData) */
- const Type* input_sig[] = { EFFECT, ORDINAL, TOPDATA, TOPDATA };
+ /* callstatic: (Effect, Env, TopData, TopData) -> (Effect, TopData) */
+ const Type* input_sig[] = { EFFECT, ENV, TOPDATA, TOPDATA };
return copySig(4, input_sig);
}
case HR_callmethod: {
/* callmethod: (Effect, Env, TopData, TopData) -> (Effect, TopData) */
const Type* input_sig[] = { EFFECT, ENV, TOPDATA, TOPDATA };
return copySig(4, input_sig);
}
case HR_callinterface: {
/* callinterface: (Effect, Env, TopData, TopData) -> (Effect, TopData) */
const Type* input_sig[] = { EFFECT, ENV, TOPDATA, TOPDATA };
return copySig(4, input_sig);
}
case HR_newcatch: {
- /* newcatch: (Effect, Traits~) -> (Effect, ScriptObject~) */
+ /* newcatch: (Effect, Traits~) -> (Effect, Atom~) */
const Type* input_sig[] = { EFFECT, TRAITS };
return copySig(2, input_sig);
}
case HR_setslot: {
/* setslot: (Effect, Ord, ScriptObject~, TopData) -> (Effect, Bot) */
const Type* input_sig[] = { EFFECT, ORDINAL, lattice_.scriptobject_type[kTypeNotNull], TOPDATA };
return copySig(4, input_sig);
}
@@ -638,18 +647,18 @@ const Type** InstrFactory::buildInputSig
return copySig(2, input_sig);
}
case HR_safepoint: {
/* safepoint: (Effect, State) -> (Effect, State) */
const Type* input_sig[] = { EFFECT, STATE };
return copySig(2, input_sig);
}
case HR_setlocal: {
- /* setlocal: (State, TopData) -> State */
- const Type* input_sig[] = { STATE, TOPDATA };
+ /* setlocal: (State, Atom) -> State */
+ const Type* input_sig[] = { STATE, lattice_.atom_type[kTypeNullable] };
return copySig(2, input_sig);
}
case HR_newstate: {
/* newstate: () -> State */
return NULL;
}
case HR_deopt_safepoint: {
/* deopt_safepoint: (Effect, TopData) -> Effect */
@@ -660,16 +669,26 @@ const Type** InstrFactory::buildInputSig
/* deopt_finish: Effect -> Effect */
return copySig(EFFECT);
}
case HR_deopt_finishcall: {
/* deopt_finishcall: (Effect, TopData) -> Effect */
const Type* input_sig[] = { EFFECT, TOPDATA };
return copySig(2, input_sig);
}
+ case HR_debugline: {
+ /* debugline: (Effect, Int) -> Effect */
+ const Type* input_sig[] = { EFFECT, lattice_.int_type };
+ return copySig(2, input_sig);
+ }
+ case HR_debugfile: {
+ /* debugfile: (Effect, String) -> Effect */
+ const Type* input_sig[] = { EFFECT, lattice_.string_type[kTypeNullable] };
+ return copySig(2, input_sig);
+ }
case HR_string2atom: {
/* string2atom: String -> Atom */
return copySig(lattice_.string_type[kTypeNullable]);
}
case HR_double2atom: {
/* double2atom: Number -> Atom~ */
return copySig(lattice_.double_type);
}
@@ -712,16 +731,20 @@ const Type** InstrFactory::buildInputSig
case HR_atom2uint: {
/* atom2uint: Atom -> Uint */
return copySig(lattice_.atom_type[kTypeNullable]);
}
case HR_atom2scriptobject: {
/* atom2scriptobject: Atom -> ScriptObject */
return copySig(lattice_.atom_type[kTypeNullable]);
}
+ case HR_atom2ns: {
+ /* atom2ns: Atom -> Namespace */
+ return copySig(lattice_.atom_type[kTypeNullable]);
+ }
case HR_i2d: {
/* i2d: Int -> Number */
return copySig(lattice_.int_type);
}
case HR_u2d: {
/* u2d: Uint -> Number */
return copySig(lattice_.uint_type);
}
@@ -1671,16 +1694,20 @@ const Type** InstrFactory::buildOutputSi
const Type* output_sig[] = { EFFECT, TOP };
return copySig(2, output_sig);
}
case HR_template: {
/* template: () -> (Effect, Top) */
const Type* output_sig[] = { EFFECT, TOP };
return copySig(2, output_sig);
}
+ case HR_catchblock: {
+ /* catchblock: () -> Top */
+ return copySig(TOP);
+ }
case HR_return: {
/* return: (Effect, Top) -> () */
return NULL;
}
case HR_throw: {
/* throw: (Effect, Atom) -> () */
return NULL;
}
@@ -1830,16 +1857,20 @@ const Type** InstrFactory::buildOutputSi
case HR_loadinitenv: {
/* loadinitenv: ScriptObject~ -> Env */
return copySig(ENV);
}
case HR_loadsuperinitenv: {
/* loadsuperinitenv: Env -> Env */
return copySig(ENV);
}
+ case HR_loadenv_env: {
+ /* loadenv_env: (Ord, Env) -> Env */
+ return copySig(ENV);
+ }
case HR_newobject: {
/* newobject: (Effect, Atom) -> (Effect, ScriptObject~) */
const Type* output_sig[] = { EFFECT, lattice_.scriptobject_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_newarray: {
/* newarray: (Effect, Atom) -> (Effect, Array~) */
const Type* output_sig[] = { EFFECT, lattice_.array_type[kTypeNotNull] };
@@ -2047,52 +2078,52 @@ const Type** InstrFactory::buildOutputSi
return copySig(2, output_sig);
}
case HR_abc_finddef: {
/* abc_finddef: (Effect, Name, Env) -> (Effect, ScriptObject~) */
const Type* output_sig[] = { EFFECT, lattice_.scriptobject_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findpropstrict: {
- /* abc_findpropstrict: (Effect, Name, Env, Atom~) -> (Effect, Atom~) */
+ /* abc_findpropstrict: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findpropstrictx: {
- /* abc_findpropstrictx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
+ /* abc_findpropstrictx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findpropstrictns: {
- /* abc_findpropstrictns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
+ /* abc_findpropstrictns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findpropstrictnsx: {
- /* abc_findpropstrictnsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~) */
+ /* abc_findpropstrictnsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findproperty: {
- /* abc_findproperty: (Effect, Name, Env, Atom~) -> (Effect, Atom~) */
+ /* abc_findproperty: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findpropertyx: {
- /* abc_findpropertyx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
+ /* abc_findpropertyx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findpropertyns: {
- /* abc_findpropertyns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~) */
+ /* abc_findpropertyns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_abc_findpropertynsx: {
- /* abc_findpropertynsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~) */
+ /* abc_findpropertynsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_newclass: {
/* newclass: (Effect, Traits~, Class, Atom~) -> (Effect, Class~) */
const Type* output_sig[] = { EFFECT, lattice_.class_type[kTypeNotNull] };
return copySig(2, output_sig);
}
@@ -2217,33 +2248,33 @@ const Type** InstrFactory::buildOutputSi
return copySig(2, output_sig);
}
case HR_abc_callsupernsx: {
/* abc_callsupernsx: (Effect, Name, Atom, Atom, Atom~, Atom) -> (Effect, Atom) */
const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNullable] };
return copySig(2, output_sig);
}
case HR_callstatic: {
- /* callstatic: (Effect, Ord, TopData, TopData) -> (Effect, TopData) */
+ /* callstatic: (Effect, Env, TopData, TopData) -> (Effect, TopData) */
const Type* output_sig[] = { EFFECT, TOPDATA };
return copySig(2, output_sig);
}
case HR_callmethod: {
/* callmethod: (Effect, Env, TopData, TopData) -> (Effect, TopData) */
const Type* output_sig[] = { EFFECT, TOPDATA };
return copySig(2, output_sig);
}
case HR_callinterface: {
/* callinterface: (Effect, Env, TopData, TopData) -> (Effect, TopData) */
const Type* output_sig[] = { EFFECT, TOPDATA };
return copySig(2, output_sig);
}
case HR_newcatch: {
- /* newcatch: (Effect, Traits~) -> (Effect, ScriptObject~) */
- const Type* output_sig[] = { EFFECT, lattice_.scriptobject_type[kTypeNotNull] };
+ /* newcatch: (Effect, Traits~) -> (Effect, Atom~) */
+ const Type* output_sig[] = { EFFECT, lattice_.atom_type[kTypeNotNull] };
return copySig(2, output_sig);
}
case HR_setslot: {
/* setslot: (Effect, Ord, ScriptObject~, TopData) -> (Effect, Bot) */
const Type* output_sig[] = { EFFECT, BOT };
return copySig(2, output_sig);
}
case HR_getslot: {
@@ -2260,17 +2291,17 @@ const Type** InstrFactory::buildOutputSi
return copySig(lattice_.atom_type[kTypeNotNull]);
}
case HR_safepoint: {
/* safepoint: (Effect, State) -> (Effect, State) */
const Type* output_sig[] = { EFFECT, STATE };
return copySig(2, output_sig);
}
case HR_setlocal: {
- /* setlocal: (State, TopData) -> State */
+ /* setlocal: (State, Atom) -> State */
return copySig(STATE);
}
case HR_newstate: {
/* newstate: () -> State */
return copySig(STATE);
}
case HR_deopt_safepoint: {
/* deopt_safepoint: (Effect, TopData) -> Effect */
@@ -2279,16 +2310,24 @@ const Type** InstrFactory::buildOutputSi
case HR_deopt_finish: {
/* deopt_finish: Effect -> Effect */
return copySig(EFFECT);
}
case HR_deopt_finishcall: {
/* deopt_finishcall: (Effect, TopData) -> Effect */
return copySig(EFFECT);
}
+ case HR_debugline: {
+ /* debugline: (Effect, Int) -> Effect */
+ return copySig(EFFECT);
+ }
+ case HR_debugfile: {
+ /* debugfile: (Effect, String) -> Effect */
+ return copySig(EFFECT);
+ }
case HR_string2atom: {
/* string2atom: String -> Atom */
return copySig(lattice_.atom_type[kTypeNullable]);
}
case HR_double2atom: {
/* double2atom: Number -> Atom~ */
return copySig(lattice_.atom_type[kTypeNotNull]);
}
@@ -2331,16 +2370,20 @@ const Type** InstrFactory::buildOutputSi
case HR_atom2uint: {
/* atom2uint: Atom -> Uint */
return copySig(lattice_.uint_type);
}
case HR_atom2scriptobject: {
/* atom2scriptobject: Atom -> ScriptObject */
return copySig(lattice_.scriptobject_type[kTypeNullable]);
}
+ case HR_atom2ns: {
+ /* atom2ns: Atom -> Namespace */
+ return copySig(lattice_.namespace_type[kTypeNullable]);
+ }
case HR_i2d: {
/* i2d: Int -> Number */
return copySig(lattice_.double_type);
}
case HR_u2d: {
/* u2d: Uint -> Number */
return copySig(lattice_.double_type);
}
--- a/halfmoon/generated/KindAdapter_cases.hh
+++ b/halfmoon/generated/KindAdapter_cases.hh
@@ -1,16 +1,18 @@
///
/// generated by templates.py -- do not edit
///
case HR_start:
return a->do_start(cast<StartInstr>(instr));
case HR_template:
return a->do_template(cast<StartInstr>(instr));
+case HR_catchblock:
+ return a->do_catchblock(cast<CatchBlockInstr>(instr));
case HR_return:
return a->do_return(cast<StopInstr>(instr));
case HR_throw:
return a->do_throw(cast<StopInstr>(instr));
case HR_goto:
return a->do_goto(cast<GotoInstr>(instr));
case HR_label:
return a->do_label(cast<LabelInstr>(instr));
@@ -73,16 +75,18 @@ case HR_loadenv_interface:
case HR_loadenv:
return a->do_loadenv(cast<BinaryExpr>(instr));
case HR_loadenv_atom:
return a->do_loadenv_atom(cast<BinaryExpr>(instr));
case HR_loadinitenv:
return a->do_loadinitenv(cast<UnaryExpr>(instr));
case HR_loadsuperinitenv:
return a->do_loadsuperinitenv(cast<UnaryExpr>(instr));
+case HR_loadenv_env:
+ return a->do_loadenv_env(cast<BinaryExpr>(instr));
case HR_newobject:
return a->do_newobject(cast<NaryStmt0>(instr));
case HR_newarray:
return a->do_newarray(cast<NaryStmt0>(instr));
case HR_applytype:
return a->do_applytype(cast<NaryStmt0>(instr));
case HR_newinstance:
return a->do_newinstance(cast<UnaryExpr>(instr));
@@ -174,29 +178,29 @@ case HR_negd:
return a->do_negd(cast<UnaryExpr>(instr));
case HR_not:
return a->do_not(cast<UnaryExpr>(instr));
case HR_newactivation:
return a->do_newactivation(cast<UnaryStmt>(instr));
case HR_abc_finddef:
return a->do_abc_finddef(cast<BinaryStmt>(instr));
case HR_abc_findpropstrict:
- return a->do_abc_findpropstrict(cast<NaryStmt2>(instr));
+ return a->do_abc_findpropstrict(cast<NaryStmt3>(instr));
case HR_abc_findpropstrictx:
- return a->do_abc_findpropstrictx(cast<NaryStmt3>(instr));
+ return a->do_abc_findpropstrictx(cast<NaryStmt4>(instr));
case HR_abc_findpropstrictns:
- return a->do_abc_findpropstrictns(cast<NaryStmt3>(instr));
+ return a->do_abc_findpropstrictns(cast<NaryStmt4>(instr));
case HR_abc_findpropstrictnsx:
return a->do_abc_findpropstrictnsx(cast<NaryStmt4>(instr));
case HR_abc_findproperty:
- return a->do_abc_findproperty(cast<NaryStmt2>(instr));
+ return a->do_abc_findproperty(cast<NaryStmt3>(instr));
case HR_abc_findpropertyx:
- return a->do_abc_findpropertyx(cast<NaryStmt3>(instr));
+ return a->do_abc_findpropertyx(cast<NaryStmt4>(instr));
case HR_abc_findpropertyns:
- return a->do_abc_findpropertyns(cast<NaryStmt3>(instr));
+ return a->do_abc_findpropertyns(cast<NaryStmt4>(instr));
case HR_abc_findpropertynsx:
return a->do_abc_findpropertynsx(cast<NaryStmt4>(instr));
case HR_newclass:
return a->do_newclass(cast<NaryStmt2>(instr));
case HR_newfunction:
return a->do_newfunction(cast<NaryStmt1>(instr));
case HR_abc_getsuper:
return a->do_abc_getsuper(cast<CallStmt2>(instr));
@@ -269,16 +273,20 @@ case HR_setlocal:
case HR_newstate:
return a->do_newstate(cast<ConstantExpr>(instr));
case HR_deopt_safepoint:
return a->do_deopt_safepoint(cast<DeoptSafepointInstr>(instr));
case HR_deopt_finish:
return a->do_deopt_finish(cast<DeoptFinishInstr>(instr));
case HR_deopt_finishcall:
return a->do_deopt_finishcall(cast<DeoptFinishCallInstr>(instr));
+case HR_debugline:
+ return a->do_debugline(cast<DebugInstr>(instr));
+case HR_debugfile:
+ return a->do_debugfile(cast<DebugInstr>(instr));
case HR_string2atom:
return a->do_string2atom(cast<UnaryExpr>(instr));
case HR_double2atom:
return a->do_double2atom(cast<UnaryExpr>(instr));
case HR_int2atom:
return a->do_int2atom(cast<UnaryExpr>(instr));
case HR_uint2atom:
return a->do_uint2atom(cast<UnaryExpr>(instr));
@@ -295,16 +303,18 @@ case HR_atom2double:
case HR_atom2string:
return a->do_atom2string(cast<UnaryExpr>(instr));
case HR_atom2int:
return a->do_atom2int(cast<UnaryExpr>(instr));
case HR_atom2uint:
return a->do_atom2uint(cast<UnaryExpr>(instr));
case HR_atom2scriptobject:
return a->do_atom2scriptobject(cast<UnaryExpr>(instr));
+case HR_atom2ns:
+ return a->do_atom2ns(cast<UnaryExpr>(instr));
case HR_i2d:
return a->do_i2d(cast<UnaryExpr>(instr));
case HR_u2d:
return a->do_u2d(cast<UnaryExpr>(instr));
case HR_d2i:
return a->do_d2i(cast<UnaryExpr>(instr));
case HR_d2u:
return a->do_d2u(cast<UnaryExpr>(instr));
--- a/halfmoon/generated/KindAdapter_methods.hh
+++ b/halfmoon/generated/KindAdapter_methods.hh
@@ -1,14 +1,15 @@
///
/// generated by templates.py -- do not edit
///
RETURN_TYPE do_start(StartInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_template(StartInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_catchblock(CatchBlockInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_return(StopInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_throw(StopInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_goto(GotoInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_label(LabelInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_if(IfInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_switch(SwitchInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_arm(ArmInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_const(ConstantExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
@@ -35,16 +36,17 @@ RETURN_TYPE do_loadenv_namespace(BinaryE
RETURN_TYPE do_loadenv_boolean(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_loadenv_number(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_loadenv_string(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_loadenv_interface(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_loadenv(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_loadenv_atom(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_loadinitenv(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_loadsuperinitenv(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_loadenv_env(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_newobject(NaryStmt0* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_newarray(NaryStmt0* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_applytype(NaryStmt0* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_newinstance(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_convert_s(UnaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_esc_xelem(UnaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_esc_xattr(UnaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_typeof(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
@@ -85,23 +87,23 @@ RETURN_TYPE do_lshi(BinaryExpr* i) { ret
RETURN_TYPE do_rshi(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_rshui(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_noti(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_negi(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_negd(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_not(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_newactivation(UnaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_finddef(BinaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
-RETURN_TYPE do_abc_findpropstrict(NaryStmt2* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
-RETURN_TYPE do_abc_findpropstrictx(NaryStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
-RETURN_TYPE do_abc_findpropstrictns(NaryStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_abc_findpropstrict(NaryStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_abc_findpropstrictx(NaryStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_abc_findpropstrictns(NaryStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_findpropstrictnsx(NaryStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
-RETURN_TYPE do_abc_findproperty(NaryStmt2* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
-RETURN_TYPE do_abc_findpropertyx(NaryStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
-RETURN_TYPE do_abc_findpropertyns(NaryStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_abc_findproperty(NaryStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_abc_findpropertyx(NaryStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_abc_findpropertyns(NaryStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_findpropertynsx(NaryStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_newclass(NaryStmt2* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_newfunction(NaryStmt1* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_getsuper(CallStmt2* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_getsuperx(CallStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_getsuperns(CallStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_getsupernsx(CallStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_abc_getdescendants(CallStmt2* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
@@ -133,29 +135,32 @@ RETURN_TYPE do_getslot(CallStmt2* i) { r
RETURN_TYPE do_slottype(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_getouterscope(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_safepoint(SafepointInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_setlocal(SetlocalInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_newstate(ConstantExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_deopt_safepoint(DeoptSafepointInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_deopt_finish(DeoptFinishInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_deopt_finishcall(DeoptFinishCallInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_debugline(DebugInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_debugfile(DebugInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_string2atom(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_double2atom(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_int2atom(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_uint2atom(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_scriptobject2atom(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_bool2atom(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_ns2atom(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_atom2bool(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_atom2double(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_atom2string(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_atom2int(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_atom2uint(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_atom2scriptobject(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_atom2ns(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_i2d(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_u2d(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_d2i(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_d2u(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_toslot(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_toprimitive(UnaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_eqi(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_lti(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
--- a/halfmoon/generated/ShapeAdapter_cases.hh
+++ b/halfmoon/generated/ShapeAdapter_cases.hh
@@ -1,16 +1,18 @@
///
/// generated by templates.py -- do not edit
///
case GOTOINSTR_SHAPE:
return a->do_GotoInstr(cast<GotoInstr>(instr));
case ARMINSTR_SHAPE:
return a->do_ArmInstr(cast<ArmInstr>(instr));
+case CATCHBLOCKINSTR_SHAPE:
+ return a->do_CatchBlockInstr(cast<CatchBlockInstr>(instr));
case LABELINSTR_SHAPE:
return a->do_LabelInstr(cast<LabelInstr>(instr));
case CONSTANTEXPR_SHAPE:
return a->do_ConstantExpr(cast<ConstantExpr>(instr));
case STARTINSTR_SHAPE:
return a->do_StartInstr(cast<StartInstr>(instr));
case IFINSTR_SHAPE:
return a->do_IfInstr(cast<IfInstr>(instr));
@@ -27,22 +29,24 @@ case STOPINSTR_SHAPE:
case DEOPTSAFEPOINTINSTR_SHAPE:
return a->do_DeoptSafepointInstr(cast<DeoptSafepointInstr>(instr));
case DEOPTFINISHINSTR_SHAPE:
return a->do_DeoptFinishInstr(cast<DeoptFinishInstr>(instr));
case VOIDSTMT_SHAPE:
return a->do_VoidStmt(cast<VoidStmt>(instr));
case NARYSTMT0_SHAPE:
return a->do_NaryStmt0(cast<NaryStmt0>(instr));
+case SAFEPOINTINSTR_SHAPE:
+ return a->do_SafepointInstr(cast<SafepointInstr>(instr));
+case DEBUGINSTR_SHAPE:
+ return a->do_DebugInstr(cast<DebugInstr>(instr));
case DEOPTFINISHCALLINSTR_SHAPE:
return a->do_DeoptFinishCallInstr(cast<DeoptFinishCallInstr>(instr));
case NARYSTMT1_SHAPE:
return a->do_NaryStmt1(cast<NaryStmt1>(instr));
-case SAFEPOINTINSTR_SHAPE:
- return a->do_SafepointInstr(cast<SafepointInstr>(instr));
case UNARYSTMT_SHAPE:
return a->do_UnaryStmt(cast<UnaryStmt>(instr));
case CALLSTMT2_SHAPE:
return a->do_CallStmt2(cast<CallStmt2>(instr));
case NARYSTMT2_SHAPE:
return a->do_NaryStmt2(cast<NaryStmt2>(instr));
case BINARYSTMT_SHAPE:
return a->do_BinaryStmt(cast<BinaryStmt>(instr));
--- a/halfmoon/generated/ShapeAdapter_methods.hh
+++ b/halfmoon/generated/ShapeAdapter_methods.hh
@@ -1,30 +1,32 @@
///
/// generated by templates.py -- do not edit
///
RETURN_TYPE do_GotoInstr(GotoInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_ArmInstr(ArmInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_CatchBlockInstr(CatchBlockInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_LabelInstr(LabelInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_ConstantExpr(ConstantExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_StartInstr(StartInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_IfInstr(IfInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_SwitchInstr(SwitchInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_UnaryExpr(UnaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_BinaryExpr(BinaryExpr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_SetlocalInstr(SetlocalInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_StopInstr(StopInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_DeoptSafepointInstr(DeoptSafepointInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_DeoptFinishInstr(DeoptFinishInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_VoidStmt(VoidStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_NaryStmt0(NaryStmt0* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_SafepointInstr(SafepointInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
+RETURN_TYPE do_DebugInstr(DebugInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_DeoptFinishCallInstr(DeoptFinishCallInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_NaryStmt1(NaryStmt1* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
-RETURN_TYPE do_SafepointInstr(SafepointInstr* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_UnaryStmt(UnaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_CallStmt2(CallStmt2* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_NaryStmt2(NaryStmt2* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_BinaryStmt(BinaryStmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_Hasnext2Stmt(Hasnext2Stmt* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_CallStmt3(CallStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_NaryStmt3(NaryStmt3* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
RETURN_TYPE do_CallStmt4(CallStmt4* i) { return static_cast<SELF_CLASS*>(this)->do_default(i); }
--- a/halfmoon/generated/Stub_callers.hh
+++ b/halfmoon/generated/Stub_callers.hh
@@ -199,16 +199,23 @@ class StubCaller {
}
// loadsuperinitenv: Env -> Env
static void do_loadsuperinitenv(Interpreter* interp, UnaryExpr* instr) {
interp->resultVal(instr->value_out()) = Value(Stubs::do_loadsuperinitenv(&interp->frame_,
interp->getEnv(instr->use(0))));
}
+ // loadenv_env: (Ord, Env) -> Env
+ static void do_loadenv_env(Interpreter* interp, BinaryExpr* instr) {
+ interp->resultVal(instr->value_out()) = Value(Stubs::do_loadenv_env(&interp->frame_,
+ interp->getOrdinal(instr->use(0)),
+ interp->getEnv(instr->use(1))));
+ }
+
// newobject: (Effect, Atom) -> (Effect, ScriptObject~)
static void do_newobject(Interpreter* interp, NaryStmt0* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = Value(Stubs::do_newobject(&interp->frame_,
@@ -501,124 +508,130 @@ class StubCaller {
// abc_finddef: (Effect, Name, Env) -> (Effect, ScriptObject~)
static void do_abc_finddef(Interpreter* interp, BinaryStmt* instr) {
interp->resultVal(instr->value_out()) = Value(Stubs::do_abc_finddef(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2))));
}
- // abc_findpropstrict: (Effect, Name, Env, Atom~) -> (Effect, Atom~)
- static void do_abc_findpropstrict(Interpreter* interp, NaryStmt2* instr) {
+ // abc_findpropstrict: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~)
+ static void do_abc_findpropstrict(Interpreter* interp, NaryStmt3* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findpropstrict(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
+ interp->getOrdinal(instr->use(3)),
argc, args));
}
- // abc_findpropstrictx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static void do_abc_findpropstrictx(Interpreter* interp, NaryStmt3* instr) {
+ // abc_findpropstrictx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static void do_abc_findpropstrictx(Interpreter* interp, NaryStmt4* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findpropstrictx(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
- interp->getAtom(instr->use(3)),
+ interp->getOrdinal(instr->use(3)),
+ interp->getAtom(instr->use(4)),
argc, args));
}
- // abc_findpropstrictns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static void do_abc_findpropstrictns(Interpreter* interp, NaryStmt3* instr) {
+ // abc_findpropstrictns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static void do_abc_findpropstrictns(Interpreter* interp, NaryStmt4* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findpropstrictns(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
- interp->getAtom(instr->use(3)),
+ interp->getOrdinal(instr->use(3)),
+ interp->getAtom(instr->use(4)),
argc, args));
}
- // abc_findpropstrictnsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~)
+ // abc_findpropstrictnsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
static void do_abc_findpropstrictnsx(Interpreter* interp, NaryStmt4* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findpropstrictnsx(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
- interp->getAtom(instr->use(3)),
+ interp->getOrdinal(instr->use(3)),
interp->getAtom(instr->use(4)),
argc, args));
}
- // abc_findproperty: (Effect, Name, Env, Atom~) -> (Effect, Atom~)
- static void do_abc_findproperty(Interpreter* interp, NaryStmt2* instr) {
+ // abc_findproperty: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~)
+ static void do_abc_findproperty(Interpreter* interp, NaryStmt3* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findproperty(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
+ interp->getOrdinal(instr->use(3)),
argc, args));
}
- // abc_findpropertyx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static void do_abc_findpropertyx(Interpreter* interp, NaryStmt3* instr) {
+ // abc_findpropertyx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static void do_abc_findpropertyx(Interpreter* interp, NaryStmt4* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findpropertyx(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
- interp->getAtom(instr->use(3)),
+ interp->getOrdinal(instr->use(3)),
+ interp->getAtom(instr->use(4)),
argc, args));
}
- // abc_findpropertyns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static void do_abc_findpropertyns(Interpreter* interp, NaryStmt3* instr) {
+ // abc_findpropertyns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static void do_abc_findpropertyns(Interpreter* interp, NaryStmt4* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findpropertyns(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
- interp->getAtom(instr->use(3)),
+ interp->getOrdinal(instr->use(3)),
+ interp->getAtom(instr->use(4)),
argc, args));
}
- // abc_findpropertynsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~)
+ // abc_findpropertynsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
static void do_abc_findpropertynsx(Interpreter* interp, NaryStmt4* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
Atom* args = (Atom*)interp->args_out_;
for (int i = 0; i < argc; ++i)
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_findpropertynsx(&interp->frame_,
interp->getName(instr->use(1)),
interp->getEnv(instr->use(2)),
- interp->getAtom(instr->use(3)),
+ interp->getOrdinal(instr->use(3)),
interp->getAtom(instr->use(4)),
argc, args));
}
// newclass: (Effect, Traits~, Class, Atom~) -> (Effect, Class~)
static void do_newclass(Interpreter* interp, NaryStmt2* instr) {
int argc = instr->arg_count();
Use* arg_uses = instr->args();
@@ -910,19 +923,19 @@ class StubCaller {
args[i] = interp->getAtom(arg_uses[i]);
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_abc_callsupernsx(&interp->frame_,
interp->getName(instr->use(1)),
interp->getAtom(instr->use(2)),
interp->getAtom(instr->use(3)),
argc, args));
}
- // newcatch: (Effect, Traits~) -> (Effect, ScriptObject~)
+ // newcatch: (Effect, Traits~) -> (Effect, Atom~)
static void do_newcatch(Interpreter* interp, UnaryStmt* instr) {
- interp->resultVal(instr->value_out()) = Value(Stubs::do_newcatch(&interp->frame_,
+ interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_newcatch(&interp->frame_,
interp->getTraits(instr->use(1))));
}
// slottype: (ScriptObject~, Ord) -> Traits
static void do_slottype(Interpreter* interp, BinaryExpr* instr) {
interp->resultVal(instr->value_out()) = Value(Stubs::do_slottype(&interp->frame_,
interp->getObject(instr->use(0)),
interp->getOrdinal(instr->use(1))));
@@ -937,16 +950,30 @@ class StubCaller {
// deopt_finish: Effect -> Effect
static void do_deopt_finish(Interpreter* interp, DeoptFinishInstr* instr) {
Stubs::do_deopt_finish(&interp->frame_);
(void)interp;
(void)instr;
}
+ // debugline: (Effect, Int) -> Effect
+ static void do_debugline(Interpreter* interp, DebugInstr* instr) {
+ Stubs::do_debugline(&interp->frame_,
+ interp->getInt(instr->use(1)));
+ (void)interp;
+ }
+
+ // debugfile: (Effect, String) -> Effect
+ static void do_debugfile(Interpreter* interp, DebugInstr* instr) {
+ Stubs::do_debugfile(&interp->frame_,
+ interp->getString(instr->use(1)));
+ (void)interp;
+ }
+
// string2atom: String -> Atom
static void do_string2atom(Interpreter* interp, UnaryExpr* instr) {
interp->resultVal(instr->value_out()) = AtomValue(Stubs::do_string2atom(&interp->frame_,
interp->getString(instr->use(0))));
}
// double2atom: Number -> Atom~
static void do_double2atom(Interpreter* interp, UnaryExpr* instr) {
@@ -1015,16 +1042,22 @@ class StubCaller {
}
// atom2scriptobject: Atom -> ScriptObject
static void do_atom2scriptobject(Interpreter* interp, UnaryExpr* instr) {
interp->resultVal(instr->value_out()) = Value(Stubs::do_atom2scriptobject(&interp->frame_,
interp->getAtom(instr->use(0))));
}
+ // atom2ns: Atom -> Namespace
+ static void do_atom2ns(Interpreter* interp, UnaryExpr* instr) {
+ interp->resultVal(instr->value_out()) = Value(Stubs::do_atom2ns(&interp->frame_,
+ interp->getAtom(instr->use(0))));
+ }
+
// i2d: Int -> Number
static void do_i2d(Interpreter* interp, UnaryExpr* instr) {
interp->resultVal(instr->value_out()) = Value(Stubs::do_i2d(&interp->frame_,
interp->getInt(instr->use(0))));
}
// u2d: Uint -> Number
static void do_u2d(Interpreter* interp, UnaryExpr* instr) {
@@ -1723,16 +1756,17 @@ class StubCaller {
(void)interp;
}
};
const Interpreter::StubCall Interpreter::stub_table[] = {
0, // start
0, // template
+ 0, // catchblock
0, // return
(StubCall)&StubCaller::do_throw,
0, // goto
0, // label
0, // if
0, // switch
0, // arm
0, // const
@@ -1759,16 +1793,17 @@ const Interpreter::StubCall Interpreter:
(StubCall)&StubCaller::do_loadenv_boolean,
(StubCall)&StubCaller::do_loadenv_number,
(StubCall)&StubCaller::do_loadenv_string,
(StubCall)&StubCaller::do_loadenv_interface,
(StubCall)&StubCaller::do_loadenv,
(StubCall)&StubCaller::do_loadenv_atom,
(StubCall)&StubCaller::do_loadinitenv,
(StubCall)&StubCaller::do_loadsuperinitenv,
+ (StubCall)&StubCaller::do_loadenv_env,
(StubCall)&StubCaller::do_newobject,
(StubCall)&StubCaller::do_newarray,
(StubCall)&StubCaller::do_applytype,
(StubCall)&StubCaller::do_newinstance,
(StubCall)&StubCaller::do_abc_convert_s,
(StubCall)&StubCaller::do_abc_esc_xelem,
(StubCall)&StubCaller::do_abc_esc_xattr,
(StubCall)&StubCaller::do_abc_typeof,
@@ -1857,29 +1892,32 @@ const Interpreter::StubCall Interpreter:
(StubCall)&StubCaller::do_slottype,
(StubCall)&StubCaller::do_getouterscope,
0, // safepoint
0, // setlocal
0, // newstate
0, // deopt_safepoint
(StubCall)&StubCaller::do_deopt_finish,
0, // deopt_finishcall
+ (StubCall)&StubCaller::do_debugline,
+ (StubCall)&StubCaller::do_debugfile,
(StubCall)&StubCaller::do_string2atom,
(StubCall)&StubCaller::do_double2atom,
(StubCall)&StubCaller::do_int2atom,
(StubCall)&StubCaller::do_uint2atom,
(StubCall)&StubCaller::do_scriptobject2atom,
(StubCall)&StubCaller::do_bool2atom,
(StubCall)&StubCaller::do_ns2atom,
(StubCall)&StubCaller::do_atom2bool,
(StubCall)&StubCaller::do_atom2double,
(StubCall)&StubCaller::do_atom2string,
(StubCall)&StubCaller::do_atom2int,
(StubCall)&StubCaller::do_atom2uint,
(StubCall)&StubCaller::do_atom2scriptobject,
+ (StubCall)&StubCaller::do_atom2ns,
(StubCall)&StubCaller::do_i2d,
(StubCall)&StubCaller::do_u2d,
(StubCall)&StubCaller::do_d2i,
(StubCall)&StubCaller::do_d2u,
(StubCall)&StubCaller::do_toslot,
(StubCall)&StubCaller::do_toprimitive,
(StubCall)&StubCaller::do_eqi,
(StubCall)&StubCaller::do_lti,
--- a/halfmoon/generated/Stub_lirtable.hh
+++ b/halfmoon/generated/Stub_lirtable.hh
@@ -1,16 +1,17 @@
///
/// generated by templates.py -- do not edit
///
namespace halfmoon {
const nanojit::CallInfo LirEmitter::lir_table[] = {
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "start")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "template")},
+ { 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "catchblock")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "return")},
{ (uintptr_t)&Stubs::do_throw, CallInfo::typeSig2(ARGTYPE_V, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "throw")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "goto")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "label")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "if")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "switch")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "arm")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "const")},
@@ -37,16 +38,17 @@ const nanojit::CallInfo LirEmitter::lir_
{ (uintptr_t)&Stubs::do_loadenv_boolean, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadenv_boolean")},
{ (uintptr_t)&Stubs::do_loadenv_number, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_D), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadenv_number")},
{ (uintptr_t)&Stubs::do_loadenv_string, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadenv_string")},
{ (uintptr_t)&Stubs::do_loadenv_interface, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadenv_interface")},
{ (uintptr_t)&Stubs::do_loadenv, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadenv")},
{ (uintptr_t)&Stubs::do_loadenv_atom, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadenv_atom")},
{ (uintptr_t)&Stubs::do_loadinitenv, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadinitenv")},
{ (uintptr_t)&Stubs::do_loadsuperinitenv, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadsuperinitenv")},
+ { (uintptr_t)&Stubs::do_loadenv_env, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "loadenv_env")},
{ (uintptr_t)&Stubs::do_newobject, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "newobject")},
{ (uintptr_t)&Stubs::do_newarray, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "newarray")},
{ (uintptr_t)&Stubs::do_applytype, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "applytype")},
{ (uintptr_t)&Stubs::do_newinstance, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "newinstance")},
{ (uintptr_t)&Stubs::do_abc_convert_s, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_convert_s")},
{ (uintptr_t)&Stubs::do_abc_esc_xelem, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_esc_xelem")},
{ (uintptr_t)&Stubs::do_abc_esc_xattr, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_esc_xattr")},
{ (uintptr_t)&Stubs::do_abc_typeof, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "abc_typeof")},
@@ -87,24 +89,24 @@ const nanojit::CallInfo LirEmitter::lir_
{ (uintptr_t)&Stubs::do_rshi, CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "rshi")},
{ (uintptr_t)&Stubs::do_rshui, CallInfo::typeSig3(ARGTYPE_UI, ARGTYPE_P, ARGTYPE_I, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "rshui")},
{ (uintptr_t)&Stubs::do_noti, CallInfo::typeSig2(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "noti")},
{ (uintptr_t)&Stubs::do_negi, CallInfo::typeSig2(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "negi")},
{ (uintptr_t)&Stubs::do_negd, CallInfo::typeSig2(ARGTYPE_D, ARGTYPE_P, ARGTYPE_D), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "negd")},
{ (uintptr_t)&Stubs::do_not, CallInfo::typeSig2(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "not")},
{ (uintptr_t)&Stubs::do_newactivation, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "newactivation")},
{ (uintptr_t)&Stubs::do_abc_finddef, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_finddef")},
- { (uintptr_t)&Stubs::do_abc_findpropstrict, CallInfo::typeSig5(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrict")},
- { (uintptr_t)&Stubs::do_abc_findpropstrictx, CallInfo::typeSig6(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrictx")},
- { (uintptr_t)&Stubs::do_abc_findpropstrictns, CallInfo::typeSig6(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrictns")},
- { (uintptr_t)&Stubs::do_abc_findpropstrictnsx, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrictnsx")},
- { (uintptr_t)&Stubs::do_abc_findproperty, CallInfo::typeSig5(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findproperty")},
- { (uintptr_t)&Stubs::do_abc_findpropertyx, CallInfo::typeSig6(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropertyx")},
- { (uintptr_t)&Stubs::do_abc_findpropertyns, CallInfo::typeSig6(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropertyns")},
- { (uintptr_t)&Stubs::do_abc_findpropertynsx, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropertynsx")},
+ { (uintptr_t)&Stubs::do_abc_findpropstrict, CallInfo::typeSig6(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrict")},
+ { (uintptr_t)&Stubs::do_abc_findpropstrictx, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrictx")},
+ { (uintptr_t)&Stubs::do_abc_findpropstrictns, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrictns")},
+ { (uintptr_t)&Stubs::do_abc_findpropstrictnsx, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropstrictnsx")},
+ { (uintptr_t)&Stubs::do_abc_findproperty, CallInfo::typeSig6(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findproperty")},
+ { (uintptr_t)&Stubs::do_abc_findpropertyx, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropertyx")},
+ { (uintptr_t)&Stubs::do_abc_findpropertyns, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropertyns")},
+ { (uintptr_t)&Stubs::do_abc_findpropertynsx, CallInfo::typeSig7(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_findpropertynsx")},
{ (uintptr_t)&Stubs::do_newclass, CallInfo::typeSig5(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "newclass")},
{ (uintptr_t)&Stubs::do_newfunction, CallInfo::typeSig4(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "newfunction")},
{ (uintptr_t)&Stubs::do_abc_getsuper, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_getsuper")},
{ (uintptr_t)&Stubs::do_abc_getsuperx, CallInfo::typeSig4(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_getsuperx")},
{ (uintptr_t)&Stubs::do_abc_getsuperns, CallInfo::typeSig4(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_getsuperns")},
{ (uintptr_t)&Stubs::do_abc_getsupernsx, CallInfo::typeSig5(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_getsupernsx")},
{ (uintptr_t)&Stubs::do_abc_getdescendants, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_getdescendants")},
{ (uintptr_t)&Stubs::do_abc_getdescendantsx, CallInfo::typeSig4(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_getdescendantsx")},
@@ -135,29 +137,32 @@ const nanojit::CallInfo LirEmitter::lir_
{ (uintptr_t)&Stubs::do_slottype, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "slottype")},
{ (uintptr_t)&Stubs::do_getouterscope, CallInfo::typeSig3(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "getouterscope")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "safepoint")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "setlocal")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "newstate")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "deopt_safepoint")},
{ (uintptr_t)&Stubs::do_deopt_finish, CallInfo::typeSig1(ARGTYPE_V, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "deopt_finish")},
{ 0, 0, ABI_CDECL, 0, ACCSET_NONE verbose_only(, "deopt_finishcall")},
+ { (uintptr_t)&Stubs::do_debugline, CallInfo::typeSig2(ARGTYPE_V, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "debugline")},
+ { (uintptr_t)&Stubs::do_debugfile, CallInfo::typeSig2(ARGTYPE_V, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "debugfile")},
{ (uintptr_t)&Stubs::do_string2atom, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "string2atom")},
{ (uintptr_t)&Stubs::do_double2atom, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_D), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "double2atom")},
{ (uintptr_t)&Stubs::do_int2atom, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "int2atom")},
{ (uintptr_t)&Stubs::do_uint2atom, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_UI), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "uint2atom")},
{ (uintptr_t)&Stubs::do_scriptobject2atom, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "scriptobject2atom")},
{ (uintptr_t)&Stubs::do_bool2atom, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "bool2atom")},
{ (uintptr_t)&Stubs::do_ns2atom, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "ns2atom")},
{ (uintptr_t)&Stubs::do_atom2bool, CallInfo::typeSig2(ARGTYPE_I, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "atom2bool")},
{ (uintptr_t)&Stubs::do_atom2double, CallInfo::typeSig2(ARGTYPE_D, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "atom2double")},
{ (uintptr_t)&Stubs::do_atom2string, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "atom2string")},
{ (uintptr_t)&Stubs::do_atom2int, CallInfo::typeSig2(ARGTYPE_I, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "atom2int")},
{ (uintptr_t)&Stubs::do_atom2uint, CallInfo::typeSig2(ARGTYPE_UI, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "atom2uint")},
{ (uintptr_t)&Stubs::do_atom2scriptobject, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "atom2scriptobject")},
+ { (uintptr_t)&Stubs::do_atom2ns, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "atom2ns")},
{ (uintptr_t)&Stubs::do_i2d, CallInfo::typeSig2(ARGTYPE_D, ARGTYPE_P, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "i2d")},
{ (uintptr_t)&Stubs::do_u2d, CallInfo::typeSig2(ARGTYPE_D, ARGTYPE_P, ARGTYPE_UI), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "u2d")},
{ (uintptr_t)&Stubs::do_d2i, CallInfo::typeSig2(ARGTYPE_I, ARGTYPE_P, ARGTYPE_D), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "d2i")},
{ (uintptr_t)&Stubs::do_d2u, CallInfo::typeSig2(ARGTYPE_UI, ARGTYPE_P, ARGTYPE_D), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "d2u")},
{ (uintptr_t)&Stubs::do_toslot, CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "toslot")},
{ (uintptr_t)&Stubs::do_toprimitive, CallInfo::typeSig2(ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "toprimitive")},
{ (uintptr_t)&Stubs::do_eqi, CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "eqi")},
{ (uintptr_t)&Stubs::do_lti, CallInfo::typeSig3(ARGTYPE_I, ARGTYPE_P, ARGTYPE_I, ARGTYPE_I), ABI_CDECL, 1, ACCSET_NONE verbose_only(, "lti")},
@@ -244,16 +249,17 @@ const nanojit::CallInfo LirEmitter::lir_
{ (uintptr_t)&Stubs::do_abc_initpropx, CallInfo::typeSig5(ARGTYPE_V, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_initpropx")},
{ (uintptr_t)&Stubs::do_abc_initpropns, CallInfo::typeSig5(ARGTYPE_V, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_initpropns")},
{ (uintptr_t)&Stubs::do_abc_initpropnsx, CallInfo::typeSig6(ARGTYPE_V, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P, ARGTYPE_P), ABI_CDECL, 0, ACCSET_ALL verbose_only(, "abc_initpropnsx")},
};
const int LirEmitter::stub_fixc[] = {
-1, // start
-1, // template
+ -1, // catchblock
0, // return
-1, // throw
0, // goto
-1, // label
1, // if
1, // switch
-1, // arm
-1, // const
@@ -280,16 +286,17 @@ const int LirEmitter::stub_fixc[] = {
-1, // loadenv_boolean
-1, // loadenv_number
-1, // loadenv_string
-1, // loadenv_interface
-1, // loadenv
-1, // loadenv_atom
-1, // loadinitenv
-1, // loadsuperinitenv
+ -1, // loadenv_env
0, // newobject
0, // newarray
0, // applytype
-1, // newinstance
-1, // abc_convert_s
-1, // abc_esc_xelem
-1, // abc_esc_xattr
-1, // abc_typeof
@@ -330,23 +337,23 @@ const int LirEmitter::stub_fixc[] = {
-1, // rshi
-1, // rshui
-1, // noti
-1, // negi
-1, // negd
-1, // not
-1, // newactivation
-1, // abc_finddef
- 2, // abc_findpropstrict
- 3, // abc_findpropstrictx
- 3, // abc_findpropstrictns
+ 3, // abc_findpropstrict
+ 4, // abc_findpropstrictx
+ 4, // abc_findpropstrictns
4, // abc_findpropstrictnsx
- 2, // abc_findproperty
- 3, // abc_findpropertyx
- 3, // abc_findpropertyns
+ 3, // abc_findproperty
+ 4, // abc_findpropertyx
+ 4, // abc_findpropertyns
4, // abc_findpropertynsx
2, // newclass
1, // newfunction
-1, // abc_getsuper
-1, // abc_getsuperx
-1, // abc_getsuperns
-1, // abc_getsupernsx
-1, // abc_getdescendants
@@ -372,35 +379,38 @@ const int LirEmitter::stub_fixc[] = {
1, // callstatic
1, // callmethod
1, // callinterface
-1, // newcatch
-1, // setslot
-1, // getslot
-1, // slottype
-1, // getouterscope
- -1, // safepoint
+ 0, // safepoint
-1, // setlocal
-1, // newstate
0, // deopt_safepoint
-1, // deopt_finish
-1, // deopt_finishcall
+ -1, // debugline
+ -1, // debugfile
-1, // string2atom
-1, // double2atom
-1, // int2atom
-1, // uint2atom
-1, // scriptobject2atom
-1, // bool2atom
-1, // ns2atom
-1, // atom2bool
-1, // atom2double
-1, // atom2string
-1, // atom2int
-1, // atom2uint
-1, // atom2scriptobject
+ -1, // atom2ns
-1, // i2d
-1, // u2d
-1, // d2i
-1, // d2u
-1, // toslot
-1, // toprimitive
-1, // eqi
-1, // lti
--- a/halfmoon/generated/Stub_protos.hh
+++ b/halfmoon/generated/Stub_protos.hh
@@ -1,16 +1,16 @@
///
/// generated by templates.py -- do not edit
///
namespace halfmoon {
using namespace avmplus;
struct Stubs {
- static const int stub_count = 240;
+ static const int stub_count = 245;
// throw: (Effect, Atom) -> ()
static void do_throw(MethodFrame*, Atom);
// coerce: (Effect, Traits, Atom) -> (Effect, Atom)
static Atom do_coerce(MethodFrame*, Traits*, Atom);
// cast: (Effect, Traits, Atom) -> (Effect, ScriptObject)
@@ -86,16 +86,19 @@ struct Stubs {
static MethodEnv* do_loadenv_atom(MethodFrame*, int, Atom);
// loadinitenv: ScriptObject~ -> Env
static MethodEnv* do_loadinitenv(MethodFrame*, ScriptObject*);
// loadsuperinitenv: Env -> Env
static MethodEnv* do_loadsuperinitenv(MethodFrame*, MethodEnv*);
+ // loadenv_env: (Ord, Env) -> Env
+ static MethodEnv* do_loadenv_env(MethodFrame*, int, MethodEnv*);
+
// newobject: (Effect, Atom) -> (Effect, ScriptObject~)
static ScriptObject* do_newobject(MethodFrame*, int, Atom*);
// newarray: (Effect, Atom) -> (Effect, Array~)
static ArrayObject* do_newarray(MethodFrame*, int, Atom*);
// applytype: (Effect, Atom) -> (Effect, Atom)
static Atom do_applytype(MethodFrame*, int, Atom*);
@@ -215,39 +218,39 @@ struct Stubs {
static BoolKind do_not(MethodFrame*, BoolKind);
// newactivation: (Effect, Env) -> (Effect, ScriptObject~)
static ScriptObject* do_newactivation(MethodFrame*, MethodEnv*);
// abc_finddef: (Effect, Name, Env) -> (Effect, ScriptObject~)
static ScriptObject* do_abc_finddef(MethodFrame*, const Multiname*, MethodEnv*);
- // abc_findpropstrict: (Effect, Name, Env, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findpropstrict(MethodFrame*, const Multiname*, MethodEnv*, int, Atom*);
+ // abc_findpropstrict: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findpropstrict(MethodFrame*, const Multiname*, MethodEnv*, int, int, Atom*);
- // abc_findpropstrictx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findpropstrictx(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*);
+ // abc_findpropstrictx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findpropstrictx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*);
- // abc_findpropstrictns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findpropstrictns(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*);
+ // abc_findpropstrictns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findpropstrictns(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*);
- // abc_findpropstrictnsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findpropstrictnsx(MethodFrame*, const Multiname*, MethodEnv*, Atom, Atom, int, Atom*);
+ // abc_findpropstrictnsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findpropstrictnsx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*);
- // abc_findproperty: (Effect, Name, Env, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findproperty(MethodFrame*, const Multiname*, MethodEnv*, int, Atom*);
+ // abc_findproperty: (Effect, Name, Env, Ord, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findproperty(MethodFrame*, const Multiname*, MethodEnv*, int, int, Atom*);
- // abc_findpropertyx: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findpropertyx(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*);
+ // abc_findpropertyx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findpropertyx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*);
- // abc_findpropertyns: (Effect, Name, Env, Atom, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findpropertyns(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*);
+ // abc_findpropertyns: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findpropertyns(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*);
- // abc_findpropertynsx: (Effect, Name, Env, Atom, Atom, Atom~) -> (Effect, Atom~)
- static Atom do_abc_findpropertynsx(MethodFrame*, const Multiname*, MethodEnv*, Atom, Atom, int, Atom*);
+ // abc_findpropertynsx: (Effect, Name, Env, Ord, Atom, Atom~) -> (Effect, Atom~)
+ static Atom do_abc_findpropertynsx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*);
// newclass: (Effect, Traits~, Class, Atom~) -> (Effect, Class~)
static ClassClosure* do_newclass(MethodFrame*, Traits*, ClassClosure*, int, Atom*);
// newfunction: (Effect, Method, Atom~) -> (Effect, Function~)
static ClassClosure* do_newfunction(MethodFrame*, MethodInfo*, int, Atom*);
// abc_getsuper: (Effect, Name, Atom~) -> (Effect, Atom)
@@ -317,28 +320,34 @@ struct Stubs {
static Atom do_abc_callsuperx(MethodFrame*, const Multiname*, Atom, int, Atom*);
// abc_callsuperns: (Effect, Name, Atom, Atom~, Atom) -> (Effect, Atom)
static Atom do_abc_callsuperns(MethodFrame*, const Multiname*, Atom, int, Atom*);
// abc_callsupernsx: (Effect, Name, Atom, Atom, Atom~, Atom) -> (Effect, Atom)
static Atom do_abc_callsupernsx(MethodFrame*, const Multiname*, Atom, Atom, int, Atom*);
- // newcatch: (Effect, Traits~) -> (Effect, ScriptObject~)
- static ScriptObject* do_newcatch(MethodFrame*, Traits*);
+ // newcatch: (Effect, Traits~) -> (Effect, Atom~)
+ static Atom do_newcatch(MethodFrame*, Traits*);
// slottype: (ScriptObject~, Ord) -> Traits
static Traits* do_slottype(MethodFrame*, ScriptObject*, int);
// getouterscope: (Ord, Env) -> Atom~
static Atom do_getouterscope(MethodFrame*, int, MethodEnv*);
// deopt_finish: Effect -> Effect
static void do_deopt_finish(MethodFrame*);
+ // debugline: (Effect, Int) -> Effect
+ static void do_debugline(MethodFrame*, int32_t);
+
+ // debugfile: (Effect, String) -> Effect
+ static void do_debugfile(MethodFrame*, String*);
+
// string2atom: String -> Atom
static Atom do_string2atom(MethodFrame*, String*);
// double2atom: Number -> Atom~
static Atom do_double2atom(MethodFrame*, double);
// int2atom: Int -> Atom~
static Atom do_int2atom(MethodFrame*, int32_t);
@@ -368,16 +377,19 @@ struct Stubs {
static int32_t do_atom2int(MethodFrame*, Atom);
// atom2uint: Atom -> Uint
static uint32_t do_atom2uint(MethodFrame*, Atom);
// atom2scriptobject: Atom -> ScriptObject
static ScriptObject* do_atom2scriptobject(MethodFrame*, Atom);
+ // atom2ns: Atom -> Namespace
+ static Namespace* do_atom2ns(MethodFrame*, Atom);
+
// i2d: Int -> Number
static double do_i2d(MethodFrame*, int32_t);
// u2d: Uint -> Number
static double do_u2d(MethodFrame*, uint32_t);
// d2i: Number -> Int
static int32_t do_d2i(MethodFrame*, double);
@@ -672,16 +684,17 @@ struct Stubs {
MethodEnv* Stubs::do_loadenv_boolean(MethodFrame*, int, BoolKind) { assert(false && "loadenv_boolean not implemented"); return 0; }
MethodEnv* Stubs::do_loadenv_number(MethodFrame*, int, double) { assert(false && "loadenv_number not implemented"); return 0; }
MethodEnv* Stubs::do_loadenv_string(MethodFrame*, int, String*) { assert(false && "loadenv_string not implemented"); return 0; }
MethodEnv* Stubs::do_loadenv_interface(MethodFrame*, MethodInfo*, ScriptObject*) { assert(false && "loadenv_interface not implemented"); return 0; }
MethodEnv* Stubs::do_loadenv(MethodFrame*, int, ScriptObject*) { assert(false && "loadenv not implemented"); return 0; }
MethodEnv* Stubs::do_loadenv_atom(MethodFrame*, int, Atom) { assert(false && "loadenv_atom not implemented"); return 0; }
MethodEnv* Stubs::do_loadinitenv(MethodFrame*, ScriptObject*) { assert(false && "loadinitenv not implemented"); return 0; }
MethodEnv* Stubs::do_loadsuperinitenv(MethodFrame*, MethodEnv*) { assert(false && "loadsuperinitenv not implemented"); return 0; }
+ MethodEnv* Stubs::do_loadenv_env(MethodFrame*, int, MethodEnv*) { assert(false && "loadenv_env not implemented"); return 0; }
ScriptObject* Stubs::do_newobject(MethodFrame*, int, Atom*) { assert(false && "newobject not implemented"); return 0; }
ArrayObject* Stubs::do_newarray(MethodFrame*, int, Atom*) { assert(false && "newarray not implemented"); return 0; }
Atom Stubs::do_applytype(MethodFrame*, int, Atom*) { assert(false && "applytype not implemented"); return 0; }
ScriptObject* Stubs::do_newinstance(MethodFrame*, ClassClosure*) { assert(false && "newinstance not implemented"); return 0; }
String* Stubs::do_abc_convert_s(MethodFrame*, Atom) { assert(false && "abc_convert_s not implemented"); return 0; }
String* Stubs::do_abc_esc_xelem(MethodFrame*, Atom) { assert(false && "abc_esc_xelem not implemented"); return 0; }
String* Stubs::do_abc_esc_xattr(MethodFrame*, Atom) { assert(false && "abc_esc_xattr not implemented"); return 0; }
String* Stubs::do_abc_typeof(MethodFrame*, Atom) { assert(false && "abc_typeof not implemented"); return 0; }
@@ -715,24 +728,24 @@ struct Stubs {
int32_t Stubs::do_rshi(MethodFrame*, int32_t, int32_t) { assert(false && "rshi not implemented"); return 0; }
uint32_t Stubs::do_rshui(MethodFrame*, int32_t, int32_t) { assert(false && "rshui not implemented"); return 0; }
int32_t Stubs::do_noti(MethodFrame*, int32_t) { assert(false && "noti not implemented"); return 0; }
int32_t Stubs::do_negi(MethodFrame*, int32_t) { assert(false && "negi not implemented"); return 0; }
double Stubs::do_negd(MethodFrame*, double) { assert(false && "negd not implemented"); return 0; }
BoolKind Stubs::do_not(MethodFrame*, BoolKind) { assert(false && "not not implemented"); return 0; }
ScriptObject* Stubs::do_newactivation(MethodFrame*, MethodEnv*) { assert(false && "newactivation not implemented"); return 0; }
ScriptObject* Stubs::do_abc_finddef(MethodFrame*, const Multiname*, MethodEnv*) { assert(false && "abc_finddef not implemented"); return 0; }
- Atom Stubs::do_abc_findpropstrict(MethodFrame*, const Multiname*, MethodEnv*, int, Atom*) { assert(false && "abc_findpropstrict not implemented"); return 0; }
- Atom Stubs::do_abc_findpropstrictx(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*) { assert(false && "abc_findpropstrictx not implemented"); return 0; }
- Atom Stubs::do_abc_findpropstrictns(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*) { assert(false && "abc_findpropstrictns not implemented"); return 0; }
- Atom Stubs::do_abc_findpropstrictnsx(MethodFrame*, const Multiname*, MethodEnv*, Atom, Atom, int, Atom*) { assert(false && "abc_findpropstrictnsx not implemented"); return 0; }
- Atom Stubs::do_abc_findproperty(MethodFrame*, const Multiname*, MethodEnv*, int, Atom*) { assert(false && "abc_findproperty not implemented"); return 0; }
- Atom Stubs::do_abc_findpropertyx(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*) { assert(false && "abc_findpropertyx not implemented"); return 0; }
- Atom Stubs::do_abc_findpropertyns(MethodFrame*, const Multiname*, MethodEnv*, Atom, int, Atom*) { assert(false && "abc_findpropertyns not implemented"); return 0; }
- Atom Stubs::do_abc_findpropertynsx(MethodFrame*, const Multiname*, MethodEnv*, Atom, Atom, int, Atom*) { assert(false && "abc_findpropertynsx not implemented"); return 0; }
+ Atom Stubs::do_abc_findpropstrict(MethodFrame*, const Multiname*, MethodEnv*, int, int, Atom*) { assert(false && "abc_findpropstrict not implemented"); return 0; }
+ Atom Stubs::do_abc_findpropstrictx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*) { assert(false && "abc_findpropstrictx not implemented"); return 0; }
+ Atom Stubs::do_abc_findpropstrictns(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*) { assert(false && "abc_findpropstrictns not implemented"); return 0; }
+ Atom Stubs::do_abc_findpropstrictnsx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*) { assert(false && "abc_findpropstrictnsx not implemented"); return 0; }
+ Atom Stubs::do_abc_findproperty(MethodFrame*, const Multiname*, MethodEnv*, int, int, Atom*) { assert(false && "abc_findproperty not implemented"); return 0; }
+ Atom Stubs::do_abc_findpropertyx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*) { assert(false && "abc_findpropertyx not implemented"); return 0; }
+ Atom Stubs::do_abc_findpropertyns(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*) { assert(false && "abc_findpropertyns not implemented"); return 0; }
+ Atom Stubs::do_abc_findpropertynsx(MethodFrame*, const Multiname*, MethodEnv*, int, Atom, int, Atom*) { assert(false && "abc_findpropertynsx not implemented"); return 0; }
ClassClosure* Stubs::do_newclass(MethodFrame*, Traits*, ClassClosure*, int, Atom*) { assert(false && "newclass not implemented"); return 0; }
ClassClosure* Stubs::do_newfunction(MethodFrame*, MethodInfo*, int, Atom*) { assert(false && "newfunction not implemented"); return 0; }
Atom Stubs::do_abc_getsuper(MethodFrame*, const Multiname*, Atom) { assert(false && "abc_getsuper not implemented"); return 0; }
Atom Stubs::do_abc_getsuperx(MethodFrame*, const Multiname*, Atom, Atom) { assert(false && "abc_getsuperx not implemented"); return 0; }
Atom Stubs::do_abc_getsuperns(MethodFrame*, const Multiname*, Atom, Atom) { assert(false && "abc_getsuperns not implemented"); return 0; }
Atom Stubs::do_abc_getsupernsx(MethodFrame*, const Multiname*, Atom, Atom, Atom) { assert(false && "abc_getsupernsx not implemented"); return 0; }
Atom Stubs::do_abc_getdescendants(MethodFrame*, const Multiname*, Atom) { assert(false && "abc_getdescendants not implemented"); return 0; }
Atom Stubs::do_abc_getdescendantsx(MethodFrame*, const Multiname*, Atom, Atom) { assert(false && "abc_getdescendantsx not implemented"); return 0; }
@@ -749,33 +762,36 @@ struct Stubs {
Atom Stubs::do_abc_constructprop(MethodFrame*, const Multiname*, int, Atom*) { assert(false && "abc_constructprop not implemented"); return 0; }
Atom Stubs::do_abc_constructpropx(MethodFrame*, const Multiname*, Atom, int, Atom*) { assert(false && "abc_constructpropx not implemented"); return 0; }
Atom Stubs::do_abc_constructpropns(MethodFrame*, const Multiname*, Atom, int, Atom*) { assert(false && "abc_constructpropns not implemented"); return 0; }
Atom Stubs::do_abc_constructpropnsx(MethodFrame*, const Multiname*, Atom, Atom, int, Atom*) { assert(false && "abc_constructpropnsx not implemented"); return 0; }
Atom Stubs::do_abc_callsuper(MethodFrame*, const Multiname*, int, Atom*) { assert(false && "abc_callsuper not implemented"); return 0; }
Atom Stubs::do_abc_callsuperx(MethodFrame*, const Multiname*, Atom, int, Atom*) { assert(false && "abc_callsuperx not implemented"); return 0; }
Atom Stubs::do_abc_callsuperns(MethodFrame*, const Multiname*, Atom, int, Atom*) { assert(false && "abc_callsuperns not implemented"); return 0; }
Atom Stubs::do_abc_callsupernsx(MethodFrame*, const Multiname*, Atom, Atom, int, Atom*) { assert(false && "abc_callsupernsx not implemented"); return 0; }
- ScriptObject* Stubs::do_newcatch(MethodFrame*, Traits*) { assert(false && "newcatch not implemented"); return 0; }
+ Atom Stubs::do_newcatch(MethodFrame*, Traits*) { assert(false && "newcatch not implemented"); return 0; }
Traits* Stubs::do_slottype(MethodFrame*, ScriptObject*, int) { assert(false && "slottype not implemented"); return 0; }
Atom Stubs::do_getouterscope(MethodFrame*, int, MethodEnv*) { assert(false && "getouterscope not implemented"); return 0; }
void Stubs::do_deopt_finish(MethodFrame*) { assert(false && "deopt_finish not implemented"); }
+ void Stubs::do_debugline(MethodFrame*, int32_t) { assert(false && "debugline not implemented"); }
+ void Stubs::do_debugfile(MethodFrame*, String*) { assert(false && "debugfile not implemented"); }
Atom Stubs::do_string2atom(MethodFrame*, String*) { assert(false && "string2atom not implemented"); return 0; }
Atom Stubs::do_double2atom(MethodFrame*, double) { assert(false && "double2atom not implemented"); return 0; }
Atom Stubs::do_int2atom(MethodFrame*, int32_t) { assert(false && "int2atom not implemented"); return 0; }
Atom Stubs::do_uint2atom(MethodFrame*, uint32_t) { assert(false && "uint2atom not implemented"); return 0; }
Atom Stubs::do_scriptobject2atom(MethodFrame*, ScriptObject*) { assert(false && "scriptobject2atom not implemented"); return 0; }
Atom Stubs::do_bool2atom(MethodFrame*, BoolKind) { assert(false && "bool2atom not implemented"); return 0; }
Atom Stubs::do_ns2atom(MethodFrame*, Namespace*) { assert(false && "ns2atom not implemented"); return 0; }
BoolKind Stubs::do_atom2bool(MethodFrame*, Atom) { assert(false && "atom2bool not implemented"); return 0; }
double Stubs::do_atom2double(MethodFrame*, Atom) { assert(false && "atom2double not implemented"); return 0; }
String* Stubs::do_atom2string(MethodFrame*, Atom) { assert(false && "atom2string not implemented"); return 0; }
int32_t Stubs::do_atom2int(MethodFrame*, Atom) { assert(false && "atom2int not implemented"); return 0; }
uint32_t Stubs::do_atom2uint(MethodFrame*, Atom) { assert(false && "atom2uint not implemented"); return 0; }
ScriptObject* Stubs::do_atom2scriptobject(MethodFrame*, Atom) { assert(false && "atom2scriptobject not implemented"); return 0; }
+ Namespace* Stubs::do_atom2ns(MethodFrame*, Atom) { assert(false && "atom2ns not implemented"); return 0; }
double Stubs::do_i2d(MethodFrame*, int32_t) { assert(false && "i2d not implemented"); return 0; }
double Stubs::do_u2d(MethodFrame*, uint32_t) { assert(false && "u2d not implemented"); return 0; }
int32_t Stubs::do_d2i(MethodFrame*, double) { assert(false && "d2i not implemented"); return 0; }
uint32_t Stubs::do_d2u(MethodFrame*, double) { assert(false && "d2u not implemented"); return 0; }
int Stubs::do_toslot(MethodFrame*, ScriptObject*, const Multiname*) { assert(false && "toslot not implemented"); return 0; }
Atom Stubs::do_toprimitive(MethodFrame*, Atom) { assert(false && "toprimitive not implemented"); return 0; }
BoolKind Stubs::do_eqi(MethodFrame*, int32_t, int32_t) { assert(false && "eqi not implemented"); return 0; }
BoolKind Stubs::do_lti(MethodFrame*, int32_t, int32_t) { assert(false && "lti not implemented"); return 0; }
--- a/halfmoon/halfmoon.h
+++ b/halfmoon/halfmoon.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
using avmplus::AbcEnv;
using avmplus::CodegenDriver;
using avmplus::CodeWriter;
@@ -64,17 +64,17 @@ public:
void writeCheckNull(const FrameState* state, uint32_t index);
void writeCoerce(const FrameState* state, uint32_t index, Traits *type);
void writeEpilogue(const FrameState* state);
void writeBlockStart(const FrameState* state);
private:
void analyze(AbcOpcode abcop, const uint8_t* pc, const FrameState*);
void finishBlock(const uint8_t* nextpc);
- void newBlock(const uint8_t* pc);
+ void newBlock(const uint8_t* pc, const FrameState* state);
void startBlock(const FrameState*);
public:
InstrGraph *ir_; //TODO: matz_inline_experiment review this comment. (stash graph for inlined callees here)
//maybe put callers context here? Then compile callee could set it when compiling for inliner. matz
private:
Allocator alloc_;
MethodInfo* method_;
@@ -97,11 +97,12 @@ private:
///
/// For the purposes of this analyzer, A loop is formed by an edge from B2->B1
/// whenever B2 comes after B1 in linear order, ignoring control-flow paths.
/// An instruction is "in the loop" if its between B1.first_ins and B2.last_ins.
///
/// Returns true on success. Failures print a diagnostic and assert (debug),
/// or return false (release).
///
-bool checkLir(Fragment*);
+using avmplus::AvmLogControl;
+bool checkLir(Fragment*, AvmLogControl* logc);
-} // namespace avmplus
+} // namespace halfmoon
--- a/halfmoon/hm-abcbuilder.cpp
+++ b/halfmoon/hm-abcbuilder.cpp
@@ -18,33 +18,37 @@ using avmplus::TraitsBindings;
using profiler::MethodProfile;
using profiler::ProfiledState;
using profiler::RecordedType;
// OP_end means we fell off the end of a label.
static const AbcOpcode OP_end = AbcOpcode(-1);
-AbcBuilder::AbcBuilder(MethodInfo* method, AbcGraph* abc, InstrFactory* factory, Toplevel* toplevel, ProfiledInformation* profiled_information)
+ AbcBuilder::AbcBuilder(MethodInfo* method, AbcGraph* abc, InstrFactory* factory, Toplevel* toplevel, ProfiledInformation* profiled_information,
+ bool has_reachable_exceptions)
: alloc_(factory->alloc())
, alloc0_(factory->alloc())
, method_(method)
, sig_(method->getMethodSignature())
, abc_(abc)
, pool_(method->pool())
, console_(pool_->core->console)
, lattice_(factory->lattice())
, scope_base_(sig_->local_count())
, stack_base_(scope_base_ + sig_->max_scope())
, framesize_(stack_base_ + sig_->max_stack())
-, num_vars_(framesize_ + 2)
+, num_vars_(framesize_ + 2 + (has_reachable_exceptions ? framesize_ : 0))
, effect_pos_(framesize_)
, state_pos_(framesize_ + 1)
+, setlocal_pos_(has_reachable_exceptions ? (framesize_ + 2) : 0)
, frame_(new (alloc0_) Def*[num_vars_])
, code_pos_(sig_->abc_code_start())
+, pc_(NULL)
+, has_reachable_exceptions_(has_reachable_exceptions)
, return_label_(0)
, throw_label_(0)
, factory_(*factory)
, ir_(factory->createGraph())
, builder_(ir_, factory)
, profiled_info_(profiled_information)
, toplevel_(toplevel)
{
@@ -112,54 +116,107 @@ AbcBuilder::AbcBuilder(MethodInfo* metho
}
AbcBuilder::~AbcBuilder() {
}
InstrGraph* AbcBuilder::visitBlocks(Seq<AbcBlock*> *list) {
// Build the instr graph by visiting ABC blocks in reverse postorder.
buildStart();
- for (SeqRange<AbcBlock*> b(list); !b.empty(); b.popFront())
- visitBlock(b.front());
+
+ for (SeqRange<AbcBlock*> b(list); !b.empty(); b.popFront()) {
+ AbcBlock* abc_block = b.front();
+
+ // Exception blocks shouldn't be normally reachable
+ AvmAssert(abc_block->label == NULL || !pcIsHandler(abc_block->start));
+
+ // Lazily fill in the exception handler blocks before parsing them
+ if (abc_block->label == NULL && pcIsHandler(abc_block->start)) {
+ AvmAssert(has_reachable_exceptions_);
+ ensureCatchBlockLabel(abc_block);
+ }
+ visitBlock(abc_block);
+ }
+
+ // In the current world of setjmp/longjmp style exception handling
+ // it's sufficient to link all the exception blocks off the start
+ // block. Later if we have more precise handling of exception
+ // blocks it might be beneficial to directly track which blocks
+ // might have exception handlers. So for now this code is disabled
+#if 0
+ for (SeqRange<AbcBlock*> b(list); !b.empty(); b.popFront()) {
+ AbcBlock* abc_block = b.front();
+ if (abc_block->label == NULL)
+ continue;
+ for (int c = 0; c < abc_block->max_catch_blocks; c++) {
+ if (abc_block->catch_blocks[c] != NULL) {
+ BlockEndInstr* end = InstrGraph::blockEnd(abc_block->label);
+ if (end == NULL) continue;
+ CatchBlockInstr* handler = (CatchBlockInstr*)abc_block->catch_blocks[c]->label;
+ linkExceptionEdge(abc_block->label, handler);
+ }
+ }
+ }
+#endif
+
finish();
+
+ if (enable_printir)
+ listCfg(console_, ir_);
+
assert(checkPruned(ir_) && checkSSA(ir_));
Context cxt(method_);
propagateTypes(ir_);
removeDeadCode(&cxt, ir_);
return ir_;
}
void AbcBuilder::visitBlock(AbcBlock* abc_block) {
if (!abc_block->label)
return;
startBlock(abc_block);
+
+ bool in_try = false;
+ for (int c = 0; c < abc_block->max_catch_blocks; c++) {
+ if (abc_block->catch_blocks[c] != NULL) {
+ in_try = true;
+ break;
+ }
+ }
+
+ if (!in_try && has_reachable_exceptions_) {
+ safepointStmt(abc_block->start);
+ }
+
const uint8_t* end = abc_block->end;
for (const uint8_t* pc = abc_block->start;;) {
uint32_t imm30 = 0, imm30b = 0;
int imm8 = 0, imm24 = 0;
const uint8_t* nextpc = pc;
AbcOpcode abcop = readInstr(nextpc, end, imm30, imm30b, imm24, imm8);
if (abcop == OP_end) {
jumpStmt(); // Add the fall-through edge.
break;
}
// TODO: could we restrict to just this:
// (abc_block->in_try && opcodeInfo[abcop].canThrow)
- if (needAbcState())
+ // if (needAbcState())
+ if (in_try && opcodeInfo[abcop].canThrow)
safepointStmt(pc);
// TODO: This is preposterous without a filter for catchable
// canThrow instructions. We must also safepoint targets of
// backward branches. Avoid safepointing calls.
//emitThrowSafepoint(pc);
visitInstr(pc, abcop, imm30, imm30b, imm8);
assert(checkFrame(frame_, stackp_, scopep_));
if (isBlockEnd(abcop))
break;
- pc = nextpc;
+ pc_ = pc = nextpc;
}
+ pc_ = NULL;
}
bool AbcBuilder::shouldSpeculate() {
bool speculate = enable_profiler > 0;
profiler::PROFILING_STATE state =
JitManager::getProfile(method_)->current_profiler_state_;
// We may deopt, so we should stop speculating
@@ -273,16 +330,17 @@ void AbcBuilder::buildStart() {
builder_.addInstr(newstate);
if (method_->isConstructor())
emitInitializers(start->data_param(1));
set_state(newstate->value());
scopep_ = scope_base_ - 1;
stackp_ = stack_base_ - 1;
+ withbase_ = -1;
int local_id = 0;
for (int n = start->data_param_count() - 1; local_id < n; ++local_id) {
Def* local_def = start->data_param(local_id + 1);
setLocal(local_id, local_def);
}
for (; local_id < scope_base_; ++local_id) {
@@ -299,41 +357,59 @@ void AbcBuilder::buildStart() {
void AbcBuilder::finish() {
if (return_label_)
ir_->end = cast<StopInstr>(ir_->blockEnd(return_label_));
if (throw_label_)
ir_->exit = cast<StopInstr>(ir_->blockEnd(throw_label_));
}
void AbcBuilder::safepointStmt(const uint8_t* pc) {
- assert (needAbcState());
+ // assert (needAbcState());
+ Def** vars = new (alloc0_) Def*[num_vars_];
+ int argc = 0;
+
+ for (int i = 0, n = scope_base_; i < n; i++) {
+ vars[argc++] = frame_[setlocal_pos_ + i];
+ }
+
+ // scopep_ starts at scope_base - 1
+ for (int i = scope_base_; i <= scopep_; i++) {
+ vars[argc++] = frame_[setlocal_pos_ + i];
+ }
+
+ // stackp_ starts at stack_base - 1
+ for (int i = stack_base_; i <= stackp_; i++) {
+ vars[argc++] = frame_[setlocal_pos_ + i];
+ }
+ assert(argc < num_vars_);
+
Def* effect = this->effect();
- SafepointInstr* instr = factory_.newSafepointInstr(effect, state());
+ SafepointInstr* instr = factory_.newSafepointInstr(effect, argc, vars);
+ instr->vpc = int(pc - code_pos_);
+ instr->sp = stackp_;
+ instr->scopep = scopep_;
+
set_state(instr->state_out());
builder_.addInstr(instr);
set_effect(instr->effect_out());
-
- instr->vpc = int(pc - code_pos_);
- instr->sp = stackp_;
- instr->scopep = scopep_;
}
/// DEOPT
/// In the future, we will want to filter the frame slots
/// with liveness information. At present, we assume that
/// all locals and active scopes and operands are live.
DeoptSafepointInstr* AbcBuilder::emitBailoutSafepoint(const uint8_t* pc) {
if (!enable_deopt) return NULL; // DEOPT FIXME
// TODO: We could re-use a fixed-sized buffer,
// allocated once per compilation.
Def** vars = new (alloc0_) Def*[framesize_];
int argc = 0;
for (int i = 0, n = sig_->local_count(); i < n; i++) {
- vars[argc++] = getLocal(i);
+ vars[argc++] = getLocal(i);
}
// scopep_ starts at scope_base - 1
for (int i = scope_base_; i <= scopep_; i++) {
vars[argc++] = getLocal(i);
}
// stackp_ starts at stack_base - 1
@@ -362,17 +438,17 @@ DeoptSafepointInstr* AbcBuilder::emitBai
DeoptSafepointInstr* AbcBuilder::emitThrowSafepoint(const uint8_t* pc) {
if (!enable_deopt) return NULL; // DEOPT FIXME
// TODO: We could re-use a fixed-sized buffer,
// allocated once per compilation.
Def** vars = new (alloc0_) Def*[framesize_];
int argc = 0;
for (int i = 0, n = sig_->local_count(); i < n; i++) {
- vars[argc++] = getLocal(i);
+ vars[argc++] = getLocal(i);
}
// we do not need to preserve scopes or operands
Def* effect = this->effect();
DeoptSafepointInstr* instr =
factory_.newDeoptSafepointInstr(effect, argc, vars);
builder_.addInstr(instr);
@@ -451,17 +527,20 @@ void AbcBuilder::emitFinishCall(DeoptSaf
DeoptFinishCallInstr* instr = factory_.newDeoptFinishCallInstr(effect, arg);
builder_.addInstr(instr);
set_effect(instr->effect_out());
instr->safepoint = sfp;
}
}
void AbcBuilder::set_effect(Def* effect) {
- frame_[effect_pos_] = peephole(effect);
+ // Def* new_effect = peephole(effect);
+ // assert(effect == new_effect);
+ assert(kind(type(effect)) == kTypeEffect);
+ frame_[effect_pos_] = effect;
}
void AbcBuilder::set_state(Def* state) {
frame_[state_pos_] = state;
}
AbcOpcode peek(const uint8_t *pc, const uint8_t* end) {
return pc != end ? AbcOpcode(*pc) : OP_end;
@@ -481,18 +560,16 @@ AbcOpcode AbcBuilder::readInstr(const ui
AbcOpcode abcop = AbcOpcode(*pc);
AvmCore::readOperands(pc, imm30, imm24, imm30b, imm8);
if (pc == end || !enable_peephole)
return abcop;
switch (abcop) {
case OP_coerce_a:
case OP_nop:
case OP_label:
- case OP_debugline:
- case OP_debugfile:
goto again;
}
switch (abcop) {
case OP_pushundefined:
abcop = peek(pc, end);
if (abcop == OP_pop) {
++pc;
goto again;
@@ -732,40 +809,19 @@ bool AbcBuilder::isType(Def* val, Record
}
/// Stores the current ABC state by emitting setlocals for every value
/// in the abc stack frame.
/// scopep offset is the scope depth.
/// stackp_offset is the stack depth
/// we cannot rely on the stackp_ / scopep_ vars because defs may already have
/// been popped / pushed prior to calling savestate.
-void AbcBuilder::saveState(const uint8_t* pc,
- int scopep_offset, int stackp_offset) {
- for (int i = 0; i < this->sig_->local_count(); i++) {
- createSetLocalInstr(i, getLocal(i));
- }
-
- // scopep_ starts at scope_base - 1
- for (int i = scope_base_; i <= scopep_ + scopep_offset; i++) {
- createSetLocalInstr(i, getLocal(i));
- }
-
- // stackp_ starts at stack_base - 1
- for (int i = stack_base_; i <= stackp_ + stackp_offset; i++) {
- createSetLocalInstr(i, getLocal(i));
- }
-
- SafepointInstr* instr = factory_.newSafepointInstr(effect(), state());
- set_state(instr->state_out());
- builder_.addInstr(instr);
- set_effect(instr->effect_out());
-
- instr->vpc = int(pc - code_pos_);
- instr->sp = stackp_ + stackp_offset;
- instr->scopep = scopep_ + scopep_offset;
+void AbcBuilder::saveState(const uint8_t*,
+ int, int) {
+ assert(false);
}
bool AbcBuilder::hasType(Def* val, RecordedType recorded_type) {
return isType(val, recorded_type) || !isAny(type(val));
}
InstrKind AbcBuilder::getSpeculativeKind(RecordedType recorded_type) {
switch (recorded_type) {
@@ -835,22 +891,38 @@ void AbcBuilder::visitInstr(const uint8_
assert(false && "Unsupported opcode");
case OP_istype:
pushDef(binaryStmt(HR_abc_istype, traitsConst(imm30), popDef()));
break;
case OP_debug:
case OP_bkpt:
+ case OP_bkptline:
case OP_label:
case OP_nop:
case OP_timestamp:
- case OP_debugfile:
- case OP_debugline:
+ break;
+
+ case OP_debugfile: {
+ // Steal code from CodegenLIR and put it into the stubs for this
+ if (enable_trace) {
+ Def* filename = createConst(lattice_.makeStringConst(pool_, imm30));
+ debugInstr(HR_debugfile, filename);
+ }
break;
+ }
+ case OP_debugline: {
+ // Steal code from CodegenLIR and put it into the stubs for this
+ if (enable_trace) {
+ Def* lineno = createConst(lattice_.makeIntConst(imm30));
+ debugInstr(HR_debugline, lineno);
+ }
+ break;
+ }
case OP_jump:
jumpStmt();
break;
case OP_lookupswitch:
switchStmt(imm30b + 1, popDef());
break;
@@ -917,35 +989,36 @@ void AbcBuilder::visitInstr(const uint8_
pushDef(getLocal(imm30));
break;
case OP_setlocal:
setLocal(imm30, popDef());
break;
case OP_dup:
- temp1 = popDef();
- pushDef(temp1);
- pushDef(temp1);
+ pushDef(peekDef());
break;
case OP_pop:
popDef();
break;
case OP_popscope:
scopep_--;
+ if (withbase_ >= scopep_)
+ withbase_ = -1;
break;
case OP_pushwith:
- {
- // We don't support withbase in halfmoon cryil release.
- // TODO: fix after release
- assert(false && "need to track withbase");
- }
+ temp1 = nullCheck(popDef());
+ setLocal(++scopep_, temp1);
+ if (withbase_ == -1)
+ withbase_ = scopep_;
+ break;
+
case OP_pushscope:
temp1 = nullCheck(popDef());
setLocal(++scopep_, temp1);
break;
case OP_swap:
temp1 = popDef();
temp2 = popDef();
@@ -1027,16 +1100,21 @@ void AbcBuilder::visitInstr(const uint8_
pushDef(binaryExpr(HR_abc_astype, traitsConst(imm30), popDef()));
break;
case OP_coerce:
pushDef(coerceExpr(getNamedTraits(imm30), popDef()));
break;
case OP_instanceof:
+ temp2 = popDef(); // RHS is null checked by instanceof since it throws a different exception
+ temp1 = popDef();
+ pushDef(binaryStmt(kind_map_[abcop], temp1, temp2));
+ break;
+
case OP_istypelate:
case OP_astypelate:
case OP_in:
temp2 = nullCheck(popDef()); // RHS object cannot be null.
temp1 = popDef();
pushDef(binaryStmt(kind_map_[abcop], temp1, temp2));
break;
@@ -1275,27 +1353,33 @@ void AbcBuilder::visitInstr(const uint8_
break;
case OP_callsupervoid:
sfp = emitCallSafepoint(pc, imm30b);
callStmt(callsuper_kinds, imm30, imm30b);
emitFinishCall(sfp, NULL);
break;
- case OP_callstatic:
+ case OP_callstatic: {
// fixme: coerce args first, but this requires knowing obj type, which
// we don't have inside of loops.
sfp = emitCallSafepoint(pc, imm30b);
args = popArgs(imm30b);
+ MethodInfo* callee = pool_->getMethodInfo(imm30);
+ assert(callee->method_id() == (int)imm30);
+ temp1 = popDef();
+ temp1 = coerceArgs(temp1, args, imm30b, callee);
+ temp1 = nullCheck(temp1); // obj
temp2 = ordinalConst(imm30);
- temp1 = nullCheck(popDef()); // obj
+ temp2 = binaryExpr(HR_loadenv_env, temp2, env_param());
temp3 = callStmt2(HR_callstatic, temp2, temp1, args, imm30b);
emitFinishCall(sfp, temp3);
pushDef(temp3);
break;
+ }
case OP_call:
// stack: function thisarg args...
sfp = emitCallSafepoint(pc, imm30);
args = popArgs(imm30); // imm30 = extra_argc
temp2 = popDef(); // thisarg
temp1 = popDef(); // function
temp3 = callStmt2(HR_call, temp1, temp2, args, imm30);
@@ -1340,16 +1424,21 @@ void AbcBuilder::visitInstr(const uint8_
case OP_setglobalslot:
temp1 = getglobalscope();
temp2 = popDef();
setslotStmt(imm30 - 1, temp1, temp2);
break;
case OP_hasnext2:
pushDef(hasnext2Stmt(&frame_[imm30], &frame_[imm30b]));
+ if (has_reachable_exceptions_) {
+ // Make sure to update the state of the locals
+ setLocal(imm30, getLocal(imm30));
+ setLocal(imm30b, getLocal(imm30b));
+ }
break;
case OP_hasnext:
temp1 = popDef(); // index:int
temp2 = popDef(); // object
pushDef(binaryStmt(HR_abc_hasnext, temp2, temp1));
break;
@@ -1363,16 +1452,18 @@ void AbcBuilder::visitInstr(const uint8_
case OP_applytype:
// FIXME: abc format allows N type parameters as args, but Vector
// is the only class works, and it only allows 1 arg. There is a
// misplaced assert() in VectorClass::applyTypeArgs().
pushDef(naryStmt(HR_applytype, imm30 + 1));
break;
}
+ if (enable_framestate)
+ printFrameState();
}
Def* AbcBuilder::getglobalscope() {
return method_->declaringScope()->size == 0 ? getLocal(scope_base_) :
getouterscopeStmt(0);
}
/// Expand getlex into (fatgetprop name (findstrict name [scopes]))
@@ -1401,29 +1492,29 @@ Def* AbcBuilder::findStmt(const InstrKin
return getouterscopeStmt(abc_instr->index);
case OP_finddef:
assert(abc_instr->index == name_index);
return finddefStmt(name);
case OP_findpropglobal:
case OP_findpropglobalstrict:
case OP_findproperty:
case OP_findpropstrict:
- return naryStmt2(kinds[arity], name, env, scopes, scope_count);
+ return naryStmt3(kinds[arity], name, env, ordinalConst(withbase_ == -1 ? -1 : withbase_ - scope_base_), scopes, scope_count);
case OP_getglobalscope:
return getglobalscope();
}
break;
}
case kNameIndex:
case kNameNs:
- return naryStmt3(kinds[arity], name, env, popDef(), scopes, scope_count);
+ return naryStmt4(kinds[arity], name, env, ordinalConst(withbase_ == -1 ? -1 : withbase_ - scope_base_), popDef(), scopes, scope_count);
case kNameNsIndex: {
Def* index = popDef();
Def* ns = popDef();
- return naryStmt4(kinds[arity], name, env, ns, index, scopes, scope_count);
+ return naryStmt4(kinds[arity], name, env, ordinalConst(withbase_ == -1 ? -1 : withbase_ - scope_base_), ns, index, scopes, scope_count);
}
}
}
Def* AbcBuilder::finddefStmt(Def *name) {
return binaryStmt(HR_abc_finddef, name, env_param());
}
@@ -1449,30 +1540,61 @@ Def* AbcBuilder::toInt(Def* val) {
assert (false && "Not quite supported");
if (isInt(type(val)))
return val;
// toint is a statement because it can call Object.valueOf()
return unaryStmt(HR_toint, val);
}
bool AbcBuilder::needAbcState() {
- return enable_vmstate || method_->hasExceptions();
+ if (enable_vmstate) return true;
+ if (has_reachable_exceptions_) {
+ return handlerCoversPc(pc_);
+ }
+ return false;
+}
+
+bool AbcBuilder::handlerCoversPc(const uint8_t* pc) {
+ if (has_reachable_exceptions_) {
+ ExceptionHandlerTable* exTable = method_->abc_exceptions();
+ for (int i=0, n=exTable->exception_count; i < n; i++) {
+ ExceptionHandler* handler = &exTable->exceptions[i];
+ if (pc >= code_pos_ + handler->from && pc < code_pos_ + handler->to) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool AbcBuilder::pcIsHandler(const uint8_t* pc) {
+ if (has_reachable_exceptions_) {
+ ExceptionHandlerTable* exTable = method_->abc_exceptions();
+ for (int i=0, n=exTable->exception_count; i < n; i++) {
+ ExceptionHandler* handler = &exTable->exceptions[i];
+ if (pc == code_pos_ + handler->target) {
+ return true;
+ }
+ }
+ }
+ return false;
}
void AbcBuilder::createSetLocalInstr(int i, Def* val) {
SetlocalInstr* setlocal = factory_.newSetlocalInstr(i, state(), val);
- set_state(setlocal->state_out());
+ // set_state(setlocal->state_out());
builder_.addInstr(setlocal);
+ frame_[setlocal_pos_ + i] = setlocal->state_out();
}
void AbcBuilder::setLocal(int i, Def* val) {
frame_[i] = val;
// We have to save all assignments because setlocal and safepoints
// are used for deopt in addition to exceptions.
- if (!needAbcState()) {
+ if (!has_reachable_exceptions_) {
return;
}
createSetLocalInstr(i, val);
}
Traits* AbcBuilder::getNamedTraits(uint32_t type_name_index) {
DomainMgr* domainMgr = pool_->core->domainMgr();
@@ -1541,16 +1663,24 @@ Def* AbcBuilder::naryStmt3(InstrKind kin
Def* AbcBuilder::naryStmt4(InstrKind kind, Def* name, // multiname
Def* env, Def* ns, Def *index, Def* args[],
int extra_argc) {
NaryStmt4* stmt = factory_.newNaryStmt4(kind, effect(), name, env, ns, index,
extra_argc, args);
return finishStmt(stmt, stmt->effect_out(), stmt->value_out());
}
+Def* AbcBuilder::naryStmt4(InstrKind kind, Def* name, // multiname
+ Def* env, Def* ns, Def *index, Def* index2, Def* args[],
+ int extra_argc) {
+ NaryStmt4* stmt = factory_.newNaryStmt4(kind, effect(), name, env, ns, index, index2,
+ extra_argc, args);
+ return finishStmt(stmt, stmt->effect_out(), stmt->value_out());
+}
+
Def* AbcBuilder::callStmt2(InstrKind kind, Def *name, // name, function, or id
Def *object, Def* args[], int extra_argc) {
CallStmt2* call = factory_.newCallStmt2(kind, effect(), name, object,
extra_argc, args);
return finishStmt(call, call->effect_out(), call->value_out());
}
Def* AbcBuilder::finishStmt(Instr* instr, Def* effect, Def* value) {
@@ -1744,17 +1874,18 @@ void AbcBuilder::stopStmt(InstrKind kind
}
GotoInstr* goto_instr = factory_.newGotoStmt(label);
goto_instr->args[0] = effect();
goto_instr->args[1] = value;
builder_.addInstr(goto_instr);
}
Def * AbcBuilder::nullCheck(Def* ptr) {
- if (!isNullable(type(ptr)))
+ const Type* ptr_type = type(ptr);
+ if (!isNullable(ptr_type) && ptr_type->kind != kTypeVoid)
return ptr;
//ir_->addNullcheck(&effect_, &ptr_out);
UnaryStmt* stmt = factory_.newUnaryStmt(HR_cknull, effect(), ptr);
builder_.addInstr(stmt);
Def* ptr_out = stmt->value_out();
// Refs to ptr now should point to notnull(ptr)
@@ -1764,16 +1895,27 @@ Def * AbcBuilder::nullCheck(Def* ptr) {
for (FrameRange<Def*> r = frameRange(frame_); !r.empty(); r.popFront())
if (r.front() == ptr)
r.front() = ptr_out;
set_effect(stmt->effect_out());
return ptr_out;
}
+/// add unary statement on passed arg to ir graph in progress.
+/// control input is taken from last statement added.
+/// new statement's data output is returned, unless peephole()
+/// bypasses (but note that stmt is linked into ir regardless)
+///
+void AbcBuilder::debugInstr(InstrKind kind, Def* arg) {
+ DebugInstr* stmt = factory_.newDebugInstr(kind, effect(), arg);
+ builder_.addInstr(stmt);
+ set_effect(stmt->effect_out());
+}
+
/// Handle an if statement with the given sense and condition
///
void AbcBuilder::ifStmt(bool sense, Def* cond) {
const Type* cond_type = type(cond);
if (isConst(cond_type)) {
// cond is already known to be const, replace if with goto
int succ = int(boolVal(cond_type) == sense);
addGoto(abc_block_->succ_blocks[succ]);
@@ -1800,16 +1942,24 @@ void AbcBuilder::setFrameArgs(BlockEndIn
FrameRange<Use> arg_range = frameRange(args);
FrameRange<Def*> from_def = frameRange(frame_);
for (; !arg_range.empty(); arg_range.popFront(), from_def.popFront())
arg_range.front() = from_def.front();
args[effect_pos_] = effect();
args[state_pos_] = state();
+
+ if (has_reachable_exceptions_) {
+ // bring down the state of the locals from the label too
+ FrameIndexRange fir(stackp_, scopep_, stack_base_);
+ for (; !fir.empty(); fir.popFront()) {
+ args[setlocal_pos_ + fir.front()] = frame_[setlocal_pos_ + fir.front()];
+ }
+ }
}
/// Map the given successor of the current abc_block_
/// to a given ArmInstr and current stack/scope chain.
///
void AbcBuilder::addArm(int i, ArmInstr* arm, bool switch_arm) {
AbcBlock* to_block = abc_block_->succ_blocks[i];
AbcBlock* current_block = abc_block_;
@@ -1820,17 +1970,17 @@ void AbcBuilder::addArm(int i, ArmInstr*
int start_pc = int(current_block->end - 4 - abc_->code_pos());
int target_pc = int(to_block->start - abc_->code_pos());
MethodProfile* profile = JitManager::getProfile(method_);
double branch_probability = profile->getBranchProbability(start_pc,
target_pc);
profiled_info_->addBranchProbability(arm, branch_probability);
}
- if (to_block->num_preds > 1) {
+ if (to_block->num_preds > 1 || abc_block_ == to_block) {
// Target block either has or will need a label, so create an empty
// block for this arm, ending in a goto.
builder_.addInstr(arm);
set_effect(&arm->params[effect_pos_]);
addGoto(to_block);
} else {
// Target block's only predecessor is the CondInstr that owns this arm.
assert(!to_block->label);
@@ -1878,30 +2028,103 @@ void AbcBuilder::addGoto(AbcBlock* to_bl
LabelInstr* label = ensureBlockLabel(to_block);
GotoInstr* go = factory_.newGotoStmt(label, never_def_);
setFrameArgs(go);
builder_.addInstr(go);
}
/// helper - check/initialize an AbcBlock's LabelInstr
///
+CatchBlockInstr* AbcBuilder::ensureCatchBlockLabel(AbcBlock* abc_block) {
+ stackp_ = abc_block->start_sp = stack_base_;
+ scopep_ = abc_block->start_scopep = scope_base_ - 1;
+ withbase_ = abc_block->start_withbase;
+ assert(withbase_ == -1 || withbase_ > 0);
+ if (withbase_ != -1) {
+ withbase_ += scope_base_;
+ }
+
+ // set up the label with param capacity for the current frame
+ CatchBlockInstr* catch_block = factory_.newCatchBlockInstr(num_vars_);
+ catch_block->vpc = int(abc_block->start - code_pos_);
+
+ for (int i = 0; i < num_vars_; ++i) {
+ new (&catch_block->params[i]) Def(catch_block, lattice_.void_type);
+ }
+
+ setType(&catch_block->params[effect_pos_], EFFECT);
+ setType(&catch_block->params[state_pos_], STATE);
+
+ abc_block->label = catch_block;
+ ir_->addBlock(catch_block);
+
+ FrameRange<Def> p = frameRange(catch_block->params);
+ FrameRange<const Type*> t = abc_block->startTypesRange(stack_base_);
+ for (; !t.empty(); t.popFront(), p.popFront()) {
+ if (t.front() != NULL) {
+ // The model for the exception edges must be Atom for now to
+ // ensure consistent representations. It could be relaxed if
+ // all exception edges had the same model.
+ new (&p.front()) Def(catch_block, lattice_.makeAtom(t.front()));
+ }
+ }
+
+ if (has_reachable_exceptions_) {
+ // these start out simply as state
+ FrameIndexRange fir(stackp_, scopep_, stack_base_);
+ for (; !fir.empty(); fir.popFront()) {
+ setType(&catch_block->params[setlocal_pos_ + fir.front()], STATE);
+ }
+ }
+
+ linkExceptionEdge(ir_->begin, catch_block);
+ return catch_block;
+}
+
+void AbcBuilder::linkExceptionEdge(BlockStartInstr* block, CatchBlockInstr* catch_block) {
+ BlockEndInstr* end = InstrGraph::blockEnd(block);
+ ExceptionEdge* edge = new (alloc_) ExceptionEdge(block, catch_block);
+ if (enable_verbose)
+ console_ << "creating exception edge i" << block->id << " -> i" << catch_block->id << "\n";
+ // Link the edge
+ ExceptionEdge* N = catch_block->catch_preds;
+ if (!N) {
+ catch_block->catch_preds = edge;
+ edge->next_exception = edge->prev_exception = edge;
+ } else {
+ ExceptionEdge* P = N->prev_exception;
+ edge->next_exception = N;
+ edge->prev_exception = P;
+ N->prev_exception = edge;
+ P->next_exception = edge;
+ }
+ if (end->catch_blocks == NULL) {
+ end->catch_blocks = new (alloc_) SeqBuilder<ExceptionEdge*>(alloc_);
+ }
+ end->catch_blocks->add(edge);
+}
+
+/// helper - check/initialize an AbcBlock's LabelInstr
+///
LabelInstr* AbcBuilder::ensureBlockLabel(AbcBlock* abc_block) {
BlockStartInstr* block_start = abc_block->label;
if (!block_start) {
// set up the label with param capacity for the current frame
LabelInstr* label = factory_.newLabelInstr(num_vars_);
abc_block->label = label;
abc_block->start_sp = stackp_;
abc_block->start_scopep = scopep_;
ir_->addBlock(label);
return label;
}
// sanity check abcbuilder state vs. label state
assert(stackp_ == abc_block->start_sp);
assert(scopep_ == abc_block->start_scopep);
+ assert(withbase_ == abc_block->start_withbase ||
+ withbase_ == abc_block->start_withbase + scope_base_);
return cast<LabelInstr>(block_start);
}
/** Insert a timeout check. If cktimeout returns true then we branch
* to a throw. In reality, cktimeout itself will throw, but this way
* infinite loops have an exit path, which our IR requires
*/
void AbcBuilder::cktimeout() {
@@ -1961,42 +2184,63 @@ Def* AbcBuilder::hasnext2Stmt(Def** obj,
/// Start processing this abc_block.
///
void AbcBuilder::startBlock(AbcBlock* abc_block) {
// set abcbuilder state to this block
abc_block_ = abc_block;
stackp_ = abc_block->start_sp;
scopep_ = abc_block->start_scopep;
-
+ withbase_ = abc_block->start_withbase;
+ assert(withbase_ == -1 || withbase_ > 0);
+ if (withbase_ != -1) {
+ withbase_ += scope_base_;
+ }
BlockStartInstr* label = abc_block->label;
assert(label);
if (abc_block->dfs_loop) {
// Set label params to pessimistic types from CodegenDriver
// since we have not seen all predecessors yet.
FrameRange<Def> p = frameRange(label->params);
FrameRange<const Type*> t = abc_block->startTypesRange(stack_base_);
for (; !t.empty(); t.popFront(), p.popFront())
setType(&p.front(), t.front());
setType(&label->params[effect_pos_], EFFECT);
setType(&label->params[state_pos_], STATE);
+
+ if (has_reachable_exceptions_) {
+ // these start out simply as state
+ FrameIndexRange fir(stackp_, scopep_, stack_base_);
+ for (; !fir.empty(); fir.popFront()) {
+ setType(&label->params[setlocal_pos_ + fir.front()], STATE);
+ }
+ }
+
} else {
// Compute valid types for label params.
builder_.computeType(label);
}
-
+
set_effect(&label->params[effect_pos_]);
set_state(&label->params[state_pos_]);
FrameRange<Def> from = frameRange(label->params);
FrameRange<Def*> to = frameRange(frame_);
for (; !from.empty(); from.popFront(), to.popFront())
to.front() = &from.front();
+ if (has_reachable_exceptions_) {
+ // bring down the state of the locals from the label too
+ FrameIndexRange fir(stackp_, scopep_, stack_base_);
+ for (; !fir.empty(); fir.popFront()) {
+ frame_[setlocal_pos_ + fir.front()] = &label->params[setlocal_pos_ + fir.front()];
+ }
+ }
+
builder_.setPos(label);
if (enable_verbose)
printStartState(abc_block);
assert(checkFrame(frame_, stackp_, scopep_));
// Ignore the global configuration flag for timeouts because it can lead to
// IR graphs with no ends, if the graph has an infinite loop. We require
@@ -2008,11 +2252,49 @@ void AbcBuilder::startBlock(AbcBlock* ab
void AbcBuilder::printStartState(AbcBlock* abc_block) {
console_ << (abc_block->dfs_loop ? "LOOP:" : "BLOCK:") << " ["
<< int(abc_block->start - code_pos_) << "-"
<< int(abc_block->end - code_pos_) << "] effect=";
if (abc_block->label)
printInstr(console_, abc_block->label);
}
+void AbcBuilder::printFrameState() {
+ // locals
+ console_ << "[ ";
+ for (int i = 0; i < scope_base_; i++) {
+ printDef(console_, frame_[i]);
+ console_ << ":" << typeName(frame_[i]);
+ if (i+1 < scope_base_)
+ console_ << ' ';
+ }
+ console_ << " ] {";
+
+ // scope chain
+ for (int i = scope_base_; i < scopep_ + 1; i++) {
+ printDef(console_, frame_[i]);
+ console_ << ":" << typeName(frame_[i]);
+ if (i+1 < stack_base_)
+ console_ << ' ';
+ }
+ console_ << " } ( ";
+
+ // stack
+ for (int i = stack_base_; i < stackp_ + 1; i++) {
+ printDef(console_, frame_[i]);
+ console_ << ":" << typeName(frame_[i]);
+ if (i+1 < framesize_)
+ console_ << ' ';
+ }
+ console_ << " ) effect ";
+
+ printDef(console_, effect());
+ console_ << ":" << typeName(effect());
+
+ console_ << " withbase_ " << withbase_;
+
+ console_ << "\n";
+
+}
+
} // namespace avmplus
#endif // VMCFG_HALFMOON
--- a/halfmoon/hm-abcbuilder.h
+++ b/halfmoon/hm-abcbuilder.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HALFMOON_ABCBUILDER_H_
#define HALFMOON_ABCBUILDER_H_
namespace halfmoon {
@@ -22,17 +22,17 @@ class AbcBuilder {
kNameKnown, // name with no args, e.g. o.name
kNameIndex, // name with index on stack, e.g. o[index]
kNameNs, // name with namespace on stack, e.g. o.ns::name
kNameNsIndex
// name with namespace and index on stack o.ns::[index]
};
public:
- AbcBuilder(MethodInfo*, AbcGraph* abc, InstrFactory*, Toplevel*, ProfiledInformation* profiled_info);
+ AbcBuilder(MethodInfo*, AbcGraph* abc, InstrFactory*, Toplevel*, ProfiledInformation* profiled_info, bool has_reachable_exceptions);
~AbcBuilder();
InstrGraph* visitBlocks(Seq<AbcBlock*>*);
private:
class InitVisitor: public avmplus::InitVisitor {
public:
InitVisitor(AbcBuilder* abc, Def* object) : abc(abc), object(object) {}
virtual ~InitVisitor() {}
@@ -71,16 +71,19 @@ private:
void pushDef(Def*);
Def* finishStmt(Instr* instr, Def* effect, Def* value);
Def* naryStmt1(InstrKind, Def* name, Def** args, int argc);
Def* naryStmt2(InstrKind, Def* name, Def* obj, Def** args, int extra_argc);
Def* naryStmt3(InstrKind, Def* name, Def* obj, Def* index, Def** args,
int extra_argc);
Def* naryStmt4(InstrKind, Def* name, Def* obj, Def* ns, Def* index,
Def** args, int extra_argc);
+ // Build an NaryStmt4 with an extra fixed arg
+ Def* naryStmt4(InstrKind, Def* name, Def* obj, Def* ns, Def* index, Def* index2,
+ Def** args, int extra_argc);
Def* callStmt2(InstrKind, Def* name, Def* obj, Def** args, int extra_argc);
Def* callStmt3(InstrKind, Def* name, Def* index, Def* obj, Def** args,
int extra_argc);
Def* callStmt4(InstrKind, Def* name, Def* ns, Def* index, Def* obj,
Def** args, int extra_argc);
Def* callStmt(const InstrKind*, uint32_t name_index, int argc);
Def* initStmt(uint32_t name_index);
Def* newclassStmt(int scope_count, Def* base, Def* scopes[],
@@ -92,36 +95,40 @@ private:
Def* binaryStmt(InstrKind, Def* arg0, Def* arg1);
Def* binaryExpr(InstrKind, Def* arg0, Def* arg1);
Def* unaryStmt(InstrKind, Def* val_in);
Def* unaryExpr(InstrKind, Def* value);
void constructsuperStmt(int argc);
Def* coerceArgs(Def* obj, Def** args, int argc, MethodInfo* m);
void stopStmt(InstrKind, Def*, LabelInstr**);
Def* nullCheck(Def* ptr);
+ void debugInstr(InstrKind, Def* value);
void ifStmt(bool sense, Def* cond);
void addIf(bool sense, Def* cond);
void setFrameArgs(BlockEndInstr* end);
void addArm(int i, ArmInstr* arm, bool switch_arm = false);
void switchStmt(uint32_t num_cases, Def* index);
void addSwitch(uint32_t num_cases, Def* index);
void addGoto(AbcBlock* to);
LabelInstr* ensureBlockLabel(AbcBlock* abc_block);
+ CatchBlockInstr* ensureCatchBlockLabel(AbcBlock* abc_block);
+ void linkExceptionEdge(BlockStartInstr* block, CatchBlockInstr* catch_block);
void cktimeout();
void jumpStmt();
Def* newcatchStmt(uint32_t imm30);
void setslotStmt(uint32_t slot, Def* obj, Def* val);
Def* getslotStmt(Def* obj, uint32_t slot);
Def* getouterscopeStmt(uint32_t scope_index);
Def* getglobalscope();
Def* hasnext2Stmt(Def** obj, Def** ctr);
void startBlock(AbcBlock*);
void printStartState(AbcBlock*);
+ void printFrameState();
Def** popArgs(int argc);
Def* peekDef();
Def* popDef();
Def* coerceExpr(Traits*, Def*);
Def* toNumber(Def* val);
Def* toInt(Def* val);
@@ -130,16 +137,19 @@ private:
InstrKind getSpeculativeKind(RecordedType recorded_type);
Def* toSpeculativeType(Def* val, RecordedType abc_type);
bool isType(Def* val, RecordedType abc_type);
void createSetLocalInstr(int i, Def* val);
void setLocal(int i, Def* val);
bool needAbcState();
+ bool handlerCoversPc(const uint8_t* pc);
+ bool pcIsHandler(const uint8_t* pc);
+
// Profiler methods
bool shouldSpeculate();
Def* getTypedDef(const uint8_t* pc, Def* current_def, int input_index, int input_count, int output_count);
RecordedType getRecordedType(const uint8_t* pc, int input_index, int input_count, int output_count);
Def* typeSpecializedBinary(AbcOpcode abcop, const uint8_t* pc, Def* lhs, Def* rhs);
private:
Def* createConst(const Type* type) {
@@ -195,23 +205,27 @@ private:
PrintWriter& console_;
Lattice& lattice_;
const int scope_base_;
const int stack_base_;
const int framesize_;
const int num_vars_; // framesize + effect + state
const int effect_pos_; // position of effect within vars[] array
const int state_pos_; // position of state within vars[] array
+ const int setlocal_pos_;
int scopep_;
int stackp_;
+ int withbase_;
Def** const frame_; // most recent data results
AbcBlock* abc_block_; // current block
const uint8_t * const code_pos_;
+ const uint8_t * pc_;
+ bool has_reachable_exceptions_;
LabelInstr* return_label_;
LabelInstr* throw_label_;
InstrFactory& factory_;
InstrKind kind_map_[256]; // AbcOpcode -> InstrKind, indexed by AbcOpcode.
InstrGraph* const ir_;
InstrGraphBuilder builder_;
Def* never_def_;
ProfiledInformation* profiled_info_;
--- a/halfmoon/hm-abcgraph.cpp
+++ b/halfmoon/hm-abcgraph.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
// hm-abcgraph.cpp: implementation code for ABC Control Flow Graphs
//
@@ -25,17 +25,17 @@ AbcGraph::AbcGraph(MethodInfo* method)
/// Create and add a label starting at pc to blockmap_,
/// if not already present.
///
AbcBlock* AbcGraph::newAbcBlock(const uint8_t* pc) {
AbcBlock* b = blockmap_.get(pc);
if (!b) {
if (enable_verbose)
- printf("createBlock %d\n", int(pc - code_pos_));
+ method->pool()->core->console << "createBlock " << int(pc - code_pos_) << "\n";
blockmap_.put(pc, b = new (alloc0_) AbcBlock(pc));
}
return b;
}
/// Record an edge from one label to another, by adding
/// 'to' label to 'from' label's succ list. Create 'to'
/// label from target pc if necessary, and add it to
@@ -44,17 +44,17 @@ AbcBlock* AbcGraph::newAbcBlock(const ui
void AbcGraph::addAbcEdge(AbcBlock* fm, const uint8_t* target_pc, int edge_index) {
AbcBlock* to = newAbcBlock(target_pc);
++to->num_preds;
if (target_pc <= fm->start)
to->abc_loop = true;
fm->succ_blocks[edge_index] = to;
if (enable_verbose)
- printf("edge %d->%d\n", int(fm->start - code_pos_), int(target_pc - code_pos_));
+ method->pool()->core->console << "edge " << int(fm->start - code_pos_) << "->" << int(target_pc - code_pos_) << "\n";
}
void AbcGraph::createTryCatchBlocks() {
handler_count_ = table_->exception_count;
if (!handler_count_)
return;
handlers_ = new (alloc_) AbcBlock*[handler_count_];
for (int i = 0, n = handler_count_; i < n; ++i) {
--- a/halfmoon/hm-abcgraph.h
+++ b/halfmoon/hm-abcgraph.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HALFMOON_ABCGRAPH_H_
#define HALFMOON_ABCGRAPH_H_
namespace halfmoon {
@@ -15,17 +15,17 @@ using nanojit::BitSet;
/**
* An AbcBlock marks the boundaries of a basic label in ABC. frame_ is a
* state vector to track the current value (Def) in each local variable,
* scope chain slot, and operand stack slot, while building the InstrGraph.
*/
class AbcBlock {
public:
AbcBlock(const uint8_t* pc)
- : start(pc) {
+ : start(pc), start_withbase(-1) {
// Everything else is zero'd in newAbcBlock()
}
template<class E> FrameRange<E> startRange(E* frame, int stack_base) {
return FrameRange < E > (frame, start_sp, start_scopep, stack_base);
}
FrameRange<const Type*> startTypesRange(int stack_base) {
return startRange(start_types, stack_base);
@@ -39,16 +39,17 @@ public:
int max_catch_blocks; // size of catch_blocks[] array.
int post_id;
int num_preds; // Number of incoming normal and exception edges.
bool dfs_loop; // True if target of DFS back-edge.
bool abc_loop; // True if target of ABC back-edge.
const Type** start_types; // Verifier-derived types at label start.
BlockStartInstr* label; // BlockStartInstr for this AbcBlock
int start_sp, start_scopep; // stackp_ and scope at label start
+ int start_withbase;
};
/**
* An AbcInstr is a saved copy of arguments passed by the Verifier
* to JitWriter, for the few cases we can't or don't want to reconstruct
* from the raw ABC. Its a cheap way to reuse verifier specializations
* without re-implementing them in halfmoon.
*/
--- a/halfmoon/hm-algorithms.h
+++ b/halfmoon/hm-algorithms.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
/// Simple max function.
///
--- a/halfmoon/hm-bailout-stubs.h
+++ b/halfmoon/hm-bailout-stubs.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/***
* The equivalent of jit-calls.h in CodegenLIR but specific
* methods ONLY for halfmoon
*/
--- a/halfmoon/hm-bailouts.cpp
+++ b/halfmoon/hm-bailouts.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-bailouts.h
+++ b/halfmoon/hm-bailouts.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_BAILOUTS_H
#define HM_BAILOUTS_H
namespace halfmoon {
--- a/halfmoon/hm-check.cpp
+++ b/halfmoon/hm-check.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -215,18 +215,22 @@ bool TypeChecker::do_default(Instr* inst
if (hasInputSignature(instr)) {
// Check types from signature.
SigRange sig = inputSigRange(instr);
ArrayRange<Use> u = useRange(instr);
for (int i = 0; !u.empty(); u.popFront(), sig.popFront(), ++i) {
const Type* t = type(u.front());
const Type* constraint = sig.front();
if (!subtypeof(t, constraint)) {
+ avmplus::AvmCore* core = avmplus::AvmCore::getActiveCore();
+ printCompactInstr(core->console, instr, false);
report(i, u.front(), constraint, "subtype of");
} else if (check_model && !submodelof(t, constraint)) {
+ avmplus::AvmCore* core = avmplus::AvmCore::getActiveCore();
+ printCompactInstr(core->console, instr, false);
report(i, u.front(), constraint, "submodel of");
}
}
} else {
assert(numUses(instr) == 0 && "missing input signature");
}
return true;
@@ -275,16 +279,42 @@ bool checkPruned(InstrGraph* ir) {
marked.set(i.front()->id);
for (AllInstrRange i(ir); !i.empty(); i.popFront()) {
Instr* instr = i.front();
for (AllUsesRange u(instr); !u.empty(); u.popFront())
assert(marked.get(user(u.front())->id) && "user not linked");
if (kind(instr) == HR_label)
for (PredRange p(cast<LabelInstr>(instr)); !p.empty(); p.popFront())
assert(marked.get(p.front()->id) && "goto not linked");
+ if (kind(instr) == HR_catchblock) {
+ CatchBlockInstr* cblock = cast<CatchBlockInstr>(instr);
+ for (ExceptionEdgeRange p(cblock); !p.empty(); p.popFront()) {
+ assert(p.front()->from->catch_blocks != NULL);
+ bool found = false;
+ for (CatchBlockRange r(p.front()->from); !r.empty(); r.popFront()) {
+ if (r.front() == cblock) found = true;
+ }
+ assert(found);
+ }
+ }
+ if (isBlockEnd(instr)) {
+ BlockEndInstr* end = (BlockEndInstr*)instr;
+ if (end->catch_blocks != NULL) {
+ for (CatchBlockRange r(end); !r.empty(); r.popFront()) {
+ bool found = false;
+ for (ExceptionEdgeRange p(r.front()); !p.empty(); p.popFront()) {
+ if (p.front()->from == end) found = true;
+ }
+ if (!found) {
+ printf("missing exception back edge: i%d -> i%d", end->id, r.front()->id);
+ }
+ assert(found);
+ }
+ }
+ }
}
if (ir->end)
assert(marked.get(ir->end->id) && "end not linked");
if (ir->exit)
assert(marked.get(ir->exit->id) && "exit not linked");
return true;
}
@@ -698,54 +728,78 @@ public:
checkRetired(def_ins, use_ins);
}
void def(LIns* def_ins) {
setStatus(def_ins, kRetired);
}
// Print the LIR Control Flow Graph.
- void print() {
+ void print(AvmLogControl* logc) {
if (!printer)
return;
for (LirBlock* b = first_block; b; b = b->next) {
RefBuf rb1, rb2;
- printf("B%d [%s - %s]", b->linear_id,
+ logc->printf("B%d [%s - %s]", b->linear_id,
printer->formatRef(&rb1, b->first_ins, false),
printer->formatRef(&rb2, b->last_ins, false));
if (b->idom)
- printf(" idom=B%d", b->idom->linear_id);
+ logc->printf(" idom=B%d", b->idom->linear_id);
else if (!isReachable(b))
- printf(" unreachable");
- printf("\n");
+ logc->printf(" unreachable");
+
+ logc->printf(" preds [ ");
+ for (SeqRange<LirBlock*> i(b->preds); !i.empty(); i.popFront()) {
+ LirBlock* pred = i.front();
+ logc->printf(" B%d ", pred->linear_id);
+ }
+ logc->printf("]");
+ logc->printf(" succs [ ");
+ for (int s = 0; s < b->num_succs; s++) {
+ LirBlock* succ = b->succs[s];
+ logc->printf(" B%d ", succ->linear_id);
+ }
+ logc->printf("]");
+ logc->printf("\n");
+
+ LIns* last = b->last_ins;
+ LirReader r2(last);
+ ReverseLister rl(&r2, alloc, printer, logc, "Initial LIR");
+
+ // Scan each instruction and populate insmap.
+ LIns* ins;
+ do {
+ ins = rl.read();
+ } while (ins != b->first_ins);
+ rl.finish();
+
}
}
public:
Allocator alloc;
LInsPrinter* printer;
LIns* last_ins;
int num_blocks;
LirBlock* first_block; // First block in linear order.
LirBlock* last_block; // Last block in linear order.
insmap_t* insmap; // Map of LIns -> LirBlock.
bool error;
};
// fixme dont use halfmoon-specific enable_verbose
// todo Test checkLir() on sanities, brightspot, past bugs.
-// todo use Nanojit log instead of printf.
// todo move checkLir() to nanojit
-bool checkLir(Fragment* fragment) {
+bool checkLir(Fragment* fragment, AvmLogControl* logc) {
Allocator scratch;
LirCfg cfg(fragment);
computeDoms(cfg.first_block);
if (enable_verbose)
- cfg.print();
+ cfg.print(logc);
// Go through LIR instructions in reverse, checking each one.
for (LirBlock* b = cfg.last_block; b; b = b->prev) {
LirReader r(b->last_ins);
LIns *ins;
do {
ins = r.read();
switch (repKinds[ins->opcode()]) {
--- a/halfmoon/hm-check.h
+++ b/halfmoon/hm-check.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
/// Run checkTypes(Instr) on every instruction reachable by PostorderDefIter.
///
--- a/halfmoon/hm-cleaner.cpp
+++ b/halfmoon/hm-cleaner.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-cleaner.h
+++ b/halfmoon/hm-cleaner.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_CLEANER_H_
#define HM_CLEANER_H_
namespace halfmoon {
--- a/halfmoon/hm-constraints.cpp
+++ b/halfmoon/hm-constraints.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-constraints.h
+++ b/halfmoon/hm-constraints.h
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
/// Range
///
--- a/halfmoon/hm-dead.cpp
+++ b/halfmoon/hm-dead.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -23,16 +23,40 @@ void removeGoto(GotoInstr* go) {
GotoInstr* P = go->prev_goto;
if (target->preds == go)
target->preds = N;
N->prev_goto = P;
P->next_goto = N;
}
go->next_goto = go->prev_goto = 0;
go->target = 0;
+
+ if (go->catch_blocks != NULL) {
+ for (SeqRange<ExceptionEdge*> r(*go->catch_blocks); !r.empty(); r.popFront()) {
+ CatchBlockInstr* cblock = r.front()->to;
+
+ for (ExceptionEdgeRange p(cblock); !p.empty(); p.popFront()) {
+ ExceptionEdge* edge = p.front();
+ if (edge->from == go) {
+ // dead edge
+ if (edge->next_exception == edge) {
+ cblock->catch_preds = NULL;
+ } else {
+ ExceptionEdge* N = edge->next_exception;
+ ExceptionEdge* P = edge->prev_exception;
+ if (cblock->catch_preds == edge) {
+ cblock->catch_preds = N;
+ }
+ N->prev_exception = P;
+ P->next_exception = N;
+ }
+ }
+ }
+ }
+ }
}
/**
* Dead code elimination. This class implements the mark phase of an optimistic
* two-phase algorithm. The mark phase marks defs and instructions which are
* directly observable or contribute to observable computations.
*
* A branch is marked if some marked instruction is control-dependent on it,
--- a/halfmoon/hm-dead.h
+++ b/halfmoon/hm-dead.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_DEAD_H_
#define HM_DEAD_H_
namespace halfmoon {
--- a/halfmoon/hm-debug-inlines.h
+++ b/halfmoon/hm-debug-inlines.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Debug assistance code.
#ifndef HM_DEBUG_INLINES_H_
#define HM_DEBUG_INLINES_H_
--- a/halfmoon/hm-debug.cpp
+++ b/halfmoon/hm-debug.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-debug.h
+++ b/halfmoon/hm-debug.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// Debug assistance code.
#ifndef HM_DEBUG_H_
#define HM_DEBUG_H_
--- a/halfmoon/hm-dispatch.h
+++ b/halfmoon/hm-dispatch.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HALFMOON_DISPATCH_H
#define HALFMOON_DISPATCH_H
namespace halfmoon {
--- a/halfmoon/hm-dominatortree.cpp
+++ b/halfmoon/hm-dominatortree.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -115,16 +115,20 @@ int CfgInfo::intersect(int idom, int pre
class SuccEdges {
public:
class EdgeRange: public ArrayRange<ArmInstr*> {
public:
explicit EdgeRange(BlockStartInstr* b)
: ArrayRange<ArmInstr*>(armRange((CondInstr*)end(b))) {}
};
+ class CatchEdgeRange: public CatchBlockRange {
+ public:
+ explicit CatchEdgeRange(BlockStartInstr* block): CatchBlockRange(block) {}
+ };
class RootRange {
public:
explicit RootRange(InstrGraph* ir) : begin(ir->begin) {}
bool empty() const { return begin == 0; }
BlockStartInstr* front() const { assert(!empty()); return begin; }
BlockStartInstr* popFront() {
BlockStartInstr* b = begin;
begin = 0;
@@ -138,16 +142,19 @@ public:
}
static BlockStartInstr* next(BlockStartInstr* b) {
return cast<GotoInstr>(end(b))->target;
}
static bool manyEdges(BlockStartInstr* b) {
InstrKind k = kind(end(b));
return k == HR_if || k == HR_switch;
}
+ static bool hasCatchEdges(BlockStartInstr* b) {
+ return InstrGraph::blockEnd(b)->catch_blocks != NULL;
+ }
private:
static BlockEndInstr* end(BlockStartInstr* b) {
return InstrGraph::blockEnd(b);
}
};
class PredEdges {
public:
@@ -155,16 +162,26 @@ public:
public:
explicit EdgeRange(BlockStartInstr* b) : r(cast<LabelInstr>(b)) {}
bool empty() const { return r.empty(); }
BlockStartInstr* front() const { return start(r.front()); }
BlockStartInstr* popFront() { return start(r.popFront()); }
private:
PredRange r;
};
+ class CatchEdgeRange: public ExceptionEdgeRange {
+ public:
+ explicit CatchEdgeRange(BlockStartInstr* block): ExceptionEdgeRange(cast<CatchBlockInstr>(block)) {}
+ BlockStartInstr* front() {
+ return InstrGraph::blockStart(ExceptionEdgeRange::front()->from);
+ }
+ BlockStartInstr* popFront() {
+ return InstrGraph::blockStart(ExceptionEdgeRange::popFront()->from);
+ }
+ };
class RootRange {
public:
explicit RootRange(InstrGraph* ir) : ir(ir) {
assert((ir->exit || ir->end) && ir->exit != ir->end);
e = ir->exit ? ir->exit : ir->end;
}
bool empty() const { return e == 0; }
BlockStartInstr* front() const { assert(!empty()); return start(e); }
@@ -181,16 +198,19 @@ public:
return kind(b) == HR_arm;
}
static BlockStartInstr* next(BlockStartInstr* b) {
return start(cast<ArmInstr>(b)->owner);
}
static bool manyEdges(BlockStartInstr* b) {
return kind(b) == HR_label;
}
+ static bool hasCatchEdges(BlockStartInstr* b) {
+ return kind(b) == HR_catchblock;
+ }
private:
static BlockStartInstr* start(BlockEndInstr* e) {
return InstrGraph::blockStart(e);
}
};
template<class VIEW>
void CfgInfo::genericDfs(InstrGraph* ir) {
@@ -210,16 +230,20 @@ void CfgInfo::genericDfs(BlockStartInstr
return;
post_ids[blockid] = -1; // mark visited
if (VIEW::oneEdge(block)) {
genericDfs<VIEW>(VIEW::next(block));
} else if (VIEW::manyEdges(block)) {
for (typename VIEW::EdgeRange s(block); !s.empty();)
genericDfs<VIEW>(s.popFront());
}
+ if (VIEW::hasCatchEdges(block)) {
+ for (typename VIEW::CatchEdgeRange s(block); !s.empty();)
+ genericDfs<VIEW>(s.popFront());
+ }
int post_id = ++max_post_id;
post_ids[blockid] = post_id;
blocks[post_id].start = block;
}
template<class VIEW>
void CfgInfo::computeGenericDoms() {
blocks[max_post_id].idom = max_post_id;
@@ -235,19 +259,26 @@ void CfgInfo::computeGenericDoms() {
if (VIEW::oneEdge(block)) {
idom = post_ids[VIEW::next(block)->blockid];
} else if (VIEW::manyEdges(block)) {
for (typename VIEW::EdgeRange e(block); !e.empty();) {
int pred_post_id = post_ids[e.popFront()->blockid];
if (pred_post_id)
idom = intersect(idom, pred_post_id);
}
- } else {
+ } else if (!VIEW::hasCatchEdges(block)) {
idom = max_post_id; // idom is root node
}
+ if (VIEW::hasCatchEdges(block)) {
+ for (typename VIEW::CatchEdgeRange e(block); !e.empty();) {
+ int pred_post_id = post_ids[e.popFront()->blockid];
+ if (pred_post_id)
+ idom = intersect(idom, pred_post_id);
+ }
+ }
if (blocks[i].idom != idom) {
// save the newly computed dominator
blocks[i].idom = idom;
changed = true;
}
}
} while (changed);
}
@@ -273,31 +304,47 @@ void DominatorTree::computeGeneric(Instr
SparseSet visited(scratch, cfg.max_post_id + 1);
for (int i = cfg.max_post_id - 1; i > 0; --i) {
BlockStartInstr* block = cfg.blocks[i].start;
BlockInfo& info = info_[block->blockid];
int idom = cfg.blocks[i].idom;
BlockStartInstr* idom_instr = cfg.blocks[idom].start;
info.idom = idom_instr;
info.depth = idom_instr ? info_[idom_instr->blockid].depth + 1 : 1;
- if (REV::manyEdges(block)) {
+ if (REV::manyEdges(block) || REV::hasCatchEdges(block)) {
visited.clear();
+ }
+ if (REV::manyEdges(block)) {
for (typename REV::EdgeRange r(block); !r.empty();) {
BlockStartInstr* next = r.popFront();
int next_post_id = cfg.post_ids[next->blockid];
if (!next_post_id)
continue; // block was not reachable
for (int n = next_post_id; n != idom; n = cfg.blocks[n].idom) {
if (visited.add(n)) {
Seq<BlockStartInstr*>* &df = info_[cfg.blocks[n].start->blockid].df;
df = cons(dom_alloc_, block, df);
}
}
}
}
+ if (REV::hasCatchEdges(block)) {
+ for (typename REV::CatchEdgeRange r(block); !r.empty();) {
+ BlockStartInstr* next = r.popFront();
+ int next_post_id = cfg.post_ids[next->blockid];
+ if (!next_post_id)
+ continue; // block was not reachable
+ for (int n = next_post_id; n != idom; n = cfg.blocks[n].idom) {
+ if (visited.add(n)) {
+ Seq<BlockStartInstr*>* &df = info_[cfg.blocks[n].start->blockid].df;
+ df = cons(dom_alloc_, block, df);
+ }
+ }
+ }
+ }
}
}
DominatorTree* forwardDoms(Allocator& alloc, InstrGraph* ir) {
DominatorTree* d = new (alloc) DominatorTree(alloc, ir);
d->computeGeneric<SuccEdges, PredEdges>(ir);
return d;
}
--- a/halfmoon/hm-dominatortree.h
+++ b/halfmoon/hm-dominatortree.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef DOMINATORTREE_H_
#define DOMINATORTREE_H_
namespace halfmoon {
--- a/halfmoon/hm-exec.cpp
+++ b/halfmoon/hm-exec.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
// This file contains BaseExecMgr changes that belong in core/exec-jit.cpp
// or core/exec.cpp, but they are here to encapsulate them until halfmoon
// is a shipping feature.
@@ -13,25 +13,36 @@
#ifdef VMCFG_HALFMOON
#include "profiler/profiler-main.h"
namespace avmplus {
using halfmoon::JitManager;
bool BaseExecMgr::verifyOptimizeJit(MethodInfo* m, MethodSignaturep ms,
Toplevel* toplevel, AbcEnv* abc_env, OSR* /* osr_state */) {
- if (!halfmoon::canCompile(m))
- return false;
- halfmoon::JitWriter jit(m, toplevel, abc_env);
- verifyCommon(m, ms, toplevel, abc_env, &jit);
- GprMethodProc code = jit.finish();
- if (code) {
- setJit(m, code);
- return true;
+ if (halfmoon::canCompile(m)) {
+ halfmoon::JitWriter jit(m, toplevel, abc_env);
+ verifyCommon(m, ms, toplevel, abc_env, &jit);
+ GprMethodProc code = jit.finish();
+ if (code) {
+ setJit(m, code);
+ return true;
+ }
}
+ if (config.jitordie && halfmoon::enable_mode != 0) {
+ Exception* e = new (core->GetGC())
+ Exception(core, core->newStringLatin1("JIT failed")->atom());
+ e->flags |= Exception::EXIT_EXCEPTION;
+#ifdef AVMPLUS_VERBOSE
+ if (m->pool()->isVerbose(VB_execpolicy))
+ core->console << "execpolicy die " << m << " method-jit-failed\n";
+#endif
+ core->throwException(e);
+ }
+
return false;
}
void BaseExecMgr::resetMethodInvokers(MethodEnv* env) {
MethodInfo* method_info = env->method;
method_info->_implGPR = verifyEnterGPR;
method_info->_invoker = verifyInvoke;
env->_implGPR = method_info->_implGPR;
--- a/halfmoon/hm-identityanalyzer.cpp
+++ b/halfmoon/hm-identityanalyzer.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -23,27 +23,31 @@ Def* IdentityAnalyzer::identity(UnaryStm
/// Return the identity def for the given instruction, which will either
/// be effect_in, or the given value_in.
///
Def* IdentityAnalyzer::identity(UnaryStmt* instr) {
return def(def_ == instr->effect_out() ? instr->effect_in() :
instr->value_in());
}
+Def* IdentityAnalyzer::identity(NaryStmt3* instr, Def* value_in) {
+ return (def_ == instr->effect_out() ? def(instr->effect_in()) : value_in);
+}
+
Def* IdentityAnalyzer::identity(Instr* instr) {
assert(definer(def_) == instr && "Illegal def");
return do_instr(this, instr);
}
/// Analyze lexical lookup instructions HR_findprop and HR_findpropstrict.
///
-Def* IdentityAnalyzer::doFindStmt(NaryStmt2* instr) {
+Def* IdentityAnalyzer::doFindStmt(NaryStmt3* instr) {
int index;
if (findScope(lattice_, instr, &index) == kScopeLocal)
- return def(instr->vararg(index));
+ return identity(instr, def(instr->vararg(index)));
return def_;
}
Def* IdentityAnalyzer::do_cast(BinaryStmt* instr) {
const Type* traits_type = type(instr->lhs_in());
if (!isConst(traits_type))
return def_; // Don't know the target traits.
const Type* to_type = lattice_->makeType(traitsVal(traits_type));
--- a/halfmoon/hm-identityanalyzer.h
+++ b/halfmoon/hm-identityanalyzer.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef IDENTITYANALYZER_H_
#define IDENTITYANALYZER_H_
namespace halfmoon {
@@ -34,35 +34,36 @@ public: // dispatch() adapter methods.
Def* do_coerce(BinaryStmt*);
Def* do_castobject(UnaryExpr* i) { return coerceIdentity(i, lattice_->object_type[kTypeNullable]); }
Def* do_caststring(UnaryStmt* i) { return coerceIdentity(i, lattice_->string_type[kTypeNullable]); }
Def* do_tonumber(UnaryStmt* i) { return coerceIdentity(i, lattice_->double_type); }
Def* do_toint(UnaryStmt* i) { return coerceIdentity(i, lattice_->int_type); }
Def* do_touint(UnaryStmt* i) { return coerceIdentity(i, lattice_->uint_type); }
Def* do_toboolean(UnaryExpr* i) { return coerceIdentity(i, lattice_->boolean_type); }
Def* do_doubletoint32(UnaryExpr* i) { return coerceIdentity(i, lattice_->int_type); }
- Def* do_abc_findproperty(NaryStmt2* i) { return doFindStmt(i); }
- Def* do_abc_findpropstrict(NaryStmt2* i) { return doFindStmt(i); }
+ Def* do_abc_findproperty(NaryStmt3* i) { return doFindStmt(i); }
+ Def* do_abc_findpropstrict(NaryStmt3* i) { return doFindStmt(i); }
Def* do_atom2scriptobject(UnaryExpr* i) { return doModelChange(i, HR_scriptobject2atom); }
Def* do_cast(BinaryStmt*);
Def* do_cknull(UnaryStmt*);
Def* do_cknullobject(UnaryStmt* i) { return do_cknull(i); }
Def* do_u2i(UnaryExpr*);
Def* do_speculate_number(BinaryExpr*);
private:
/// Generic analyzer for lexical 'find' instructions.
///
- Def* doFindStmt(NaryStmt2*);
+ Def* doFindStmt(NaryStmt3*);
/// Helper method: return the appropriate identity def based on which
/// use value_in is, and what def_ is pointing to.
///
Def* identity(BinaryStmt*, Def* value_in);
Def* identity(UnaryStmt*, Def* value_in);
+ Def* identity(NaryStmt3*, Def* value_in);
/// Helper method: return UnaryStmt.effect_in or value_in based on
/// what def_ is pointing to.
///
Def* identity(UnaryStmt*);
/// Identity for coerce opcodes
///
--- a/halfmoon/hm-inline.cpp
+++ b/halfmoon/hm-inline.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-inline.h
+++ b/halfmoon/hm-inline.h
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
* hm-inline.h
*
* Created on: Apr 12, 2011
--- a/halfmoon/hm-instr.h
+++ b/halfmoon/hm-instr.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_INSTR_H_
#define HM_INSTR_H_
namespace halfmoon {
@@ -75,36 +75,36 @@ public:
/// A VarArgInstr has a variable (but nonvolatile)
/// number of uses (args) above a fixed minimum
/// number of uses, and a fixed number of defs.
///
/// NOTE: uses are stored 'off the end', requiring
/// custom allocation (see InstrFactory) and
/// precluding structural extension by subclasses.
///
-template<int USEMIN, int DEFC>
+template<int USEMIN, int DEFC, class BASE>
class VarArgInstr : public Instr {
friend class InfoManager;
friend class InstrFactory;
static InstrInfo createInfo(InstrKind kind, int argc, const Type** insig,
const Type** outsig, InstrGraph* ir) {
return InstrInfo(USEMIN + argc, DEFC,
- sizeof(VarArgInstr),
+ sizeof(BASE),
offsetof(VarArgInstr, defs),
kind, insig, outsig, ir);
}
protected:
VarArgInstr(const InstrInfo* info) :
Instr(info) {
}
Use* uses() {
- return (Use*)(this + 1);
+ return (Use*)((intptr_t)this + info->uses_off);
}
Def defs[DEFC];
public:
/// number of variable args
int vararg_count() const {
return this->info->num_uses - USEMIN;
@@ -122,27 +122,28 @@ public:
}
Use& use(int i) {
assert (i >= 0 && i < info->num_uses);
return uses()[i];
}
};
+
/// VarArgStmt is a VarArgInstr with a fixed minimum number
/// of arguments, whose first input and output are effects,
/// and whose second output is a data result. VarArgStmt is
/// parameterized on its fixed minimum number of value args.
/// the "arg" range of a VarArgStmt maps exactly to VarArgInstr's
/// "vararg" range.
template<int ARGMIN>
-class NaryStmt : public VarArgInstr<ARGMIN + 1, 2> {
+class NaryStmt : public VarArgInstr<ARGMIN + 1, 2, class NaryStmt<ARGMIN> > {
protected:
NaryStmt(const InstrInfo* info) :
- VarArgInstr<ARGMIN + 1, 2>(info) {
+ VarArgInstr<ARGMIN + 1, 2, class NaryStmt<ARGMIN> >(info) {
}
public:
Def* effect_out() {
return &this->defs[0];
}
Def* value_out() {
@@ -173,20 +174,20 @@ public:
/// parameterized on its fixed minimum number of value args.
///
/// NOTE: the term 'arg' in CallStmt's API means
/// the combination of the last fixed arg plus variable args, designed
/// to be congruent with VM calling conventions. The only difference
/// between CallStmt and NaryStmt is the definition of the 'arg' range.
///
template<int ARGMIN>
-class CallStmt : public VarArgInstr<ARGMIN + 1, 2> {
+class CallStmt : public VarArgInstr<ARGMIN + 1, 2, class CallStmt<ARGMIN> > {
protected:
CallStmt(const InstrInfo* info) :
- VarArgInstr<ARGMIN + 1, 2>(info) {
+ VarArgInstr<ARGMIN + 1, 2, class CallStmt<ARGMIN> >(info) {
}
public:
Def* effect_out() {
return &this->defs[0];
}
Def* value_out() {
@@ -268,17 +269,16 @@ class NaryStmt3 : public NaryStmt<3> {
NaryStmt3(const InstrInfo* info) : NaryStmt<3>(info) {
}
public:
// for findproperty opcodes
Use& name_in() { return uses()[1]; }
Use& env_in() { return uses()[2]; }
- Use& ns_in() { return uses()[3]; } // namespace variable
Use& index_in() { return uses()[3]; } // index variable
public:
static const InstrShape shape = NARYSTMT3_SHAPE;
};
class NaryStmt4 : public NaryStmt<4> {
friend class InstrFactory;
@@ -286,18 +286,16 @@ class NaryStmt4 : public NaryStmt<4> {
NaryStmt4(const InstrInfo* info) : NaryStmt<4>(info) {
}
public:
// for findproperty opcodes
Use& name_in() { return uses()[1]; }
Use& env_in() { return uses()[2]; }
- Use& ns_in() { return uses()[3]; } // namespace variable
- Use& index_in() { return uses()[4]; } // index variable
public:
static const InstrShape shape = NARYSTMT4_SHAPE;
};
/// CallStmt2 is for instructions that take a name parameter,
/// an object, and some arguments.
///
@@ -569,39 +567,47 @@ public:
/// 2. Conditional Exception. This would look just like a conditional branch;
/// it would have an explicit control edge to a catch block, and the catch
/// block would start with a block and phis for all incoming paths and
/// live values. This supports full dataflow analysis and would be used
/// if we want to optimize the try code and catch code at the same time.
///
/// Safepoint MUST output state, because it has an implicit setlocal
/// It implicitly saves the current abc
-class SafepointInstr : public FixedArgStmt<1, 1> {
+class SafepointInstr : public VarArgInstr<1, 2, class SafepointInstr> {
friend class InfoManager;
friend class InstrFactory;
friend class Copier;
SafepointInstr(const InstrInfo* info) :
- FixedArgStmt<1, 1>(info) {
+ VarArgInstr<1, 2, class SafepointInstr>(info) {
+ assert(info->uses_off == sizeof(SafepointInstr));
}
+ static const int USEMIN = 1; // effect in
+ static const int DEFC = 2; // effect out, state out
+
public:
static const InstrShape shape = SAFEPOINTINSTR_SHAPE;
int vpc; // Points into abc bytecode. fixme: should be uint8_t*.
int sp; // points to top of operand stack
int scopep; // points to top of abc scope stack.
- Use& state_in() {
- return this->uses[1];
+ Def* effect_out() {
+ return &this->defs[0];
}
Def* state_out() {
return &this->defs[1];
}
+
+ Use& effect_in() {
+ return this->uses()[0];
+ }
};
/// A setlocal instruction updates one element of the abstract "local state"
/// tuple (called kStateIn and kStateOut).
/// input: kStateIn (v0, ..., vk, ... vN), newval, index (k)
/// output: kStateOut (v0, ..., newval, ... vN)
///
class SetlocalInstr : public FixedArgInstr<2, 1> {
@@ -739,16 +745,35 @@ public:
DeoptSafepointInstr* safepoint;
Use& value_in() {
return this->uses[1];
}
};
+
+class DebugInstr : public FixedArgStmt<1, 0> {
+ friend class InfoManager;
+ friend class InstrFactory;
+ friend class Copier;
+
+ DebugInstr(const InstrInfo* info) :
+ FixedArgStmt<1, 0>(info) {
+ }
+
+public:
+ static const InstrShape shape = DEBUGINSTR_SHAPE;
+
+ Use& value_in() {
+ return this->uses[1];
+ }
+};
+
+
// ------------------------------- IR5 start ---------------------------------
/// BlockStartInstr is the common superclass of all IR5
/// block start delimiters: StartInstr, LabelInstr,
/// ArmInstr.
///
/// All block start instructions carry a parameter
/// list of Defs. Predecessor blocks end with block
@@ -799,31 +824,44 @@ public:
/// start delimiters carrying congruent parameter
/// lists.
///
/// Design note: we use an allocated array for args,
/// rather than inline off-the-end storage, so that
/// we can factor out a nonvirtual superclass of
/// block end delimiters.
///
+
+class ExceptionEdge {
+ public:
+ ExceptionEdge(BlockStartInstr* f, CatchBlockInstr* t): from(InstrGraph::blockEnd(f)), to(t), next_exception(NULL), prev_exception(NULL) {}
+
+ BlockEndInstr* from;
+ CatchBlockInstr* to;
+ ExceptionEdge *next_exception, *prev_exception;
+};
+
class BlockEndInstr : public Instr {
protected:
static InstrInfo createInfo(InstrKind kind, const Type** insig,
const Type** outsig, InstrGraph* ir) {
return InstrInfo(-1, 0, -1, 0, kind, insig, outsig, ir);
}
BlockEndInstr(const InstrInfo* info, Use* args) :
- Instr(info), args(args) {
+ Instr(info), args(args), catch_blocks(NULL) {
}
public:
Use* args; // arguments for successor
+
+ SeqBuilder<ExceptionEdge*>* catch_blocks;
};
+
/// A BlockFooterInstr ends a block that is a unique
/// predecessor - i.e., none of its successors has any
/// other predecessor. As such it owns its argument count,
/// which determines the parameter counts of its successors.
///
class BlockFooterInstr : public BlockEndInstr {
protected:
BlockFooterInstr(const InstrInfo* info, int argc, Use* args) :
@@ -931,16 +969,18 @@ public:
/// A LabelInstr starts a block targeted by multiple predecessors.
/// Every incoming edge must come from a GotoInstr.
///
class LabelInstr : public BlockHeaderInstr {
friend class InfoManager;
friend class InstrFactory;
friend class Copier;
+
+protected:
LabelInstr(const InstrInfo* info, int paramc, Def* params) :
BlockHeaderInstr(info, paramc, params), preds(0) {
}
public:
static const InstrShape shape = LABELINSTR_SHAPE;
GotoInstr* preds; // list of incoming gotos
@@ -1098,23 +1138,113 @@ public:
return arms[i];
}
ArmInstr* default_arm() {
return arms[num_cases()];
}
};
+/// A CatchBlockInstr begins the initial block of a catch block. Legal
+/// opcodes are HR_catchblock. The parameters of a CatchBlockInstr are
+/// the incoming state.
+///
+/// HR_catchblock: ([args]
+class CatchBlockInstr : public LabelInstr {
+ friend class InfoManager;
+ friend class InstrFactory;
+ friend class Copier;
+
+ CatchBlockInstr(const InstrInfo* info, int paramc, Def* params) :
+ LabelInstr(info, paramc, params), catch_preds(NULL) {
+ }
+
+public:
+ static const InstrShape shape = CATCHBLOCKINSTR_SHAPE;
+
+ /** Number of parameters, not counting effect */
+ int data_param_count() const {
+ return paramc - 1;
+ }
+
+ /** get data param i */
+ Def* data_param(int i) {
+ assert(i >= 0 && i < data_param_count());
+ return ¶ms[1 + i];
+ }
+
+ Def* effect_out() {
+ return ¶ms[0];
+ }
+
+ int vpc;
+ ExceptionEdge* catch_preds;
+
+ inline void printCatchPreds();
+};
+
+class CatchBlockRange: public SeqRange<ExceptionEdge*> {
+ public:
+ explicit CatchBlockRange(BlockStartInstr* block): SeqRange<ExceptionEdge*>(*InstrGraph::blockEnd(block)->catch_blocks) {}
+ explicit CatchBlockRange(BlockEndInstr* block): SeqRange<ExceptionEdge*>(*block->catch_blocks) {}
+
+ CatchBlockInstr* front() const {
+ return SeqRange<ExceptionEdge*>::front()->to;
+ }
+ CatchBlockInstr* popFront() {
+ CatchBlockInstr* t = front();
+ SeqRange<ExceptionEdge*>::popFront();
+ return t;
+ }
+};
+
+
+class ExceptionEdgeRange {
+public:
+ explicit ExceptionEdgeRange(CatchBlockInstr* catch_block) {
+ ExceptionEdge* p = catch_block->catch_preds;
+ front_ = p;
+ back_ = p ? p->prev_exception : 0;
+ }
+
+ bool empty() const {
+ return !front_;
+ }
+
+ ExceptionEdge* front() const {
+ assert(!empty());
+ return front_;
+ }
+
+ ExceptionEdge* popFront() {
+ ExceptionEdge* t = front();
+ ExceptionEdge* F = front_;
+ front_ = (F == back_) ? (back_ = 0) : F->next_exception;
+ return t;
+ }
+
+private:
+ ExceptionEdge *front_, *back_;
+};
+
+inline void CatchBlockInstr::printCatchPreds() {
+ printf("exception edges ( ");
+ for (ExceptionEdgeRange r(this); !r.empty(); r.popFront())
+ printf("i%d ", r.front()->from->id);
+ printf(") -> i%d\n", id);
+}
+
// ------------------------------- IR5 end ---------------------------------
/// true if this goto is the only predecessor of its target.
///
inline bool isAlone(GotoInstr* go) {
assert(go->target);
- return go->next_goto == go;
+ // Don't allow start block to merge into main block
+ return go->next_goto == go && kind(InstrGraph::blockStart(go)) != HR_start;
}
/// Range over the param at the given position
/// for all arms of a CondInstr
///
class ArmParamRange {
public:
ArmParamRange(CondInstr* instr, int pos) :
--- a/halfmoon/hm-instrfactory.cpp
+++ b/halfmoon/hm-instrfactory.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
#include "hm-templatebuilder.h"
@@ -183,19 +183,19 @@ NaryStmt2* InstrFactory::newNaryStmt2(In
NaryStmt3* InstrFactory::newNaryStmt3(InstrKind kind, Def* effect, Def* param1,
Def* param2, Def* param3, int varargc,
Def* varargs[]) {
assert(isNaryStmt3(kind) && "invalid opcode");
InstrInfo* info = infos_.get<NaryStmt3>(kind, varargc, this);
NaryStmt3* stmt = new (alloc_, info->num_uses, sizeof(Use)) NaryStmt3(info);
// placement new to initialize Uses
new (&stmt->effect_in()) Use(stmt, effect);
- new (&stmt->name_in()) Use(stmt, param1);
- new (&stmt->env_in()) Use(stmt, param2);
- new (&stmt->index_in()) Use(stmt, param3);
+ new (&stmt->uses()[1]) Use(stmt, param1);
+ new (&stmt->uses()[2]) Use(stmt, param2);
+ new (&stmt->uses()[3]) Use(stmt, param3);
for (int i = 0; i < varargc; ++i)
new (&stmt->vararg(i)) Use(stmt, varargs[i]);
// placement new to initialize Defs
new (stmt->effect_out()) Def(stmt);
new (stmt->value_out()) Def(stmt);
return stmt;
}
@@ -204,28 +204,52 @@ NaryStmt3* InstrFactory::newNaryStmt3(In
NaryStmt4* InstrFactory::newNaryStmt4(InstrKind kind, Def* effect, Def* param1,
Def* param2, Def* param3, Def* param4,
int varargc, Def* varargs[]) {
assert(isNaryStmt4(kind) && "invalid opcode");
InstrInfo* info = infos_.get<NaryStmt4>(kind, varargc, this);
NaryStmt4* stmt = new (alloc_, info->num_uses, sizeof(Use)) NaryStmt4(info);
// placement new to initialize Uses
new (&stmt->effect_in()) Use(stmt, effect);
- new (&stmt->name_in()) Use(stmt, param1);
- new (&stmt->env_in()) Use(stmt, param2);
- new (&stmt->ns_in()) Use(stmt, param3);
- new (&stmt->index_in()) Use(stmt, param4);
+ new (&stmt->uses()[1]) Use(stmt, param1);
+ new (&stmt->uses()[2]) Use(stmt, param2);
+ new (&stmt->uses()[3]) Use(stmt, param3);
+ new (&stmt->uses()[4]) Use(stmt, param4);
for (int i = 0; i < varargc; ++i)
new (&stmt->vararg(i)) Use(stmt, varargs[i]);
// placement new to initialize Defs
new (stmt->effect_out()) Def(stmt);
new (stmt->value_out()) Def(stmt);
return stmt;
}
+/// Create an nary5 statement with the given inputs.
+///
+NaryStmt4* InstrFactory::newNaryStmt4(InstrKind kind, Def* effect, Def* param1,
+ Def* param2, Def* param3, Def* param4, Def* param5,
+ int varargc, Def* varargs[]) {
+ assert(isNaryStmt4(kind) && "invalid opcode");
+ varargc++;
+ InstrInfo* info = infos_.get<NaryStmt4>(kind, varargc, this);
+ NaryStmt4* stmt = new (alloc_, info->num_uses, sizeof(Use)) NaryStmt4(info);
+ // placement new to initialize Uses
+ new (&stmt->effect_in()) Use(stmt, effect);
+ new (&stmt->uses()[1]) Use(stmt, param1);
+ new (&stmt->uses()[2]) Use(stmt, param2);
+ new (&stmt->uses()[3]) Use(stmt, param3);
+ new (&stmt->uses()[4]) Use(stmt, param4);
+ new (&stmt->vararg(0)) Use(stmt, param5);
+ for (int i = 1; i < varargc; ++i)
+ new (&stmt->vararg(i)) Use(stmt, varargs[i - 1]);
+ // placement new to initialize Defs
+ new (stmt->effect_out()) Def(stmt);
+ new (stmt->value_out()) Def(stmt);
+ return stmt;
+}
+
/// helper - create and initialize a CallStmt2, up to but not including
/// initializing the varargs
///
CallStmt2* InstrFactory::createCallStmt2(InstrKind kind, Def* effect, Def* param,
Def* obj, int varargc) {
assert(isCallStmt2(kind) && "invalid opcode for call statement");
InstrInfo* info = infos_.get<CallStmt2>(kind, varargc, this);
CallStmt2* call = new (alloc_, info->num_uses, sizeof(Use)) CallStmt2(info);
@@ -504,16 +528,25 @@ StartInstr* InstrFactory::newStartInstr(
param_types[fixedc] = lattice_.array_type[kTypeNotNull];
for (int i = 0; i < paramc; ++i)
new (&start->params[i]) Def(start, param_types[i]);
return start;
}
+/// Create CatchBlock instruction with given param types
+///
+CatchBlockInstr* InstrFactory::newCatchBlockInstr(int paramc) {
+ Def* params = new (alloc_) Def[paramc];
+ CatchBlockInstr* start = new (alloc_) CatchBlockInstr(infos_.get<CatchBlockInstr>(HR_catchblock, this),
+ paramc, params);
+ return start;
+}
+
/// private helper: initialize an ArmInstr within a given owner
/// NOTE: static, takes an allocator so it can be called by Info::clone()
/// TODO: refactor so clone just calls a helper in here for the whole CondInstr
///
ArmInstr* InstrFactory::initArm(Allocator& alloc, int arm_pos, CondInstr* owner,
const InstrInfo* info) {
ArmInstr* arm = new (alloc) ArmInstr(info);
arm->owner = owner;
@@ -690,24 +723,28 @@ StopInstr* InstrFactory::newStopInstr(In
new (&stop->args[0]) Use(stop, effect);
for (int i = 0; i < data_argc; ++i)
new (&stop->args[i + 1]) Use(stop, data_args[i]);
return stop;
}
/// create a new safepoint instr with the given inputs
///
-SafepointInstr* InstrFactory::newSafepointInstr(Def* effect, Def* state) {
- SafepointInstr* instr = new (alloc_)
- SafepointInstr(infos_.get<SafepointInstr>(HR_safepoint, this));
- new (&instr->effect_in()) Use(instr, effect);
- new (&instr->state_in()) Use(instr, state);
- new (instr->effect_out()) Def(instr);
- new (instr->state_out()) Def(instr);
- return instr;
+SafepointInstr* InstrFactory::newSafepointInstr(Def* effect, int argc, Def* args[]) {
+ InstrInfo* info = infos_.get<SafepointInstr>(HR_safepoint, argc, this);
+ SafepointInstr* stmt =
+ new (alloc_, info->num_uses, sizeof(Use)) SafepointInstr(info);
+ // placement new to initialize uses.
+ new (&stmt->effect_in()) Use(stmt, effect);
+ for (int i = 0; i < argc; ++i)
+ new (&stmt->vararg(i)) Use(stmt, args[i]); // placement new
+ // placement new to initialize defs.
+ new (stmt->effect_out()) Def(stmt);
+ new (stmt->state_out()) Def(stmt);
+ return stmt;
}
/// create a new setlocal instr with the given tuple index,
/// state tuple, and value to set
///
SetlocalInstr* InstrFactory::newSetlocalInstr(int index, Def* state, Def* val) {
SetlocalInstr* setlocal = new (alloc_)
SetlocalInstr(infos_.get<SetlocalInstr>(HR_setlocal, this), index);
@@ -754,16 +791,27 @@ DeoptFinishCallInstr* InstrFactory::newD
DeoptFinishInstr* InstrFactory::newDeoptFinishInstr(Def* effect) {
InstrInfo* info = infos_.get<DeoptFinishInstr>(HR_deopt_finish, this);
DeoptFinishInstr* stmt = new (alloc_) DeoptFinishInstr(info);
new (&stmt->effect_in()) Use(stmt, effect);
new (stmt->effect_out()) Def(stmt);
return stmt;
}
+DebugInstr* InstrFactory::newDebugInstr(InstrKind kind, Def* effect, Def* val) {
+ DebugInstr* debuginstr = new (alloc_)
+ DebugInstr(infos_.get<DebugInstr>(kind, this));
+ // placement new to initialize uses
+ new (&debuginstr->effect_in()) Use(debuginstr, effect);
+ new (&debuginstr->value_in()) Use(debuginstr, val);
+ // placement new to initialize defs
+ new (debuginstr->effect_out()) Def(debuginstr);
+ return debuginstr;
+}
+
/// create a new InstrGraph, using our infos and lattice
///
InstrGraph* InstrFactory::createGraph() {
return new (alloc_) InstrGraph(this, &infos_);
}
/// helper: return the HR coercion opcode corresponding
/// to the given traits.
--- a/halfmoon/hm-instrfactory.h
+++ b/halfmoon/hm-instrfactory.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef INSTR_FACTORY_H_
#define INSTR_FACTORY_H_
namespace halfmoon {
@@ -37,16 +37,18 @@ public:
NaryStmt2* newNaryStmt2(InstrKind kind, Def* effect, Def* param1,
Def* param2, int varargc, Def* varargs[]);
NaryStmt3* newNaryStmt3(InstrKind kind, Def* effect, Def* param1, Def* param2,
Def* param3, int varargc, Def* varargs[]);
NaryStmt4* newNaryStmt4(InstrKind kind, Def* effect, Def* param1, Def* param2,
Def* param3, Def* param4, int varargc, Def* varargs[]);
+ NaryStmt4* newNaryStmt4(InstrKind kind, Def* effect, Def* param1, Def* param2,
+ Def* param3, Def* param4, Def* param5, int varargc, Def* varargs[]);
// call stmt with multiname
CallStmt2* newCallStmt2(InstrKind kind, Def* effect, Def* param,
Def* obj, int varargc, Def* varargs[]);
CallStmt2* newCallStmt2(InstrKind kind, Def* effect, Def* param,
Def* obj, Def* arg);
CallStmt2* newCallStmt2(InstrKind kind, Def* effect, Def* param,
Def* obj);
@@ -90,16 +92,19 @@ public:
// label instr
LabelInstr* newLabelInstr(int param_count);
// start instr
StartInstr* newStartInstr(MethodInfo* method);
StartInstr* newStartInstr(InstrKind kind, int num_params, const Type* param_types[]);
+ // catchblock instr
+ CatchBlockInstr* newCatchBlockInstr(int num_params);
+
// if instr
IfInstr* newIfInstr(Def* cond, int argc, Def* args[]); // n-arg array
IfInstr* newIfInstr(Def* cond, Def* arg); // single arg
IfInstr* newIfInstr(Def* cond, Def* arg0, Def* arg1); // pair of args
IfInstr* newIfInstr(Def* cond, int argc, Def* default_arg); // n-arg default
IfInstr* newIfInstr(Def* cond, int argc); // n-arg NULL
// switch instr
@@ -108,23 +113,26 @@ public:
// goto statement
GotoInstr* newGotoStmt(LabelInstr* target, Def* default_def = 0);
/// stop instruction
StopInstr* newStopInstr(InstrKind k, Def* effect, Def* data);
StopInstr* newStopInstr(InstrKind k, Def* effect, int data_argc, Def* data_args[]);
// safepoint instr
- SafepointInstr* newSafepointInstr(Def* effect, Def* state);
+ SafepointInstr* newSafepointInstr(Def* effect, int argc, Def* args[]);
// DEOPT: new-style safepoint instr
DeoptSafepointInstr* newDeoptSafepointInstr(Def* effect, int argc, Def* args[]);
DeoptFinishInstr* newDeoptFinishInstr(Def* effect);
DeoptFinishCallInstr* newDeoptFinishCallInstr(Def* effect, Def* val);
+ // debugfile and debugline
+ DebugInstr* newDebugInstr(InstrKind kind, Def* effect, Def* val);
+
// setlocal instr
SetlocalInstr* newSetlocalInstr(int index, Def* state, Def* val);
// create a new InstrGraph over our infos and lattice
InstrGraph* createGraph();
private:
// private helper - create a CallStmt2, up to vararg initialization
--- a/halfmoon/hm-instrgraph.cpp
+++ b/halfmoon/hm-instrgraph.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -15,17 +15,17 @@ InstrGraph::InstrGraph(InstrFactory* fac
, infos_(infos)
, alloc_(factory->alloc())
, instr_count_(0)
, block_count_(0)
, def_count_(0) {
}
Instr* finishAdding(InstrGraph* ir, Instr* instr) {
- if (enable_typecheck && !enable_verbose)
+ if (enable_typecheck)
printCompactInstr(ir->lattice.console(), instr, false);
TypeAnalyzer(ir).computeTypes(instr);
if (enable_verbose)
printInstr(ir->lattice.console(), instr);
return instr;
}
Instr* InstrGraph::addInstrAfter(Instr* pos, Instr* instr) {
@@ -269,16 +269,71 @@ void InstrGraph::joinBlocks(BlockEndInst
int param_count = numDefs(succ_start);
// For each succ_start param, redirect all uses to the def specified
// by pred_end's corresponding arg, then clear the arg.
for (int i = 0; i < param_count; ++i) {
Def* new_def = def(pred_end->args[i]);
pred_end->args[i] = 0;
copyUses(&succ_start->params[i], new_def);
}
+
+ if (pred_end->catch_blocks != NULL) {
+ // Merge these into succ
+ BlockEndInstr* succ_end = blockEnd(succ_start);
+ if (succ_end->catch_blocks == NULL) {
+ // Successors didn't have any, so just transfer them
+ succ_end->catch_blocks = pred_end->catch_blocks;
+ for (SeqRange<ExceptionEdge*> r(*pred_end->catch_blocks); !r.empty(); r.popFront()) {
+ if (enable_verbose) {
+ lattice.console() << "adjusting exception edge from i" << r.front()->from->id << " -> i" << r.front()->to->id << "\n";
+ }
+ r.front()->from = succ_end;
+ if (enable_verbose) {
+ lattice.console() << "adjusting exception edge to i" << r.front()->from->id << " -> i" << r.front()->to->id << "\n";
+ }
+ }
+ } else {
+ // Merge the lists
+ for (CatchBlockRange succ_catch(succ_end); !succ_catch.empty();) {
+ CatchBlockInstr* catch_block = succ_catch.popFront();
+ for (CatchBlockRange pred_catch(pred_end); !pred_catch.empty();) {
+ if (catch_block == pred_catch.popFront()) {
+ catch_block = NULL;
+ break;
+ }
+ }
+ if (catch_block != NULL) {
+ ExceptionEdge* edge = new (alloc_) ExceptionEdge(succ_start, catch_block);
+ pred_end->catch_blocks->add(edge);
+
+ if (enable_verbose)
+ lattice.console() << "adding exception edge i" << succ_start->id << " -> i" << catch_block->id << "\n";
+
+ ExceptionEdge* N = catch_block->catch_preds;
+ ExceptionEdge* P = N->prev_exception;
+ edge->next_exception = N;
+ edge->prev_exception = P;
+ N->prev_exception = edge;
+ P->next_exception = edge;
+ }
+ }
+ // Disconnect this block
+ for (SeqRange<ExceptionEdge*> r(*pred_end->catch_blocks); !r.empty();) {
+ ExceptionEdge* edge = r.popFront();
+ ExceptionEdge* N = edge->next_exception;
+ ExceptionEdge* P = edge->prev_exception;
+ if (edge->to->catch_preds == edge) {
+ edge->to->catch_preds = N;
+ }
+ N->prev_exception = P;
+ P->next_exception = N;
+ }
+ }
+ }
+
InstrRange block(succ_start);
block.unlinkFront(); // remove succ_start from its block
replaceInstr(pred_end, block);
}
/// TODO
///
InstrRange InstrGraph::returnBlock() const {
@@ -323,26 +378,34 @@ PrintWriter& InstrGraphBuilder::console(
void InstrGraphBuilder::setPos(Instr* instr) {
assert(isBlockStart(instr));
pos_ = instr;
}
/// Create a const-generating instr of the given type if one does not already
/// exist. Since constants are only created once, link them immediately
/// after ir->begin to ensure the constant dominates all uses.
+/// In the presence of exception edges this enforced sharing results
+/// problems in the register allocator, so treat them as normal
+/// instructions and let value numbering share them where it's possible locally.
Def* InstrGraphBuilder::addConst(const Type* t) {
assert(isConst(t));
+#if 0
TypeKey k(t);
Def* c = constants_.get(k);
if (!c) {
ConstantExpr* instr = factory_.newConstantExpr(HR_const, t);
constants_.put(k, c = instr->value());
ir_->addInstrAfter(ir_->begin, instr);
}
return c;
+#endif
+ ConstantExpr* instr = factory_.newConstantExpr(HR_const, t);
+ addInstr(instr);
+ return instr->value();
}
/// Compute the types of i's defs.
///
void InstrGraphBuilder::computeType(Instr* i) {
TypeAnalyzer analyzer(ir_);
analyzer.computeTypes(i);
}
@@ -405,16 +468,17 @@ void copyAllUses(Instr* old_instr, Instr
/// Return the total number of Defs in instr.
/// TODO remove special cases once Info knows IR5
///
int numDefs(const Instr* instr) {
switch (kind(instr)) {
case HR_start:
case HR_template:
+ case HR_catchblock:
case HR_label:
return ((BlockHeaderInstr*)instr)->paramc;
case HR_arm:
return numArgs(((ArmInstr*)instr)->owner);
default:
assert(instr->info->num_defs >= 0);
return instr->info->num_defs;
}
@@ -422,16 +486,17 @@ int numDefs(const Instr* instr) {
/// Return a pointer to a contiguous array of all instr's Defs.
/// TODO remove special cases once Info knows IR5
///
Def* getDefs(const Instr* instr) {
switch (kind(instr)) {
case HR_start:
case HR_template:
+ case HR_catchblock:
case HR_label:
case HR_arm:
return ((BlockStartInstr*)instr)->params;
default:
assert(instr->info->defs_off >= 0);
return (Def*) ((char*) instr + instr->info->defs_off);
}
}
@@ -529,16 +594,17 @@ ArrayRange<ArmInstr*> armRange(CondInstr
}
/// true if instruction starts a block
///
bool isBlockStart(const Instr* instr) {
switch (kind(instr)) {
case HR_start:
case HR_template:
+ case HR_catchblock:
case HR_label:
case HR_arm:
return true;
default:
return false;
}
}
@@ -569,17 +635,17 @@ bool isCond(const Instr* instr) {
}
/// True if an instruction has root Defs, i.e. Defs whose types
/// are axiomatic. Defs introduced by ConstantExprs and
/// predecessor-free block starts have this property.
///
bool hasRootDefs(const Instr* instr) {
InstrShape s = shape(instr);
- return s == CONSTANTEXPR_SHAPE || s == STARTINSTR_SHAPE;
+ return s == CONSTANTEXPR_SHAPE || s == STARTINSTR_SHAPE || s == CATCHBLOCKINSTR_SHAPE;
}
/// true if end/start are a pair of related delimters,
/// i.e. if end is predecessor and start is successor.
///
bool isDelimPair(const Instr* end, const Instr* start) {
return ((kind(start) == HR_arm && ((ArmInstr*)start)->owner == end) ||
(kind(end) == HR_goto && ((GotoInstr*)end)->target == start));
@@ -630,29 +696,33 @@ EachBlock::EachBlock(InstrGraph* ir, boo
/// dictated by second param) of block start delimiters
/// in our blocks member variable.
///
void EachBlock::dfs(BlockStartInstr* block, bool reverse) {
if (visited.get(block->blockid))
return;
visited.set(block->blockid);
if (ir->hasBlockEnd(block)) {
- Instr* end = ir->blockEnd(block);
+ BlockEndInstr* end = ir->blockEnd(block);
InstrKind k = kind(end);
// recurse into successors
if (k == HR_goto) {
dfs(cast<GotoInstr>(end)->target, reverse);
} else if (k == HR_if || k == HR_switch) {
for (ArrayRange<ArmInstr*> r = armRange((CondInstr*)end); !r.empty();)
dfs(r.popFront(), reverse);
} else if (k == HR_return || k == HR_throw) {
// no successors
} else {
assert(false && "unsupported block-end opcode");
}
+ if (end->catch_blocks != NULL) {
+ for (CatchBlockRange r(end); !r.empty();)
+ dfs(r.popFront(), reverse);
+ }
// add to block list
if (reverse)
blocks.insert(block);
else
blocks.add(block);
}
}
@@ -677,16 +747,40 @@ void pruneGraph(InstrGraph* ir) {
GotoInstr* go = p.popFront();
if (!mark.get(go->id)) {
if (enable_verbose)
printf("prune: goto i%d ->i%d\n", go->id, instr->id);
removeGoto(go);
}
}
}
+ if (kind(instr) == HR_catchblock) {
+ CatchBlockInstr* cblock = cast<CatchBlockInstr>(instr);
+ ExceptionEdge* head = cblock->catch_preds;
+
+ for (ExceptionEdge* edge = head; edge != NULL; ) {
+ ExceptionEdge* next = edge == cblock->catch_preds->prev_exception ? NULL : edge->next_exception;
+ if (!mark.get(edge->from->id)) {
+ if (enable_verbose)
+ printf("prune: eliminated exception edge i%d -> i%d\n", edge->from->id, cblock->id);
+ if (edge->next_exception == edge) {
+ cblock->catch_preds = NULL;
+ } else {
+ ExceptionEdge* N = edge->next_exception;
+ ExceptionEdge* P = edge->prev_exception;
+ if (cblock->catch_preds == edge) {
+ head = cblock->catch_preds = N;
+ }
+ N->prev_exception = P;
+ P->next_exception = N;
+ }
+ }
+ edge = next;
+ }
+ }
}
if (ir->end && !mark.get(ir->end->id))
ir->end = 0;
if (ir->exit && !mark.get(ir->exit->id))
ir->exit = 0;
assert(checkPruned(ir));
}
--- a/halfmoon/hm-instrgraph.h
+++ b/halfmoon/hm-instrgraph.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef INSTR_GRAPH_H_
#define INSTR_GRAPH_H_
namespace halfmoon {
--- a/halfmoon/hm-interpreter.h
+++ b/halfmoon/hm-interpreter.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_INTERPRETER_H_
#define HM_INTERPRETER_H_
namespace halfmoon {
--- a/halfmoon/hm-jitmanager.cpp
+++ b/halfmoon/hm-jitmanager.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
#include "profiler/profiler-main.h"
--- a/halfmoon/hm-jitmanager.h
+++ b/halfmoon/hm-jitmanager.h
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
using profiler::MethodProfileMgr;
using profiler::MethodProfile;
--- a/halfmoon/hm-jitwriter.cpp
+++ b/halfmoon/hm-jitwriter.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -158,36 +158,37 @@ void JitWriter::analyze(AbcOpcode abcop,
if (current_block_ && pc > current_block_->start && abc_->haveBlock(pc)) {
#ifdef AVMPLUS_VERBOSE
if (enable_verbose)
console_ << "surprise\n";
#endif
abc_->analyzeEnd(current_block_, pc);
finishBlock(pc);
- newBlock(pc);
+ newBlock(pc, frame);
}
}
void JitWriter::finishBlock(const uint8_t* nextpc) {
current_block_->end = nextpc;
current_block_ = 0;
}
-void JitWriter::newBlock(const uint8_t* abc_pc) {
+void JitWriter::newBlock(const uint8_t* abc_pc, const FrameState* frame) {
if (current_block_ && current_block_->start == abc_pc) {
// we just started this block. ignore.
return;
}
current_block_ = abc_->newAbcBlock(abc_pc);
+ current_block_->start_withbase = frame->withBase;
abc_->analyzeExceptions(current_block_);
}
void JitWriter::startBlock(const FrameState* frame) {
- newBlock(frame->abc_pc);
+ newBlock(frame->abc_pc, frame);
MethodSignaturep signature = method_->getMethodSignature();
const Type** types = new (abc_->alloc0()) const Type*[signature->frame_size()];
FrameRange<const FrameValue> from = range(&frame->value(0), frame, signature);
FrameRange<const Type*> t = range(types, frame, signature);
for (; !from.empty(); from.popFront(), t.popFront())
t.front() = jit_mgr_->lattice()->makeType(from.front());
current_block_->start_types = types;
}
@@ -241,17 +242,17 @@ void JitWriter::writeOp1(const FrameStat
const uint8_t* nextpc = pc + 4;
int offset = int32_t(opd1);
if (abcop == OP_jump) {
abc_->analyzeEnd(current_block_, nextpc + offset);
finishBlock(nextpc);
} else {
abc_->analyzeBranch(current_block_, abcop, nextpc, offset);
finishBlock(nextpc);
- newBlock(nextpc);
+ newBlock(nextpc, frame);
}
}
}
void JitWriter::writeOp2(const FrameState* frame, const uint8_t *pc,
AbcOpcode abcop, uint32_t, uint32_t, Traits*) {
analyze(abcop, pc, frame);
}
--- a/halfmoon/hm-liremitter.cpp
+++ b/halfmoon/hm-liremitter.cpp
@@ -96,37 +96,137 @@ CodeList* LirHelper2::assemble(const nan
#ifdef NJ_VERBOSE
if (pool->isVerbose(LC_Liveness)) {
Allocator live_alloc;
LirReader in(frag->lastIns);
nanojit::live(&in, live_alloc, frag, &codeMgr->log);
}
#endif
- AvmAssert(halfmoon::checkLir(frag));
+ AvmAssert(halfmoon::checkLir(frag, &codeMgr->log));
Assembler *assm =
new (*lir_alloc) Assembler(codeMgr->codeAlloc, codeMgr->allocator,
*lir_alloc, &codeMgr->log, config, mdwriter);
- verbose_only( StringList asmOutput(*lir_alloc);)verbose_only(
- if (!pool->isVerbose(VB_raw)) assm->_outputCache = &asmOutput;)
+
+#ifdef AVMPLUS_VERBOSE
+ StringList asmOutput(*lir_alloc);
+ if (!pool->isVerbose(VB_raw))
+ assm->_outputCache = &asmOutput;
+#endif
+
+ assm->beginAssembly(frag);
LirReader bufreader(frag->lastIns);
- assm->beginAssembly(frag);
assm->assemble(frag, &bufreader);
CodeList* code_list = assm->endAssembly(frag);
-#ifdef NJ_VERBOSE
+#ifdef AVMPLUS_VERBOSE
assm->_outputCache = 0;
- for (Seq<char*>* p = asmOutput.get(); p != NULL; p = p->tail)
+ for (Seq<char*>* p = asmOutput.get(); p != NULL; p = p->tail) {
assm->outputf("%s", p->head);
+ }
#endif
return code_list;
}
+#ifdef AVMPLUS_ARM
+#ifdef _MSC_VER
+#define RETURN_METHOD_PTR(_class, _method) \
+return *((int*)&_method);
+#else
+#define RETURN_METHOD_PTR(_class, _method) \
+union { \
+ int (_class::*bar)(); \
+ int foo[2]; \
+}; \
+bar = _method; \
+return foo[0];
+#endif
+
+#elif defined __GNUC__
+#define RETURN_METHOD_PTR(_class, _method) \
+ union { \
+ int (_class::*bar)(); \
+ intptr_t foo; \
+ }; \
+ bar = _method; \
+ return foo;
+#else
+#define RETURN_METHOD_PTR(_class, _method) \
+ return *((intptr_t*)&_method);
+#endif
+
+#ifdef _MSC_VER
+ #if !defined (AVMPLUS_ARM) || defined(UNDER_RT)
+ extern "C"
+ {
+ int __cdecl _setjmp3(jmp_buf jmpbuf, int arg);
+ }
+ #else
+ #include <setjmp.h>
+ #undef setjmp
+ extern "C"
+ {
+ int __cdecl setjmp(jmp_buf jmpbuf);
+ }
+ #endif // AVMPLUS_ARM
+#endif // _MSC_VER
+
+#if defined _MSC_VER && !defined AVMPLUS_ARM
+# define SETJMP ((uintptr_t)_setjmp3)
+#elif defined AVMPLUS_MAC_CARBON
+# define SETJMP setjmpAddress
+#else
+# define SETJMP ((uintptr_t)VMPI_setjmpNoUnwind)
+#endif // _MSC_VER
+
+#define FUNCADDR(addr) (uintptr_t)addr
+#define EFADDR(f) efAddr((int (ExceptionFrame::*)())(&f))
+
+ intptr_t efAddr( int (ExceptionFrame::*f)() )
+ {
+ RETURN_METHOD_PTR(ExceptionFrame, f);
+ }
+
+
+ int32_t hmBeginCatch(AvmCore* core,
+ ExceptionFrame* ef,
+ MethodInfo* info,
+ intptr_t pc,
+ AnyVal* slotPtr)
+ {
+ int32_t ordinal;
+ ef->beginCatch();
+ Exception* exception = core->exceptionAddr;
+ ExceptionHandler* handler = core->findExceptionHandlerNoRethrow(info, pc, exception, &ordinal);
+ if (!handler) {
+ // No matching exception, so rethrow.
+ core->throwException(exception);
+ }
+ ef->beginTry(core);
+ slotPtr->atom = exception->atom;
+
+ return ordinal;
+ }
+
+ void hmBeginTry(ExceptionFrame* ef, AvmCore* core) {
+ ef->beginTry(core);
+ }
+ void hmEndTry(ExceptionFrame* ef) {
+ ef->endTry();
+ }
+
+ FUNCTION(FUNCADDR(hmBeginCatch), SIG5(I,P,P,P,P,P), hmBeginCatch)
+
+ FUNCTION(SETJMP, SIG2(I,P,I), fsetjmp)
+ METHOD(FUNCADDR(hmBeginTry), SIG2(V,P,P), hmBeginTry)
+ METHOD(FUNCADDR(hmEndTry), SIG1(V,P), hmEndTry)
+
+
/// Types understood by LIR. We don't use LTy here because it conflates
/// LTy_P with either LTy_I or LTy_Q, but we want to distinguish them.
enum LirModel {
kLirPtr,
kLirInt,
kLirDouble,
kLirVoid
};
@@ -219,25 +319,26 @@ LirEmitter::LirEmitter(Context* cxt, Ins
, env_param(0)
, argc_param(0)
, ap_param(0)
, loop_live_(*alloc1)
, npe_label(0)
, upe_label(0)
, interrupt_label(0)
, safepoint_space_(NULL)
-, safepoint_tags_(NULL)
-, vpc_space_(NULL)
, get_cache_builder(*alloc1, *pool->codeMgr)
, set_cache_builder(*alloc1, *pool->codeMgr)
, call_cache_builder(*alloc1, *pool->codeMgr)
, enable_verbose_lir_(enable_verbose && !enable_trace)
, profiled_info_(profiled_info)
, bailout_branches_(*alloc1)
, have_safepoints(false)
+, have_catchblocks_(false)
+, emittedBeginCatch(false)
+, catchLabels(NULL)
{
allocateTables();
}
LirEmitter::~LirEmitter() {
}
/**
@@ -436,16 +537,22 @@ void LirEmitter::analyzeLiveness() {
for (ArrayRange<ArmInstr*> a = armRange((CondInstr*)branch); !a.empty();)
analyzeEdgeLiveness(livemap, live, branch, a.popFront(), scratch,
ir->size());
break;
}
default:
break;
}
+ if (InstrGraph::blockEnd(block)->catch_blocks != NULL) {
+ for (CatchBlockRange cb(block); !cb.empty();) {
+ analyzeEdgeLiveness(livemap, live, branch, cb.popFront(), scratch,
+ ir->size());
+ }
+ }
for (InstrRange i(block); !i.empty(); i.popBack()) {
Instr* instr = i.back();
live.clear(instr->id);
for (ArrayRange<Use> a = useRange(instr); !a.empty(); a.popFront())
live.set(definerId(a.front()));
}
BlockInfo* block_info = livemap.get(block);
if (!block_info) {
@@ -494,16 +601,26 @@ void LirEmitter::allocateTables() {
// Sort all the blocks. Later passes will use this order.
sortBlocks();
// Fill in the val_offsets and dom_children arrays.
int num_defs = ir->def_count();
int max_argc = 0;
for (ArrayRange<BlockStartInstr*> b(blocks_, num_blocks_);
!b.empty(); b.popFront()) {
+
+ if (kind(b.front()) == HR_catchblock) {
+ have_catchblocks_ = true;
+ if (catchLabels == NULL) {
+ catchLabels = new (*lir_alloc) HashMap<intptr_t,CatchBlock*>(*lir_alloc, 4);
+ }
+ CatchBlockInstr* cblock = cast<CatchBlockInstr>(b.front());
+ catchLabels->put(cblock->vpc, new (*lir_alloc) CatchBlock(cblock));
+ }
+
for (InstrRange r(b.front()); !r.empty(); r.popFront()) {
max_argc = max(max_argc, numUses(r.front()));
}
}
// Table of defs, indexed by val_offsets[instr->id] + pos(def)
// DEOPT: The def_ins_ array must survive to the end of assembly.
def_ins_ = new (alloc0) LIns*[num_defs];
@@ -567,17 +684,17 @@ void LirEmitter::emitStackOverflowCheck(
* if overflow() { call handleOverflow(); }
*/
LIns* stack_overflow = lirout->insBranch(LIR_jf, compare_stack, 0);
callIns(&ci_handleStackOverflowMethodEnv, 1, env_param);
LIns* begin_label = setName(label(), "begin");
stack_overflow->setTarget(begin_label);
}
-void LirEmitter::emitBegin() {
+void LirEmitter::emitBegin(bool has_reachable_exceptions) {
#ifdef NJ_VERBOSE
bool verbose = enable_verbose_lir_ || pool->isVerbose(VB_jit);
#else
bool verbose = enable_verbose_lir_;
#endif
LirBuffer* lirbuf = createLirout(verbose, "LIR");
// add other LirWriters here.
@@ -598,16 +715,32 @@ void LirEmitter::emitBegin() {
// Create a buffer for epilog code that we can write into in parallel.
LirBuffer* epilog_buf = new (*lir_alloc) LirBuffer(*lir_alloc);
epilog_buf->abi = ABI_CDECL;
#ifdef NJ_VERBOSE
epilog_buf->printer = lirbuf->printer;
#endif
traps_lir = new (*alloc1) LirBufWriter(epilog_buf, core->config.njconfig);
traps_skip = traps_lir->insSkip(0);
+
+ // then space for the exception frame, be safe if its an init stub
+ if (has_reachable_exceptions) {
+ // [_save_eip][ExceptionFrame]
+ // offsets of local vars, rel to current ESP
+ _save_eip = stackAlloc(sizeof(intptr_t), "_save_eip");
+ _ef = stackAlloc(sizeof(ExceptionFrame), "_ef");
+ MethodSignaturep method_signature = signature;
+ int alloc_size = method_signature->frame_size();
+ safepoint_space_ = stackAlloc(alloc_size << VARSHIFT(cxt->method),
+ "deopt locals");
+ } else {
+ _save_eip = NULL;
+ _ef = NULL;
+ safepoint_space_ = NULL;
+ }
}
LIns* LirEmitter::emitConst(const Type* t) {
assert(isConst(t));
switch (kind(t)) {
default:
assert(false && "unsupported kind");
case kTypeName:
@@ -626,16 +759,18 @@ LIns* LirEmitter::emitConst(const Type*
case kTypeBoolean:
case kTypeNumber:
case kTypeScriptObject:
switch (model(t)) {
default:
assert(false && "unsupported model");
case kModelScriptObject:
return InsConstPtr(objectVal(t));
+ case kModelNamespace:
+ return InsConstPtr(nsVal(t));
case kModelString:
return InsConstPtr(stringVal(t));
case kModelAtom: {
Atom const_atom = atomVal(t, core);
// Numbers and strings can be gc allocated
// So we have to store them in the pool to keep them alive
if (AvmCore::isDouble(const_atom)) {
pool->cpool_const_double.add((GCDouble*)atomPtr(const_atom));
@@ -837,50 +972,64 @@ void LirEmitter::emitLiveHints(Instr* ta
/// Generate a LIR_label instruction for block, and give it a name.
///
LIns* LirEmitter::emitLabel(BlockStartInstr* block) {
StringBuffer name(core);
name << halfmoon::label(block) << block->id;
return setName(label(), name.c_str());
}
+LIns* LirEmitter::emitCatchLabel(CatchBlockInstr* block) {
+ StringBuffer name(core);
+ name << halfmoon::label(block) << block->id;
+ LIns* catchLabel = label();
+ CatchBlock* cb = catchLabels->get(block->vpc);
+ cb->jmp->setTarget(catchLabel);
+ return setName(catchLabel, name.c_str());
+}
+
/// Patches all points that speculate to jump to bailout point
void LirEmitter::patchBailouts() {
- LIns* bailout_label = setName(label(), "Deopt Point");
- for (SeqRange<LIns*> branches(bailout_branches_); !branches.empty();)
- branches.popFront()->setTarget(bailout_label);
+ AvmAssert(false && "Unimplemented");
- LIns* abc_pc = ldi(vpc_space_, 0, ACCSET_OTHER, LOAD_NORMAL);
-
- bool returns_double = signature->returnTraitsBT() == BUILTIN_number;
- const CallInfo* deopt_call = returns_double ?
- FUNCTIONID(fprBailout) : FUNCTIONID(gprBailout);
+ // LIns* bailout_label = setName(label(), "Deopt Point");
+ // for (SeqRange<LIns*> branches(bailout_branches_); !branches.empty();)
+ // branches.popFront()->setTarget(bailout_label);
- LIns* return_val = callIns(deopt_call, 5,
- coreAddr, env_param, abc_pc,
- safepoint_space_, safepoint_tags_);
+ // LIns* abc_pc = ldi(vpc_space_, 0, ACCSET_OTHER, LOAD_NORMAL);
+
+ // bool returns_double = signature->returnTraitsBT() == BUILTIN_number;
+ // const CallInfo* deopt_call = returns_double ?
+ // FUNCTIONID(fprBailout) : FUNCTIONID(gprBailout);
- popMethodFrame(method_frame_);
- if (returns_double)
- retd(return_val);
- else
- retp(return_val);
+ // LIns* return_val = callIns(deopt_call, 5,
+ // coreAddr, env_param, abc_pc,
+ // safepoint_space_, safepoint_tags_);
+
+ // popMethodFrame(method_frame_);
+ // if (returns_double)
+ // retd(return_val);
+ // else
+ // retp(return_val);
}
GprMethodProc LirEmitter::finish(DeoptData** deopt_data) {
if (!bailout_branches_.isEmpty())
patchBailouts();
livep(args_);
livep(coreAddr);
- if (have_safepoints) {
+ if (safepoint_space_ != NULL) {
livep(safepoint_space_);
- livep(vpc_space_);
- livep(safepoint_tags_);
- }
+ }
+ if (catchLabels != NULL) {
+ livep(_ef);
+ livep(_save_eip);
+ }
+
livep(method_frame_);
LIns* last_ins = livep(env_param);
if (npe_label || upe_label || interrupt_label) {
// Link traps lirbuf to main lirbuf.
traps_skip->initLInsSk(last_ins);
traps_lir->ins1(LIR_retp, traps_lir->insImmP(0));
traps_lir->ins1(LIR_livep, coreAddr);
@@ -928,24 +1077,46 @@ GprMethodProc LirEmitter::finish(DeoptDa
GprMethodProc LirEmitter::emit(DeoptData** deopt_data) {
#ifdef NJ_VERBOSE
if (enable_verbose_lir_) {
cxt->out << "Generate LIR " << cxt->method << "\n";
}
#endif
- emitBegin();
+ emitBegin(have_catchblocks_);
+
+ // The start block is emitted specially
+ current_block_ = 0;
+ for (InstrRange r(blocks_[0]); !r.empty(); r.popFront()) {
+ if (have_catchblocks_ && kind(r.front()) == HR_goto) {
+ // Initiailize the eip
+ stp(InsConstPtr((void*)-1), _save_eip, 0, ACCSET_OTHER);
- for (int b = 0, n = num_blocks_; b < n; ++b) {
- current_block_ = b;
- for (InstrRange r(blocks_[b]); !r.empty(); r.popFront()) {
- emit(r.front());
- }
- }
+ // _ef.beginTry(core);
+ callIns(FUNCTIONID(hmBeginTry), 2, _ef, coreAddr);
+
+ // Exception* setjmpResult = setjmp(_ef.jmpBuf);
+ // ISSUE this needs to be a cdecl call
+ LIns* jmpbuf = lea(offsetof(ExceptionFrame, jmpbuf), _ef);
+ LIns* setjmpResult = callIns(FUNCTIONID(fsetjmp), 2, jmpbuf, InsConst(0));
+
+ // If (setjmp() != 0) goto catch dispatcher, which we generate in the epilog.
+ // Note that register contents following setjmp return via longjmp are not predictable.
+ catch_branch = lirout->insBranch(LIR_jf, eqi0(setjmpResult), NULL);
+ }
+ emit(r.front());
+ }
+
+ for (int b = 1, n = num_blocks_; b < n; ++b) {
+ current_block_ = b;
+ for (InstrRange r(blocks_[b]); !r.empty(); r.popFront()) {
+ emit(r.front());
+ }
+ }
return finish(deopt_data);
}
/// Called by JIT code to trace execution of this IR instruction.
///
static void traceInstr(PrintWriter* out, Instr* instr) {
#ifdef NJ_VERBOSE
@@ -1303,17 +1474,32 @@ void LirEmitter::do_callinterface(CallSt
model(value_out_type) == defaultModelKind(interface_sig->returnTraits()));
emitStoreArgs(call->args(), call->arg_count(), interface_sig);
LIns* result = emitInterfaceAvmCall(value_out_type, callee_env,
call->arg_count(), args_, iid);
set_def_ins(call->value_out(), result);
}
+void LirEmitter::do_callstatic(CallStmt2* call) {
+ const Use& method_in = call->param_in();
+ MethodInfo* callee = getMethod(type(method_in));
+ MethodSignaturep callee_sig = callee->getMethodSignature();
+ LIns* callee_method = def_ins(method_in);
+ LIns* result = emitAvmCall(call->args(), call->arg_count(),
+ callee_sig, callee_method, call->value_out());
+ set_def_ins(call->value_out(), result);
+}
+
void LirEmitter::do_return(StopInstr* stop) {
+ if (have_catchblocks_) {
+ // _ef.endTry();
+ callIns(FUNCTIONID(hmEndTry), 1, _ef);
+ }
+
// brute force; tear down MethodFrame
popMethodFrame(method_frame_);
frag->lastIns = emitReturn(stop->value_in());
}
/// This goto is a fall-through path if it jumps to the next block in linear order.
///
bool LirEmitter::isFallthruGoto(GotoInstr* go) {
@@ -1324,33 +1510,45 @@ bool LirEmitter::isFallthruGoto(GotoInst
}
/// This label is a fall-through path if the only goto is the previous block
/// in linear order.
bool LirEmitter::isFallthruLabel(LabelInstr* label) {
assert(blocks_[current_block_] == label &&
"fallthru check on non-current block");
PredRange p(label);
- if (p.empty() || (p.popFront(), !p.empty()))
- return false; // 0 or 2+ predecessors
- GotoInstr* go = p.front();
+ if (p.empty())
+ return false; // 0 predecessors
+ GotoInstr* go = p.popFront();
+ if (!p.empty())
+ return false; // 2+ predecessors
return current_block_ > 0 &&
blocks_[current_block_ - 1] == ir->blockStart(go);
}
bool LirEmitter::enableSSE() {
#if defined AVMPLUS_AMD64
return true;
#elif defined AVMPLUS_IA32
return core->config.njconfig.i386_sse2 != 0;
#else
return false;
#endif
}
+
+// Save our current PC location for the catch finder later.
+void LirEmitter::emitSetPc(DeoptSafepointInstr* instr)
+{
+ int vpc = instr->vpc;
+ // update bytecode ip if necessary
+ stp(InsConstPtr((void*)vpc), _save_eip, 0, ACCSET_OTHER);
+}
+
+
/// BRANCH PATCHING
///
/// label/goto: do_goto() and do_label() take care of patching. Each goto
/// (except fall-thrus) generate a LIR_j (jump) and saves it; if do_label() has
/// come first, the jump is already patched. Otherwise: do_label() generates
/// a LIR_label, and patches any previously generated jumps.
///
/// arm/if: do_if() and do_arm() take care of all patching, since Arms
@@ -1429,16 +1627,103 @@ void LirEmitter::do_label(LabelInstr* in
set_def_ins(
param,
emitLoad(param_type, args_, i << VARSHIFT(cxt->method),
ACCSET_OTHER, LOAD_NORMAL));
}
}
}
+void LirEmitter::emitBeginCatch() {
+ if (emittedBeginCatch)
+ return;
+
+ if (have_catchblocks_) {
+ emittedBeginCatch = true;
+
+ // exception case
+ LIns* catch_label = setName(label(), "catch");
+
+ catch_branch->setTarget(catch_label);
+
+ // This regfence is necessary for correctness,
+ // as register contents after a longjmp are unpredictable.
+ lirout->ins0(LIR_regfence);
+
+ MethodInfo* info = cxt->method;
+
+ // _ef.beginCatch()
+ int stackBase = signature->stack_base();
+ LIns* pc = lirout->insLoad(LIR_ldp, _save_eip, 0, ACCSET_OTHER, LOAD_NORMAL);
+ LIns* slotAddr = lea(stackBase << VARSHIFT(info) , safepoint_space_);
+ LIns* handler_ordinal = callIns(FUNCTIONID(hmBeginCatch), 5, coreAddr, _ef, InsConstPtr(info), pc, slotAddr);
+
+ (void)handler_ordinal;
+
+ int handler_count = info->abc_exceptions()->exception_count;
+ // Jump to catch handler
+ // Find last handler, to optimize branches generated below.
+ int i;
+ for (i = handler_count-1; i >= 0; i--) {
+ ExceptionHandler* h = &info->abc_exceptions()->exceptions[i];
+ CatchBlock* cb = catchLabels->get(h->target);
+ if (cb != NULL) break;
+ }
+ int last_ordinal = i;
+ // There should be at least one reachable handler.
+ AvmAssert(last_ordinal >= 0);
+ // Do a compare & branch to each possible target.
+ for (int j = 0; j <= last_ordinal; j++) {
+ ExceptionHandler* h = &info->abc_exceptions()->exceptions[j];
+ CatchBlock* cb = catchLabels->get(h->target);
+ if (cb != NULL) {
+ if (j == last_ordinal) {
+ cb->jmp = lirout->insBranch(LIR_j, NULL, NULL);
+ } else {
+ LIns* cond = binaryIns(LIR_eqi, handler_ordinal, InsConst(j));
+ cb->jmp = lirout->insBranch(LIR_jt, cond, NULL);
+ }
+ }
+ }
+
+ livep(_ef);
+ livep(_save_eip);
+ livep(safepoint_space_);
+ }
+
+
+}
+
+
+void LirEmitter::do_catchblock(CatchBlockInstr* instr) {
+ emitBeginCatch();
+
+ emitCatchLabel(instr);
+
+ lirout->ins0(LIR_regfence);
+
+ int pc = instr->vpc;
+ stp(InsConstPtr((void*)pc), _save_eip, 0, ACCSET_OTHER);
+ lastPcSave = pc;
+
+ // load stuff passed by incoming gotos
+ for (int i = 0, n = instr->paramc; i < n; ++i) {
+ Def* param = &instr->params[i];
+ if (!param->isUsed())
+ continue;
+ const Type* param_type = type(param);
+ if (!isLinear(param_type) && !isState(param_type)) {
+ set_def_ins(
+ param,
+ emitLoad(param_type, safepoint_space_, i << VARSHIFT(cxt->method),
+ ACCSET_OTHER, LOAD_NORMAL));
+ }
+ }
+}
+
/// Emit a conditional branch. We optimize fall-through paths; if the taken
/// arm is the next block, then swap arms and reverse the sense
/// of the test. Then, if the not-taken arm is the next block, omit the jump.
///
/// Patching is done here and in do_arm(), depending on which is seen first for
/// each arm. See the "BRANCH PATCHING" comment.
///
void LirEmitter::do_if(IfInstr* instr) {
@@ -1774,17 +2059,32 @@ LIns* LirEmitter::emitNpeHandler() {
/** Generate one handler for all kConvertUndefinedToObjectError errors. */
LIns* LirEmitter::emitUpeHandler() {
return emitHandler(&upe_label, &ci_upe);
}
/** Generate one handler for all timeout interrupts */
LIns* LirEmitter::emitInterruptHandler() {
- return emitHandler(&interrupt_label, &ci_handleInterruptMethodEnv);
+ if (interrupt_label == NULL) {
+ LIns* args[] = { env_param };
+ interrupt_label = traps_lir->ins0(LIR_label);
+
+#ifdef VMCFG_INTERRUPT_SAFEPOINT_POLL
+ traps_lir->ins0(LIR_pushstate);
+#endif
+ traps_lir->ins0(LIR_regfence);
+ traps_lir->insCall(&ci_handleInterruptMethodEnv, args);
+#ifdef VMCFG_INTERRUPT_SAFEPOINT_POLL
+ traps_lir->ins0(LIR_popstate);
+ traps_lir->ins0(LIR_restorepc);
+#endif
+
+ }
+ return interrupt_label;
}
void LirEmitter::do_cknull(UnaryStmt* instr) {
const Use& value_in = instr->value_in();
LIns* ptr = def_ins(value_in);
LIns* undefined_ins = InsConstAtom(undefinedAtom);
lirout->insBranch(LIR_jt, ltup(ptr, undefined_ins), emitNpeHandler());
lirout->insBranch(LIR_jt, eqp(ptr, undefined_ins), emitUpeHandler());
@@ -1797,21 +2097,28 @@ void LirEmitter::do_cknullobject(UnarySt
lirout->insBranch(LIR_jt, eqp0(ptr), emitNpeHandler());
set_def_ins(instr->value_out(), ptr);
}
void LirEmitter::do_cktimeout(UnaryStmt* instr) {
// Omit timeout checks if they are turned off. We don't do this further
// upstream, because it can cause the graph to have no endpoints, if there
// is an infinite loop.
- if (core->config.interrupts) {
+#ifdef VMCFG_INTERRUPT_SAFEPOINT_POLL
+ bool check_interrupt = true;
+#else
+ bool check_interrupt = core->config.interrupts;
+#endif
+ if (check_interrupt) {
+ lirout->ins0(LIR_savepc);
LIns* interrupted = ldi(coreAddr, JitFriend::core_interrupted_offset,
ACCSET_OTHER, LOAD_VOLATILE);
LIns* cond = eqi(interrupted, AvmCore::NotInterrupted);
lirout->insBranch(LIR_jf, cond, emitInterruptHandler());
+ lirout->ins0(LIR_discardpc);
}
set_def_ins(instr->value_out(), InsConst(0)); // always return false.
}
void LirEmitter::do_doubletoint32(UnaryExpr* instr) {
LIns* arg = def_ins(instr->value_in());
LIns* result;
@@ -1955,46 +2262,33 @@ void LirEmitter::emitHelperCall2(UnaryEx
LIns* result = callIns(call, 2, coreAddr, def_ins(value_in));
set_def_ins(instr->value_out(), result);
}
/// Newstate allocates space on the stack for safepoints
/// Currently assumes newstate occurs in the entry block prior to any safepoint
/// or setlocal instructions.
void LirEmitter::do_newstate(ConstantExpr* instr) {
- MethodSignaturep method_signature = signature;
- int alloc_size = method_signature->frame_size();
- assert (safepoint_space_ == NULL);
- assert (safepoint_tags_ == NULL);
-
- vpc_space_ = stackAlloc(sizeof(int), "safepoint abc pc");
- safepoint_space_ = stackAlloc(alloc_size << VARSHIFT(cxt->method),
- "deopt locals");
- safepoint_tags_ = stackAlloc(alloc_size * sizeof(SlotStorageType),
- "deopt tags");
- set_def_ins(instr->value(), safepoint_space_);
- have_safepoints = true;
+ if (safepoint_space_ != NULL) {
+ set_def_ins(instr->value(), safepoint_space_);
+ }
}
/// Saves the ABC local var, which also represents ABC operand stack values
/// Stores the local in its native format + type tag. Hopefully
/// NanoJIT removes the tag stores
void LirEmitter::do_setlocal(SetlocalInstr* instr) {
set_def_ins(instr->state_out(), def_ins(instr->state_in()));
assert (safepoint_space_ != NULL);
int stackIndex = instr->index;
emitStore(instr->value_in(), type(instr->value_in()),
safepoint_space_, stackIndex << VARSHIFT(cxt->method),
ACCSET_STORE_ANY);
set_def_ins(instr->state_out(), def_ins(instr->state_in()));
- LIns* sst_model = InsConst(type2sst(type(instr->value_in())));
- sti(sst_model, safepoint_tags_,
- stackIndex * sizeof(int32_t), ACCSET_STORE_ANY);
-
/// This is really ugly, to directly access J2.
/// Still contemplating if we should make
/// deoptGenerator a class or something and make it
/// walk through the halfmoon IR. Seems overkill for now. Defer
/// but don't let this stay - Mason
/// can't put in abcbuilder because type analysis may specialize downstream
JitManager* jit = JitManager::init(this->pool);
BailoutData* metaData = jit->ensureMethodData(cxt->method)->bailout_data;
@@ -2002,25 +2296,25 @@ void LirEmitter::do_setlocal(SetlocalIns
metaData->setNativeType(stackIndex, type2sst(type(instr->value_in())));
}
/// Generates LIR for a safepoint instruction
/// Any safepoint instr that gets here cannot be optimized away
/// Stores the abc pc, setlocals store the actual data prior to this safepoint
void LirEmitter::do_safepoint(SafepointInstr* instr) {
assert (safepoint_space_ != NULL);
- int offset = 0;
- int abc_pc = instr->vpc;
- sti(InsConst(abc_pc), vpc_space_, offset, ACCSET_STORE_ANY);
+ int vpc = instr->vpc;
+ // update bytecode ip
+ stp(InsConstPtr((void*)vpc), _save_eip, 0, ACCSET_OTHER);
/// See do_setlocal for why we grab metadata here
JitManager* jit = JitManager::init(this->pool);
BailoutData* metaData = jit->ensureMethodData(cxt->method)->bailout_data;
assert (metaData != NULL);
- metaData->do_safepoint(abc_pc, instr->scopep, instr->sp);
+ metaData->do_safepoint(vpc, instr->scopep, instr->sp);
}
// DEOPT
void LirEmitter::do_deopt_safepoint(DeoptSafepointInstr* instr) {
lirout->insSafe(LIR_safe, (void*)instr);
}
// DEOPT
--- a/halfmoon/hm-liremitter.h
+++ b/halfmoon/hm-liremitter.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
using avmplus::CacheBuilder;
using avmplus::CallCache;
using avmplus::GetCache;
@@ -98,22 +98,24 @@ public: // ADAPTER impl
void do_const(ConstantExpr*);
// fixme: re-implement-this using finddef_cache void do_abc_finddef(BinaryStmt*);
void do_loadenv(BinaryExpr*);
void do_loadinitenv(UnaryExpr*);
void do_loadsuperinitenv(UnaryExpr*);
void do_loadenv_interface(BinaryExpr*);
void do_callmethod(CallStmt2*);
void do_callinterface(CallStmt2*);
+ void do_callstatic(CallStmt2*);
void do_newinstance(UnaryExpr*);
void do_return(StopInstr*);
void do_arm(ArmInstr*);
void do_label(LabelInstr*);
void do_goto(GotoInstr*);
void do_if(IfInstr*);
+ void do_catchblock(CatchBlockInstr*);
void do_setslot(CallStmt2*);
void do_abc_setprop(CallStmt2*);
void do_abc_callprop(CallStmt2*);
void do_addd(BinaryExpr* i) { doBinaryInstr(i, LIR_addd); }
void do_subd(BinaryExpr* i) { doBinaryInstr(i, LIR_subd); }
void do_muld(BinaryExpr* i) { doBinaryInstr(i, LIR_muld); }
void do_modulo(BinaryExpr*);
void do_divd(BinaryExpr* i) { doBinaryInstr(i, LIR_divd); }
@@ -218,36 +220,38 @@ private:
LIns* emitStore(const Use& value, const Type* constraint, LIns* ptr,
int32_t offset, AccSet);
LIns* emitReturn(const Use& value);
LIns* emitNpeHandler();
LIns* emitUpeHandler();
LIns* emitInterruptHandler();
LIns* emitHandler(LIns** label, const CallInfo* call);
LIns* emitLabel(BlockStartInstr*);
+ LIns* emitCatchLabel(CatchBlockInstr*);
void emitHelperCall2(UnaryExpr*, const CallInfo* call);
void emitLiveHints(Instr* target);
void emitLive(Def*);
void emitStackOverflowCheck();
- void emitBegin();
+ void emitBegin(bool has_reachable_exceptions);
void emitInitializers(Def* object);
void emitStopFence(BlockStartInstr*);
private:
// other helpers
void allocateTables();
void printInstr(Instr*);
void sortBlocks();
void analyzeLiveness();
void patchBailouts();
bool isFallthruGoto(GotoInstr*);
bool isFallthruBranch(ArmInstr*);
bool isFallthruArm(ArmInstr*);
bool isFallthruLabel(LabelInstr*);
bool enableSSE();
+ void emitSetPc(DeoptSafepointInstr* instr);
private:
// helpers to access LIns* associated with each Def*
LIns* set_def_ins(Def* d, LIns* ins);
LIns* set_ins(Instr*, LIns* ins);
LIns* def_ins(const Def*);
LIns* def_ins(const Use&);
LIns* ins(Instr*);
@@ -270,26 +274,46 @@ private:
int max_argc_;
LoopLiveMap loop_live_; // List of live Instrs for each loop header block.
LirWriter* traps_lir; // Writer for emitting trap handlers.
LIns* traps_skip; // LIR_skip that links traps block to main code buffer.
LIns* npe_label; // label to jump to for null pointer exceptions.
LIns* upe_label; // label to jump to for undefined pointer exceptions.
LIns* interrupt_label; // label for interrupt checks.
LIns* safepoint_space_; // space to store safepoint data.
- LIns* safepoint_tags_; // space to store safepoint tags
- LIns* vpc_space_; // space to store abc pc
CacheBuilder<GetCache> get_cache_builder;
CacheBuilder<SetCache> set_cache_builder;
CacheBuilder<CallCache> call_cache_builder;
const bool enable_verbose_lir_;
ProfiledInformation* profiled_info_;
SeqBuilder<LIns*> bailout_branches_;
bool have_safepoints;
bool have_loop_;
+ bool have_catchblocks_;
+ bool emittedBeginCatch;
+ LIns *_save_eip, *_ef;
+ const uint8_t* code_pos;
+
+ class CatchBlock {
+ public:
+ CatchBlockInstr* block;
+ LIns* jmp;
+ CatchBlock(CatchBlockInstr* b): block(b), jmp(NULL) {}
+ };
+
+ // This should really be int but gcc-4.2.1 on Mac sometimes screws
+ // up lookups when it's int.
+ HashMap<intptr_t, CatchBlock*> *catchLabels;
+
+ LIns* catch_branch;
+ int lastPcSave;
+
private:
static bool haveStub(InstrKind);
static const CallInfo lir_table[]; // callinfos for each stub
static const int stub_fixc[]; // fixed arg count for each stub
+
+ void emitBeginCatch();
+ void emitBeginTry();
};
}
--- a/halfmoon/hm-main.cpp
+++ b/halfmoon/hm-main.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
#include "profiler/profiler-main.h"
@@ -22,17 +22,18 @@ int enable_gml = 0;
int enable_inline = 0;
int enable_mode = 0; // disabled by default, use -Dhalfmoon or env var
int enable_optional = 1;
int enable_peephole = 0;
int enable_printir = 0;
int enable_profiler = 0;
int enable_selftest = 0;
int enable_trace = 0;
-int enable_try = 0;
+int enable_try = 1;
+int enable_framestate = 0;
int enable_typecheck = 0;
int enable_verbose = 0;
int enable_vmstate = 0;
int enable_welcome = 0;
ScheduleKind enable_schedule = kScheduleMiddle;
void init() {
static bool first = true;
@@ -48,16 +49,17 @@ void init() {
enable_mode = parseEnv("MODE", enable_mode);
enable_optional = parseEnv("OPTIONAL", enable_optional);
enable_peephole = parseEnv("PEEPHOLE", enable_peephole);
enable_printir = parseEnv("PRINTIR", enable_printir);
enable_profiler = parseEnv("PROFILER", enable_profiler);
enable_selftest = parseEnv("SELFTEST", enable_selftest);
enable_trace = parseEnv("TRACE", enable_trace);
enable_try = parseEnv("TRY", enable_try);
+ enable_framestate = parseEnv("FRAMESTATE", enable_framestate);
enable_typecheck = parseEnv("TYPECHECK", enable_typecheck);
enable_verbose = parseEnv("VERBOSE", enable_verbose);
enable_vmstate = parseEnv("VMSTATE", enable_vmstate);
enable_welcome = parseEnv("WELCOME", enable_welcome);
enable_schedule = (ScheduleKind)parseEnv("SCHEDULE", enable_schedule);
debugInit();
@@ -139,46 +141,42 @@ void AbcRange::read() {
pc = next;
uint32_t imm30, imm30b;
int32_t imm24, imm8;
AvmCore::readOperands(next, imm30, imm24, imm30b, imm8);
if (*pc == OP_lookupswitch)
next += 3 * (imm30b + 1);
}
-bool hasWith(MethodInfo* m) {
- AbcRange r(m);
- AbcRange r2 = find(r, OP_pushwith);
- return !r2.empty();
-}
-
bool canCompile(MethodInfo* m) {
init();
if (enable_mode == kModeNone)
return false;
#ifdef VMCFG_DEBUGGER
if (m->pool()->core->debugger())
return false; // Cannot compile debuggable functions.
#endif
- if (m->isNative())
+ if (m->isNative()) {
return false;
+ }
if (!enable_builtins && m->pool()->isBuiltin)
return false; // Ignore builtin code.
if (!enable_try && m->hasExceptions())
return false; // Ignore methods with exceptions.
- if (m->method_id() < 0)
+ if (m->method_id() < 0) {
return false; // Ignore vm-created initializer methods.
- if (m->needArguments())
+ }
+ if (m->needArguments()) {
return false; // Only rest args supported yet.
- if (!enable_optional && m->hasOptional())
+ }
+ if (!enable_optional && m->hasOptional()) {
return false;
- if (hasWith(m))
- return false; // OP_pushwith not yet supported.
+ }
if (enable_profiler) {
MethodProfile* profile = JitManager::getProfile(m);
if (!profile || (!profile->hasBailedOut() && !profile->hasGatheredAllData()))
return false;
}
return true;
@@ -267,16 +265,17 @@ void computeIdentities(InstrGraph* ir) {
for (ArrayRange<Def> d = defRange(instr); !d.empty();) {
Def* d1 = &d.popFront();
if (!d1->isUsed())
continue;
Def* d2 = peephole(d1, ir, &factory);
if (k == HR_arm && d1 == d2)
d2 = unsplit(cast<ArmInstr>(instr), d1, &marks);
if (d1 != d2) {
+ assert(subtypeof(type(d2), type(d1)));
copyUses(d1, d2);
changed = true;
}
}
}
} while (changed);
assert(checkPruned(ir) && checkSSA(ir));
}
@@ -497,35 +496,38 @@ void optimize(Context* cxt, InstrGraph*
}
}
/**
* Do a depth-first traversal starting from the given block, inserting
* finished blocks in list, so list ends up in reverse postorder. Visit either
* all edges or only normal edges, depending on visit_all param.
*/
-static void dfs(AbcBlock* b, int& post_id, SeqBuilder<AbcBlock*> &list,
- bool visit_all) {
+static void dfs(AbcBlock* b, int& post_id, bool& has_reachable_exceptions, SeqBuilder<AbcBlock*> &list,
+ bool visit_all) {
b->post_id = -1;
// visit ordinary successors.
for (int i = 0, n = b->num_succ_blocks; i < n; ++i) {
AbcBlock* succ = b->succ_blocks[i];
if (!succ->post_id)
- dfs(succ, post_id, list, visit_all);
+ dfs(succ, post_id, has_reachable_exceptions, list, visit_all);
else if (succ->post_id == -1)
succ->dfs_loop = true;
}
if (visit_all) {
// visit catch blocks reachable from this block.
for (int i = 0, n = b->max_catch_blocks; i < n; ++i) {
AbcBlock* succ = b->catch_blocks[i];
if (!succ)
continue;
+ if (succ->start_types == NULL) // Unreachable catch block
+ continue;
+ has_reachable_exceptions = true;
if (!succ->post_id)
- dfs(succ, post_id, list, visit_all);
+ dfs(succ, post_id, has_reachable_exceptions, list, visit_all);
else if (succ->post_id == -1)
succ->dfs_loop = true;
}
}
b->post_id = ++post_id;
list.insert(b);
}
@@ -535,21 +537,22 @@ InstrGraph* parseAbc(MethodInfo* method,
Allocator& ir_alloc, AbcGraph* abc, Toplevel *toplevel,
AbcEnv *abc_env, ProfiledInformation* profiled_info,
Context &cxt) {
(void)abc_env; //TODO: change protocol of parseAbc
// First, sort AbcBlocks in reverse postorder.
Allocator scratch;
SeqBuilder<AbcBlock*> list(scratch);
int post_id = 0;
- dfs(abc->entry(), post_id, list, false);
+ bool has_reachable_exceptions = false;
+ dfs(abc->entry(), post_id, has_reachable_exceptions, list, true);
// Then visit the AbcBlocks and build an InstrGraph.
InstrFactory factory(ir_alloc, lattice, infos);
- AbcBuilder builder(method, abc, &factory, toplevel, profiled_info);
+ AbcBuilder builder(method, abc, &factory, toplevel, profiled_info, has_reachable_exceptions);
InstrGraph* ir = builder.visitBlocks(list.get());
if (enable_gml)
printAbcCfg(method, list.get(), ir, "0-abc");
#ifdef DEBUG
if (enable_verbose) {
--- a/halfmoon/hm-main.h
+++ b/halfmoon/hm-main.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//
// This is the main header file for the compiler implementation.
//
@@ -49,27 +49,29 @@ class ConstantExpr;
class VoidStmt;
class SafepointInstr;
class DeoptSafepointInstr; // DEOPT
class DeoptFinishInstr; // DEOPT
class DeoptFinishCallInstr; // DEOPT
class SetlocalInstr;
class UnaryExpr;
class UnaryStmt;
+class DebugInstr;
// CFG-related Instrs
class BlockStartInstr;
class ArmInstr;
class LabelInstr;
class BlockEndInstr;
class CondInstr;
class IfInstr;
class SwitchInstr;
class GotoInstr;
class StartInstr;
+class CatchBlockInstr;
class StopInstr;
}
namespace profiler {
class MethodProfile;
class MethodProfileMgr;
}
@@ -199,16 +201,17 @@ void init();
// Configuration.
extern int enable_welcome; // Print welcome and options.
extern int enable_verbose; // Generate verbose output.
extern int enable_peephole; // Enable ABC peephole optimizer.
extern int enable_gml; // Enable GML graph output.
extern int enable_vmstate; // Always generate Safepoint instructions.
extern int enable_builtins; // Optimize builtins too.
extern int enable_try; // Enable optimizing try/catch functions.
+extern int enable_framestate; // Print the frame state during parsing of abc
extern int enable_printir; // Enable printing of final IR
extern int enable_mode; // Which execution mode.
extern int enable_trace; // Enable execution trace.
extern int enable_inline; // Enable inline optimization.
extern int enable_profiler; // Enable runtime profiling
extern int enable_typecheck; // Enable type-check verbosity.
extern int enable_optional; // Enable optional argument support.
--- a/halfmoon/hm-models.cpp
+++ b/halfmoon/hm-models.cpp
@@ -84,16 +84,18 @@ InstrKind toModelScriptobject(const Type
}
InstrKind toModelKind(const Type* val_type, const Type* use_type) {
switch (model(use_type)) {
default:
printf("unknown conversion %s -> %s\n", typeName(val_type),
typeName(use_type));
assert(false && "bad model");
+ case kModelNamespace:
+ return HR_atom2ns;
case kModelAtom:
return toModelAtom(val_type);
case kModelScriptObject:
return toModelScriptobject(val_type);
case kModelString:
return HR_atom2string;
case kModelInt:
return toModelInt(val_type, use_type);
@@ -149,42 +151,50 @@ void ModelFixer::changeOps() {
}
}
/**
* Insert model conversions after defs, where needed. If multiple uses
* need to use the same converted def, reuse the conversion instruction.
*/
void ModelFixer::fixDefs() {
- Def* converts[kModelMAX]; // space to memoize one conversion per ModelKind.
+ const int kConvertsMax = 4;
+ Def* converts[kConvertsMax]; // space to memoize one conversion per ModelKind.
+ InstrKind converts_kind[kConvertsMax]; // verify that the conversion is the same
for (PostorderBlockRange b(ir_); !b.empty();) {
for (InstrRange i(b.popFront()); !i.empty();) {
Instr* instr = i.popBack();
SigRange sr = outputSigRange(instr);
for (ArrayRange<Def> dr = defRange(instr); !dr.empty(); sr.popFront()) {
Def* d = &dr.popFront();
- int have_mask = 0; // mask: 1 << ModelKind
+ int have_count = 0;
const Type* def_type = type(d);
const Type* sig_type = sr.front();
if (isBottom(def_type))
def_type = sig_type;
for (UseRange u(*d); !u.empty(); ) {
Use& use = u.popFront();
const Type* constraint = getConstraint(use);
if (!submodelof(def_type, constraint)) {
- // need a conversion
- ModelKind need = model(constraint);
- if (!(have_mask & (1 << need))) {
- InstrKind convert_kind = toModelKind(def_type, constraint);
+ // need a conversion. The same model may require different conversions
+ InstrKind convert_kind = toModelKind(def_type, constraint);
+ int h = 0;
+ for (; h < have_count; h++) {
+ if (converts_kind[h] == convert_kind)
+ break;
+ }
+ if (h >= have_count) {
UnaryExpr* expr = factory_.newUnaryExpr(convert_kind, d);
ir_->addInstrAfter(instr, expr);
- converts[need] = expr->value_out();
- have_mask |= (1 << need);
+ converts[h] = expr->value_out();
+ converts_kind[h] = convert_kind;
+ have_count++;
+ assert(have_count <= kConvertsMax);
}
- use = converts[need];
+ use = converts[h];
}
}
}
}
}
}
/// Return the constraint for this use. Instructions that have Any or
@@ -209,28 +219,26 @@ const Type* ModelFixer::getConstraint(co
CallStmt2* setslot = cast<CallStmt2>(instr);
const Type* obj_type = type(setslot->object_in());
int slot = ordinalVal(type(setslot->param_in()));
return ir_->lattice.getSlotType(obj_type, slot);
}
break;
case HR_callinterface:
case HR_callmethod:
+ case HR_callstatic:
if (use_pos >= 2) {
CallStmt2* call = cast<CallStmt2>(instr);
const Type* env_type = type(call->param_in());
if (isEnv(env_type)) {
MethodSignaturep sig = getMethod(type(call->param_in()))->getMethodSignature();
return ir_->lattice.makeParamType(use_pos - 2, sig);
}
}
break;
- case HR_callstatic:
- assert(false && "custom signature not implemented");
- break;
case HR_return:
if (use_pos == 1) {
// return type is based on method signature
MethodSignaturep sig = cxt_->method->getMethodSignature();
return ir_->lattice.makeType(sig->returnTraits());
}
break;
}
--- a/halfmoon/hm-models.h
+++ b/halfmoon/hm-models.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_MODELS_H_
#define HM_MODELS_H_
namespace halfmoon {
--- a/halfmoon/hm-prettyprint.cpp
+++ b/halfmoon/hm-prettyprint.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -535,16 +535,31 @@ void printTerseInstrList(InstrRange list
i = list.front();
console << "," << kInstrPrefix << i->id << "-" << name(i);
if (limit++ > 100)
console << "printTerseInstrList limit reached";
}
console << "]\n";
}
+PrintWriter& printUsers(PrintWriter& console, Instr* instr) {
+ printInstr(console, instr);
+
+ // Print instructions that use any def of this instruction.
+ for (AllUsesRange uses(instr); !uses.empty(); uses.popFront()) {
+ printInstr(console, user(uses.front()));
+ }
+ return console;
+}
+
+void printUsers(Instr* instr) {
+ printUsers(avmplus::AvmCore::getActiveCore()->console, instr);
+}
+
+
PrintWriter& printInstr(PrintWriter& console, Instr* instr) {
char namebuf[80];
sprintf(namebuf, " %s%-3d %-18.18s ", kInstrPrefix, instr->id, name(instr));
console << namebuf;
print(console, instr);
// Print signature of this instruction: (uses) -> (defs)
console << "(";
@@ -566,16 +581,36 @@ PrintWriter& printInstr(PrintWriter& con
if (!uses.empty()) {
console << " <= " << kInstrPrefix << user(uses.front())->id;
while (uses.popFront(), !uses.empty())
console << "," << kInstrPrefix << user(uses.front())->id;
}
return console << "\n";
}
+void printInstr(Instr* instr) {
+ printInstr(avmplus::AvmCore::getActiveCore()->console, instr);
+}
+
+PrintWriter& printPhi(PrintWriter& console, LabelInstr* label, int index) {
+ Def* d = &label->params[index];
+ for (LabelArgRange r(label, index); !r.empty(); r.popFront()) {
+ if (def(r.front()) != d) { // ignore self.
+ printDef(def(r.front())); console << " ";
+ printInstr(user(r.front())); console << "\n";
+ }
+ }
+ printInstr(label);
+ return console;
+}
+
+void printPhi(LabelInstr* label, int index) {
+ printPhi(avmplus::AvmCore::getActiveCore()->console, label, index);
+}
+
PrintWriter& printCompactInstr(PrintWriter& console, Instr* instr,
bool print_defs) {
char namebuf[80];
sprintf(namebuf, " %s%-3d %-18.18s ", kInstrPrefix, instr->id,
name(instr));
console << namebuf;
print(console, instr);
if (kind(instr) == HR_const) {
@@ -590,16 +625,22 @@ PrintWriter& printCompactInstr(PrintWrit
if (print_defs)
for (ArrayRange<Def> d = defRange(instr); !d.empty(); d.popFront())
//if (!isEffect(type(d.front())) && !isBottom(type(d.front())))
console << typeName(d.front()) << delim(d);
}
return console << "\n";
}
+void printCompactInstr(Instr* instr,
+ bool print_defs) {
+ printCompactInstr(avmplus::AvmCore::getActiveCore()->console, instr, print_defs);
+}
+
+
const char* label(BlockStartInstr* b) {
return kind(b) == HR_label ? kJoinPrefix : kBlockPrefix;
}
BlockStartInstr* idom(BlockStartInstr* b, DominatorTree* doms) {
return doms->hasIDom(b) ? doms->idom(b) : 0;
}
@@ -622,16 +663,20 @@ void listCfg(PrintWriter& console, Instr
console << label(r.front()) << r.front()->blockid << delim(r);
console << "} rdom={";
for (BlockStartInstr* dom = idom(block, rdoms); dom != 0; dom = idom(dom, rdoms))
console << label(dom) << dom->blockid << (rdoms->hasIDom(dom) ? "," : "");
console << "} rdf={";
for (SeqRange<BlockStartInstr*> r(rdoms->df(block)); !r.empty(); r.popFront())
console << label(r.front()) << r.front()->blockid << delim(r);
console << "}\n";
+ if (kind(block) == HR_catchblock) {
+ ((CatchBlockInstr*)block)->printCatchPreds();
+ }
+
for (InstrRange j(block); !j.empty(); j.popFront(), ++instr_count)
printInstr(console, j.front());
}
console << "=== IR end size=" << ir->instr_count() <<
" actual=" << instr_count << " ===\n\n";
#else
(void) console;
(void) ir;
@@ -672,16 +717,21 @@ void printAbcInstr(MethodInfo* m, PrintW
console << "\n";
}
void printDef(PrintWriter& out, const Def* d) {
out << kDefPrefix << definerId(d);
printDef(out, *d);
}
+void printDef(const Def* d) {
+ printDef(avmplus::AvmCore::getActiveCore()->console, d);
+ fflush(stdout);
+}
+
class PrintAdapter: public ShapeAdapter<PrintAdapter, void> {
public:
explicit PrintAdapter(PrintWriter& out) : out_(out) {
}
void do_default(Instr* /* instr */) {
}
@@ -736,17 +786,18 @@ class PrintDefAdapter: public ShapeAdapt
void do_LabelInstr(LabelInstr*) { doParam(); }
void do_ArmInstr(ArmInstr*) { doParam(); }
void do_UnaryStmt(UnaryStmt*) { doStmt(); }
void do_BinaryStmt(BinaryStmt*) { doStmt(); }
void do_CallStmt1(CallStmt1*) { doStmt(); }
void do_CallStmt2(CallStmt2*) { doStmt(); }
void do_CallStmt3(CallStmt3*) { doStmt(); }
void do_CallStmt4(CallStmt4*) { doStmt(); }
- void do_NaryStmt(NaryStmt0*) { doStmt(); }
+ void do_NaryStmt0(NaryStmt0*) { doStmt(); }
+ void do_NaryStmt2(NaryStmt2*) { doStmt(); }
void do_Hasnext2Stmt(Hasnext2Stmt*) {
static const char* names[] = { "effect", "value", "counter", "object" };
out << names[pos(d)];
}
private:
void doParam() {
@@ -764,16 +815,20 @@ class PrintDefAdapter: public ShapeAdapt
const Def& d;
};
void printDef(PrintWriter& out, const Def& d) {
PrintDefAdapter a(out, d);
do_shape(&a, definer(d));
}
+void printDef(const Def& d) {
+ printDef(avmplus::AvmCore::getActiveCore()->console, d);
+}
+
const char* name(Instr* instr) {
return name(*instr);
}
const char* name(Instr& instr) {
return instr.info->name();
}
@@ -801,12 +856,39 @@ void printLirCfg(MethodInfo* method, Fra
LirReader reader(frag->lastIns);
CfgLister lister(&reader, alloc, CfgLister::CFG_BB);
for (LIns* ins = lister.read(); !ins->isop(LIR_start); ins = lister.read()) {
}
lister.printGmlCfg(f, frag->lirbuf->printer, &ignore);
fclose(f);
}
+
+ void printString(Stringp string) {
+ StUTF8String buf(string);
+ fputs(buf.c_str(), stdout);
+ // flush in case debugger output is interleaved with process output
+ fflush(stdout);
+ }
+
+ void printAtom(Atom atom) {
+ StringBuffer buf(avmplus::AvmCore::getActiveCore());
+ buf.writeAtom(atom);
+ fputs(buf.c_str(), stdout);
+ // flush in case debugger output is interleaved with process output
+ fflush(stdout);
+ }
+
+ void printMethod(MethodInfo* info) {
+ String* name = info->getMethodName();
+ if (!name) return;
+ StUTF8String buf(info->getMethodName());
+ fputs(buf.c_str(), stdout);
+ // flush in case debugger output is interleaved with process output
+ fflush(stdout);
+ }
+
+
+
#endif
} // namespace avmplus
#endif // VMCFG_HALFMOON
--- a/halfmoon/hm-prettyprint.h
+++ b/halfmoon/hm-prettyprint.h
@@ -1,26 +1,28 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_PRETTYPRINT_H_
#define HM_PRETTYPRINT_H_
namespace halfmoon {
/// Print the details of one instruction.
///
PrintWriter& printInstr(PrintWriter&, Instr*);
+void printInstr(Instr*);
/// Print the brief essentials of one instruction.
///
PrintWriter& printCompactInstr(PrintWriter&, Instr*, bool print_defs = true);
+void printCompactInstr(Instr*, bool print_defs = true);
/**
* Print list of instructions in detail.
* @param list head of list of instructions.
* @param ir instruction graph
* @param title legend printed at head of list.
* A correctly formed list is circular and the end of the list (and printout) is when the next instruction
* points back at the list head. To prevent debug code from looping when confronted with incorrect lists there
@@ -84,20 +86,22 @@ extern const char* kBlockPrefix; // P
extern const char* kLoopPrefix; // Prefix for a loop header.
extern const char* kJoinPrefix; // Prefix for a non-loop merge block.
extern const char* kInstrPrefix; // Prefix for an instruction.
extern const char* kDefPrefix; // Prefix for a def.
/// Print the def as kDefPrefix + owner->id + field name.
///
void printDef(PrintWriter& out, const Def* def);
+void printDef(const Def* def);
/// Print just the name of the def. fixme: field is a historical term, change it.
///
void printDef(PrintWriter& out, const Def& ref);
+void printDef(const Def& ref);
/// Return the pretty-print name of this instruction's opcode.
///
const char* name(Instr*);
const char* name(Instr&);
/// Return the name of this Def's type.
///
--- a/halfmoon/hm-profiler.cpp
+++ b/halfmoon/hm-profiler.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-profiler.h
+++ b/halfmoon/hm-profiler.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef OPT_PROFILER_HH
#define OPT_PROFILER_HH
namespace halfmoon {
--- a/halfmoon/hm-schedulers.cpp
+++ b/halfmoon/hm-schedulers.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-schedulers.h
+++ b/halfmoon/hm-schedulers.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SCHEDULERS_H_
#define SCHEDULERS_H_
namespace halfmoon {
--- a/halfmoon/hm-specializer.cpp
+++ b/halfmoon/hm-specializer.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -136,29 +136,35 @@ Def* matchUnaryExpr(const Use& v, InstrK
/// Helper: if definer of v is a UnaryExpr k(x), return x
///
Def* matchUnaryExpr(const Use& v, InstrKind k) {
assert(InstrFactory::isUnaryExpr(k));
Instr* i = definer(v);
return kind(i) == k ? def(cast<UnaryExpr>(i)->value_in()) : 0;
}
-ScopeKind findScope(Lattice* lattice_, NaryStmt2* instr, int* index_) {
+ScopeKind findScope(Lattice* lattice_, NaryStmt3* instr, int* index_) {
assert(kind(instr) == HR_abc_findproperty ||
kind(instr) == HR_abc_findpropstrict);
const Type* name_type = type(instr->name_in());
assert(isConst(name_type) && isName(name_type));
int scope_count = instr->vararg_count();
Def* env = def(instr->env_in());
const Use* scopes = instr->varargs();
MethodInfo* caller_method = getMethod(type(env));
PoolObject* pool = caller_method->pool();
if (!nameVal(name_type)->isBinding())
return kScopeNotFound; // not an ordinary known lexical name.
+ // Don't short circuit dynamic lookups
+ assert(isOrdinal(type(instr->index_in())));
+ int withbase = ordinalVal(type(instr->index_in()));
+ if (withbase != -1)
+ return kScopeNotFound;
+
// Search local scopes.
const ScopeTypeChain* scope = caller_method->declaringScope();
int base = (scope->size == 0) ? 1 : 0; // Don't try to early bind to global.
for (int index = scope_count - 1; index >= base; --index) {
Binding b = lattice_->toBinding(type(scopes[index]), name_type);
if (isValidBinding(b))
return (*index_ = index), kScopeLocal;
if (false /* fixme: if is with scope */)
@@ -518,30 +524,35 @@ void Specializer::do_construct(CallStmt2
def(instr->arg(i)));
CallStmt2* call = factory_.newCallStmt2(HR_callmethod, builder.effect(),
env, object, arg_count - 1, args + 1);
builder.addStmt(call);
connectUsesToDef(*instr->value_out(), object);
connectUsesToDef(*instr->effect_out(), call->effect_out());
}
-void Specializer::doFindStmt(NaryStmt2* instr) {
+void Specializer::doFindStmt(NaryStmt3* instr) {
+ (void)instr;
+#if 0
+ // Can't in place replace an NaryStmt2 with a BinaryStmt, so just
+ // disable this for now. It will be deleted anyway.
int index;
switch (findScope(lattice_, instr, &index)) {
case kScopeOuter: {
SpecialBuilder builder(ir_, &factory_, instr, instr->effect_in());
instr->name_in() = builder.addConst(lattice_->makeOrdinalConst(index));
factory_.toBinaryStmt(HR_findprop2getouter, instr);
assert(def(instr->effect_in()) == builder.effect());
break;
}
case kScopeDomain:
factory_.toBinaryStmt(HR_findprop2finddef, instr);
break;
}
+#endif
}
void Specializer::do_toint(UnaryStmt* instr) {
const Type* t = type(instr->value_in());
if (isUInt(t))
factory_.toUnaryStmt(HR_uinttoint, instr);
else if (isNumber(t))
factory_.toUnaryStmt(HR_numbertoint, instr);
@@ -707,97 +718,10 @@ void Specializer::removeSpeculate(Binary
Def* state = def(instr->rhs_in());
(void) state;
assert (isState(type(state)));
assert (kind(definer(state)) == HR_safepoint);
connectUsesToDef(*instr->value_out(), lhs);
}
}
-/***
- * Is there a cleaner way to find out if an instr is a speculative use
- * other than a switch statement? Error prone to add a speculate_instr
- * and forget to modify this method. Otherwise, if we add a speculate_instr
- * and don't add this, the safepoint gets eliminated
- */
-bool Specializer::isSpeculate(Instr* instr) {
- switch (kind(instr)) {
- case HR_speculate_int:
- case HR_speculate_number:
- case HR_speculate_string:
- case HR_speculate_object:
- case HR_speculate_array:
- case HR_speculate_bool:
- return true;
- default:
- return false;
- }
-}
-
-bool Specializer::haveSpeculateUses(SafepointInstr* instr) {
- for (AllUsesRange u(instr); !u.empty(); u.popFront()) {
- bool is_speculate = isSpeculate(user(u.front()));
- if (is_speculate) {
- return true;
- }
- }
-
- return false;
-}
-
-/***
- * DANGER DANGER DANGER:
- * We're assuming setlocal and safepoints are used ONLY BY SPECULATIVE
- * optimizations. We do not support exceptions.
- * Check if we're being used by a speculate opcode
- * if not, remove this safepoint
- * We assume we have no other reasons to see a set local or safepoint
- */
-void Specializer::do_safepoint(SafepointInstr* instr) {
- if (!haveSpeculateUses(instr)) {
- // We assume safepoints occur because abcbuilder emitted a setlocal
- // for every stack slot, then this safepoint. eliminate this safepoint
- connectUsesToDef(*instr->state_out(), def(instr->state_in()));
- connectUsesToDef(*instr->effect_out(), def(instr->effect_in()));
- }
-}
-
-/***
- * DANGER, READ DO_safepoint text
- * Check the previous state. If the setlocal in a previous state sets the local
- * to the same value, as us, delete us.
- * Only make a local decision, we don't check all possible paths at arms
- * May need a global setlocal optimization if this isn't good enough
- */
-void Specializer::do_setlocal(SetlocalInstr* instr) {
- Instr* state_in = definer(instr->state_in());
- int original_index = instr->index;
- bool have_safepoint = false;
-
- while(kind(state_in) == HR_setlocal || kind(state_in) == HR_safepoint) {
- if (kind(state_in) == HR_setlocal) {
- SetlocalInstr* setlocal = cast<SetlocalInstr>(state_in);
- state_in = definer(setlocal->state_in());
-
- if (setlocal->index == original_index) {
- if (def(setlocal->value_in()) == def(instr->value_in())) {
- // instr setlocals the same value as a previous setlocal
- connectUsesToDef(*instr->state_out(), def(instr->state_in()));
- } else if (!have_safepoint) {
- // instr setlocal to the same index as a previous setlocal
- // without a safepoint in between. Delete the previous setlocal
- // since it has no effect.
- // DANGER: kind of ugly to delete a previous setlocal...
- // further downstream rather than deleting it when visiting
- // the previous setlocal.
- connectUsesToDef(*setlocal->state_out(), def(setlocal->state_in()));
- }
- }
- } else {
- SafepointInstr* safepoint = cast<SafepointInstr>(state_in);
- state_in = definer(safepoint->state_in());
- have_safepoint = true;
- }
- }
-}
-
} // namespace halfmoon
#endif // VMCFG_HALFMOON
--- a/halfmoon/hm-specializer.h
+++ b/halfmoon/hm-specializer.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef SPECIALIZER_H_
#define SPECIALIZER_H_
namespace halfmoon {
@@ -16,17 +16,17 @@ enum ScopeKind {
kScopeDomain // use finddef.
};
/**
* Analyzer for lexical binding of findproperty opcodes. This function will
* search for a binding, then return a ScopeKind result and parameter depending
* on the kind.
*/
-ScopeKind findScope(Lattice*, NaryStmt2*, int* index);
+ScopeKind findScope(Lattice*, NaryStmt3*, int* index);
/// Analyze property bindings.
///
struct CallAnalyzer {
CallAnalyzer(const Type* obj_type, const Type* name_type,
Lattice* lattice, int extra_argc);
Binding binding;
MethodSignaturep signature;
@@ -43,18 +43,18 @@ struct CallAnalyzer {
class Specializer: public KindAdapter<Specializer, void> {
public:
Specializer(InstrGraph* ir);
void specialize(Instr*);
public: // dispatch() adapter methods.
void do_default(Instr*) { }
- void do_abc_findproperty(NaryStmt2* i) { return doFindStmt(i); }
- void do_abc_findpropstrict(NaryStmt2* i) { return doFindStmt(i); }
+ void do_abc_findproperty(NaryStmt3* i) { return doFindStmt(i); }
+ void do_abc_findpropstrict(NaryStmt3* i) { return doFindStmt(i); }
void do_toint(UnaryStmt*);
void do_touint(UnaryStmt*);
void do_toboolean(UnaryExpr*);
void do_coerce(BinaryStmt*);
void do_construct(CallStmt2*);
void do_abc_callprop(CallStmt2*);
void do_abc_constructprop(CallStmt2*);
void do_constructsuper(CallStmt2*);
@@ -74,23 +74,21 @@ public: // dispatch() adapter methods.
void do_doubletoint32(UnaryExpr*);
void do_if(IfInstr*);
void do_speculate_number(BinaryExpr* i) { removeSpeculate(i); }
void do_speculate_int(BinaryExpr* i) { removeSpeculate(i); }
void do_speculate_object(BinaryExpr* i) { removeSpeculate(i); }
void do_speculate_string(BinaryExpr* i) { removeSpeculate(i); }
void do_speculate_numeric(BinaryExpr* i) { removeSpeculate(i); }
void do_speculate_bool(BinaryExpr* i) { removeSpeculate(i); }
- void do_setlocal(SetlocalInstr*);
- void do_safepoint(SafepointInstr*);
private:
void doCompare(BinaryExpr*, InstrKind int_kind, InstrKind uint_kind,
InstrKind double_kind);
- void doFindStmt(NaryStmt2*);
+ void doFindStmt(NaryStmt3*);
bool specializeArithmetic(InstrKind k1, InstrKind k2, UnaryExpr* instr);
InstrKind getLoadEnvKind(const Type* object, bool is_interface = false);
bool specializeSlotCallProp(CallStmt2* instr, CallAnalyzer* call_analyzer);
bool specializeMethodCallProp(CallStmt2* instr, CallAnalyzer* call_analyzer);
void removeSpeculate(BinaryExpr* instr);
bool haveSpeculateUses(SafepointInstr*);
bool isSpeculate(Instr* instr);
--- a/halfmoon/hm-stubs.cpp
+++ b/halfmoon/hm-stubs.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace avmplus {
@@ -98,16 +98,20 @@ MethodEnv* Stubs::do_loadenv_boolean(Met
MethodEnv* Stubs::do_loadinitenv(MethodFrame*, ScriptObject* object) {
return object->vtable->init;
}
MethodEnv* Stubs::do_loadsuperinitenv(MethodFrame*, MethodEnv* env) {
return JitFriend::superInitEnv(env);
}
+MethodEnv* Stubs::do_loadenv_env(avmplus::MethodFrame*, int method_id, avmplus::MethodEnv* env) {
+ return env->abcEnv()->getMethod(method_id);
+}
+
ScriptObject* Stubs::do_newinstance(MethodFrame*, ClassClosure* c) {
return c->vtable->createInstanceProc(c);
}
Atom Stubs::do_toprimitive(MethodFrame*, Atom x) {
return AvmCore::primitive(x);
}
@@ -676,16 +680,21 @@ String* Stubs::do_atom2string(MethodFram
return (String*)atomPtr(x);
}
BoolKind Stubs::do_atom2bool(MethodFrame*, Atom x) {
assert(AvmCore::isBoolean(x));
return BoolKind(x == trueAtom);
}
+Namespace* Stubs::do_atom2ns(MethodFrame*, Atom x) {
+ assert(AvmCore::isNamespace(x) || AvmCore::isNull(x));
+ return (Namespace*)atomPtr(x);
+}
+
int Stubs::do_atom2int(MethodFrame*, Atom x) {
return AvmCore::integer_i(x);
}
uint32_t Stubs::do_atom2uint(MethodFrame*, Atom x) {
return AvmCore::integer_u(x);
}
@@ -750,93 +759,123 @@ Atom Stubs::do_getouterscope(MethodFrame
}
/// DEOPT
/// FIXME: This stub should not be required, though it's not clear how to
/// convince templates.py of this. Note that no stubs are generated for
/// HM_deopt_safepoint and HM_deopt_finishcall.
void Stubs::do_deopt_finish(MethodFrame*) {}
+// debugline: (Effect, Int) -> Effect
+void Stubs::do_debugline(MethodFrame*, int32_t line) {
+ (void)line;
+}
+
+// debugfile: (Effect, String) -> Effect
+void Stubs::do_debugfile(MethodFrame*, String*) {}
+
inline Atom abc_find(MethodEnv* env, const Multiname* name, Atom* scopes,
- int scope_count, bool strict) {
+ int scope_count, bool strict, Atom* withbase) {
// fixme: handle withbase
- return env->findproperty(env->scope(), scopes, scope_count, name, strict, 0);
+ return env->findproperty(env->scope(), scopes, scope_count, name, strict, withbase);
}
inline Atom abc_findx(MethodEnv* env, const Multiname* name, Atom index,
- Atom* scopes, int scope_count, bool strict) {
+ Atom* scopes, int scope_count, bool strict, Atom* withbase) {
// fixme: handle withbase
Multiname tempname;
initnamex(env->core(), name, index, &tempname);
return env->findproperty(env->scope(), scopes, scope_count, &tempname,
- strict, 0);
+ strict, withbase);
}
inline Atom abc_findns(MethodEnv* env, const Multiname* name, Atom ns,
- Atom* scopes, int scope_count, bool strict) {
+ Atom* scopes, int scope_count, bool strict, Atom* withbase) {
// fixme: handle withbase
Multiname tempname;
initnamens(env, name, ns, &tempname);
return env->findproperty(env->scope(), scopes, scope_count, &tempname,
- strict, 0);
+ strict, withbase);
}
inline Atom abc_findnsx(MethodEnv* env, const Multiname* name, Atom ns,
- Atom index, Atom* scopes, int scope_count, bool strict) {
+ Atom index, Atom* scopes, int scope_count, bool strict, Atom* withbase) {
// fixme: handle withbase
Multiname tempname;
initnamensx(env, name, ns, index, &tempname);
return env->findproperty(env->scope(), scopes, scope_count, &tempname,
- strict, 0);
+ strict, withbase);
}
Atom Stubs::do_abc_findproperty(MethodFrame*, const Multiname* name,
- MethodEnv* env, int scope_count, Atom* scopes) {
- return abc_find(env, name, scopes, scope_count, false);
+ MethodEnv* env, int32_t withbase, int scope_count, Atom* scopes) {
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ return abc_find(env, name, scopes, scope_count, false, withbasep);
}
Atom Stubs::do_abc_findpropstrict(MethodFrame*, const Multiname* name,
- MethodEnv* env, int scope_count, Atom* scopes) {
- return abc_find(env, name, scopes, scope_count, true);
+ MethodEnv* env, int32_t withbase, int scope_count, Atom* scopes) {
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ return abc_find(env, name, scopes, scope_count, true, withbasep);
}
Atom Stubs::do_abc_findpropertyx(MethodFrame*, const Multiname* name,
- MethodEnv* env, Atom index, int scope_count,
+ MethodEnv* env, int32_t withbase, Atom index, int scope_count,
Atom* scopes) {
- return abc_findx(env, name, index, scopes, scope_count, false);
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ return abc_findx(env, name, index, scopes, scope_count, false, withbasep);
}
Atom Stubs::do_abc_findpropstrictx(MethodFrame*, const Multiname* name,
- MethodEnv* env, Atom index, int scope_count,
+ MethodEnv* env, int32_t withbase, Atom index, int scope_count,
Atom* scopes) {
- return abc_findx(env, name, index, scopes, scope_count, true);
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ return abc_findx(env, name, index, scopes, scope_count, true, withbasep);
}
Atom Stubs::do_abc_findpropertyns(MethodFrame*, const Multiname* name,
- MethodEnv* env, Atom ns, int scope_count,
+ MethodEnv* env, int32_t withbase, Atom ns, int scope_count,
Atom* scopes) {
- return abc_findns(env, name, ns, scopes, scope_count, false);
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ return abc_findns(env, name, ns, scopes, scope_count, false, withbasep);
}
Atom Stubs::do_abc_findpropstrictns(MethodFrame*, const Multiname* name,
- MethodEnv* env, Atom ns, int scope_count,
+ MethodEnv* env, int32_t withbase, Atom ns, int scope_count,
Atom* scopes) {
- return abc_findns(env, name, ns, scopes, scope_count, true);
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ return abc_findns(env, name, ns, scopes, scope_count, true, withbasep);
}
Atom Stubs::do_abc_findpropertynsx(MethodFrame*, const Multiname* name,
- MethodEnv* env, Atom ns, Atom index,
+ MethodEnv* env, int32_t withbase, Atom ns,
int scope_count, Atom* scopes) {
- return abc_findnsx(env, name, ns, index, scopes, scope_count, false);
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ Atom index = *scopes;
+ scopes++;
+ scope_count--;
+ return abc_findnsx(env, name, ns, index, scopes, scope_count, false, withbasep);
}
Atom Stubs::do_abc_findpropstrictnsx(MethodFrame*, const Multiname* name,
- MethodEnv* env, Atom ns, Atom index,
+ MethodEnv* env, int32_t withbase, Atom ns,
int scope_count, Atom* scopes) {
- return abc_findnsx(env, name, ns, index, scopes, scope_count, true);
+ assert(withbase >= -1 && withbase < scope_count);
+ Atom* withbasep = (withbase == -1) ? NULL : scopes + withbase;
+ Atom index = *scopes;
+ scopes++;
+ scope_count--;
+ return abc_findnsx(env, name, ns, index, scopes, scope_count, true, withbasep);
}
BoolKind Stubs::do_abc_strictequals(MethodFrame*, Atom x, Atom y) {
return boolKind(AvmCore::stricteq(x, y) == trueAtom);
}
ArrayObject* Stubs::do_newarray(MethodFrame* f, int count, Atom* values) {
return avmplus::newarray(toplevel(f), count, values);
@@ -1277,15 +1316,18 @@ String* Stubs::do_abc_esc_xattr(MethodFr
return core(f)->EscapeAttributeValue(value);
}
Atom Stubs::do_ckfilter(MethodFrame* f, Atom value) {
env(f)->checkfilter(value);
return value;
}
-ScriptObject* Stubs::do_newcatch(MethodFrame*, Traits*) { assert(false && "newcatch not implemented"); return 0; }
+Atom Stubs::do_newcatch(MethodFrame* f, Traits* traits) {
+ return env(f)->newcatch(traits)->atom();
+}
+
Traits* Stubs::do_slottype(MethodFrame*, ScriptObject*, int) { assert(false && "slottype not implemented"); return 0; }
int Stubs::do_toslot(MethodFrame*, ScriptObject*, const Multiname*) { assert(false && "toslot not implemented"); return 0; }
void Stubs::do_never(MethodFrame*) { assert(false && "never not implemented"); }
} // namespace halfmoon
#endif // #ifdef VMCFG_HALFMOON
--- a/halfmoon/hm-templatebuilder.cpp
+++ b/halfmoon/hm-templatebuilder.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
#include "hm-templatebuilder.h"
--- a/halfmoon/hm-templatebuilder.h
+++ b/halfmoon/hm-templatebuilder.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TEMPLATE_BUILDER_H_
#define TEMPLATE_BUILDER_H_
namespace halfmoon {
--- a/halfmoon/hm-typeanalyzer.cpp
+++ b/halfmoon/hm-typeanalyzer.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -34,16 +34,17 @@ void TypeAnalyzer::coerceOutputModels(In
void TypeAnalyzer::computeTypes(Instr* instr) {
// TODO consider carefully replacing the switch with the default case.
// the effect will be the same, but masking off block starts because
// their params start with no type points to a deeper issue with where
// in an instr's lifetime computeTypes() should be called.
switch (kind(instr)) {
case HR_goto:
+ case HR_catchblock:
case HR_label:
case HR_arm:
break;
default: {
if (numUses(instr) > 0) {
// For ordinary instructions, any UN input gives UN results.
for (ArrayRange<Use> r = useRange(instr); !r.empty(); r.popFront())
if (isBottom(type(r.front()))) {
@@ -146,16 +147,26 @@ void TypeAnalyzer::do_callmethod(CallStm
if (callee) {
Traits* return_traits = callee->getMethodSignature()->returnTraits();
return setStmtType(instr, lattice_->makeType(return_traits));
}
}
return do_default(instr);
}
+/// if we can resolve the called method, set
+/// data result type to the resolved method's
+/// return type.
+///
+void TypeAnalyzer::do_callstatic(CallStmt2* instr) {
+ MethodInfo* method = getMethod(type(instr->param_in()));
+ const Type* return_type = lattice_->makeType(method->getMethodSignature()->returnTraits());
+ return setStmtType(instr, return_type);
+}
+
/// Always set the output type to the interface method signature
void TypeAnalyzer::do_callinterface(CallStmt2* instr) {
MethodInfo* method = getMethod(type(instr->param_in()));
const Type* return_type = lattice_->makeType(method->getMethodSignature()->returnTraits());
return setStmtType(instr, return_type);
}
/// if we have a constant dispatch id and
@@ -200,16 +211,26 @@ void TypeAnalyzer::do_loadsuperinitenv(U
MethodInfo* info_in = getMethod(env_in);
if (info_in) {
MethodInfo* info_out = info_in->declaringTraits()->base->init;
return setType(instr->value_out(), lattice_->makeEnvType(info_out));
}
do_default(instr);
}
+void TypeAnalyzer::do_loadenv_env(BinaryExpr* instr) {
+ const Type* disp_id_type = type(instr->lhs_in());
+ assert(isConst(disp_id_type));
+ int disp_id = ordinalVal(disp_id_type);
+
+ MethodInfo* caller = getMethod(type(instr->rhs_in()));
+ MethodInfo* callee = caller->pool()->getMethodInfo(disp_id);
+ return setType(instr->value_out(), lattice_->makeEnvType(callee));
+}
+
// adapters to convert C++ bool to BoolKind into and out of stubs
inline BoolKind b2k(bool b) { return b ? kBoolTrue : kBoolFalse; }
inline bool k2b(BoolKind k) { return k == kBoolTrue; }
const Type* callstub(Lattice* l, const Type* c, Stub_I_I stub) {
return l->makeIntConst(stub(0, intVal(c)));
}
const Type* callstub(Lattice* l, const Type* c, Stub_I_U stub) {
@@ -433,17 +454,17 @@ void TypeAnalyzer::do_slottype(BinaryExp
}
// Unknown slot number.
do_default(instr);
}
/// if we find a local definition, set data result type
/// to its type.
///
-void TypeAnalyzer::doFindInstr(NaryStmt2* instr) {
+void TypeAnalyzer::doFindInstr(NaryStmt3* instr) {
int index;
if (findScope(lattice_, instr, &index) == kScopeLocal)
return setStmtType(instr, type(instr->vararg(index)));
do_default(instr);
}
void TypeAnalyzer::do_abc_add(BinaryStmt* instr) {
const Type* string_nn_type = lattice_->string_type[kTypeNotNull];
@@ -538,17 +559,22 @@ void TypeAnalyzer::do_getouterscope(Bina
const Type* t = lattice_->getOuterScopeType(caller, ordinalVal(ord_type));
return setType(instr->value_out(), t);
}
do_default(instr);
}
void TypeAnalyzer::do_cknull(UnaryStmt* instr) {
const Type* value = type(instr->value_in());
- return setStmtType(instr, lattice_->makeNotNull(value));
+ const Type* not_null = lattice_->makeNotNull(value);
+ if (isBottom(not_null)) {
+ // Don't allow this type to go to bottom, so make up something wide enough to hold it
+ return setStmtType(instr, lattice_->makeNotNull(lattice_->makeUnion(value, lattice_->atom_type[kTypeNullable])));
+ }
+ return setStmtType(instr, not_null);
}
void TypeAnalyzer::do_newactivation(UnaryStmt* instr) {
// fixme: opcode table says these can throw, but can they?
const Type* env = type(instr->value_in());
MethodInfo* method = getMethod(env);
if (method)
return setStmtType(instr, lattice_->makeType(method->activationTraits(), false));
--- a/halfmoon/hm-typeanalyzer.h
+++ b/halfmoon/hm-typeanalyzer.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef TYPEANALYZER_H_
#define TYPEANALYZER_H_
namespace halfmoon {
@@ -52,32 +52,35 @@ public:
///
void computeTypes(Instr*);
public: // dispatch() adapter methods.
void do_default(Instr*);
void doTemplateInstr(Instr*);
void do_start(StartInstr*) { } // has root defs only
void do_template(StartInstr*) { } // has root defs only
+ void do_catchblock(CatchBlockInstr*) { } // has root defs only
void do_label(LabelInstr*);
void do_arm(ArmInstr*);
void do_const(ConstantExpr*) { } // polymorphic constant
void do_abc_finddef(BinaryStmt*);
void do_callmethod(CallStmt2*);
void do_callinterface(CallStmt2*);
+ void do_callstatic(CallStmt2*);
void do_newinstance(UnaryExpr*);
void do_toprimitive(UnaryStmt*);
void do_string2atom(UnaryExpr* i) { doChangeModel(i, kModelAtom); }
void do_int2atom(UnaryExpr* i) { doChangeModel(i, kModelAtom); }
void do_uint2atom(UnaryExpr* i) { doChangeModel(i, kModelAtom); }
void do_double2atom(UnaryExpr* i) { doChangeModel(i, kModelAtom); }
void do_scriptobject2atom(UnaryExpr* i) { doChangeModel(i, kModelAtom); }
void do_bool2atom(UnaryExpr* i) { doChangeModel(i, kModelAtom); }
void do_ns2atom(UnaryExpr* i) { doChangeModel(i, kModelAtom); }
void do_atom2scriptobject(UnaryExpr* i) { doChangeModel(i, kModelScriptObject); }
+ void do_atom2ns(UnaryExpr* i) { doChangeModel(i, kModelNamespace); }
void do_atom2bool(UnaryExpr* i) { doChangeModel(i, kModelInt); }
void do_atom2string(UnaryExpr* i) { doChangeModel(i, kModelString); }
void do_i2d(UnaryExpr* i) { doChangeModel(i, kModelDouble); }
void do_u2d(UnaryExpr* i) { doChangeModel(i, kModelDouble); }
void do_d2i(UnaryExpr* i) { doChangeModel(i, kModelInt); }
void do_d2u(UnaryExpr* i) { doChangeModel(i, kModelInt); }
void do_caststring(UnaryStmt* i) { doCoerceInstr(i, lattice_->string_type[kTypeNullable]); }
void do_castobject(UnaryExpr* i) { doCoerceInstr(i, lattice_->object_type[kTypeNullable]); }
@@ -89,18 +92,18 @@ public: // dispatch() adapter methods.
void do_applytype(NaryStmt0*);
void do_newclass(NaryStmt2*);
void do_abc_callprop(CallStmt2*);
void do_abc_constructprop(CallStmt2*);
void do_toslot(BinaryExpr*);
void do_slottype(BinaryExpr*);
void do_coerce(BinaryStmt* i) { doCoerceInstr(i); }
void do_cast(BinaryStmt* i) { doCoerceInstr(i); }
- void do_abc_findproperty(NaryStmt2* i) { doFindInstr(i); }
- void do_abc_findpropstrict(NaryStmt2* i) { doFindInstr(i); }
+ void do_abc_findproperty(NaryStmt3* i) { doFindInstr(i); }
+ void do_abc_findpropstrict(NaryStmt3* i) { doFindInstr(i); }
void do_abc_add(BinaryStmt*);
void do_abc_getprop(CallStmt2*);
void do_abc_getpropx(CallStmt3*);
void do_getpropertylate_u(BinaryStmt* i) { doGetpropertylate(i); }
void do_getpropertylate_i(BinaryStmt* i) { doGetpropertylate(i); }
void do_getpropertylate_d(BinaryStmt* i) { doGetpropertylate(i); }
void do_getslot(CallStmt2*);
void do_ckfilter(UnaryExpr*);
@@ -113,16 +116,17 @@ public: // dispatch() adapter methods.
void do_loadenv_atom(BinaryExpr* i) { do_loadenv(i); }
void do_loadenv_interface(BinaryExpr*);
void do_loadenv_string(BinaryExpr* i) { do_loadenv(i); }
void do_loadenv_number(BinaryExpr* i) { do_loadenv(i); }
void do_loadenv_boolean(BinaryExpr* i) { do_loadenv(i); }
void do_loadenv_namespace(BinaryExpr* i) { do_loadenv(i); }
void do_loadinitenv(UnaryExpr*);
void do_loadsuperinitenv(UnaryExpr*);
+ void do_loadenv_env(BinaryExpr*);
// constant folding
void do_addi(BinaryExpr* i) { fold(i, Stubs::do_addi); }
void do_subi(BinaryExpr* i) { fold(i, Stubs::do_subi); }
void do_muli(BinaryExpr* i) { fold(i, Stubs::do_muli); }
void do_ori(BinaryExpr* i) { fold(i, Stubs::do_ori); }
void do_andi(BinaryExpr* i) { fold(i, Stubs::do_andi); }
void do_xori(BinaryExpr* i) { fold(i, Stubs::do_xori); }
@@ -157,17 +161,17 @@ public: // dispatch() adapter methods.
void do_i2u(UnaryExpr* i) { fold(i, Stubs::do_i2u); }
void do_d2b(UnaryExpr* i) { fold(i, Stubs::do_d2b); }
void do_doubletoint32(UnaryExpr* i) { fold(i, Stubs::do_doubletoint32); }
private:
void doCoerceInstr(UnaryExpr*, const Type* to_type);
void doCoerceInstr(UnaryStmt*, const Type* to_type);
void doCoerceInstr(BinaryStmt*);
- void doFindInstr(NaryStmt2*);
+ void doFindInstr(NaryStmt3*);
void doChangeModel(UnaryExpr*, ModelKind);
void coerceOutputModels(Instr*);
void doGetpropertylate(BinaryStmt*);
template<typename STUB> void fold(BinaryExpr*, STUB);
template<typename STUB> void fold(UnaryExpr*, STUB);
template<int ARGMIN>
--- a/halfmoon/hm-typeinference.cpp
+++ b/halfmoon/hm-typeinference.cpp
@@ -1,10 +1,10 @@
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
#include "profiler/profiler-main.h"
@@ -251,16 +251,20 @@ void SCCP::analyzeBranch(BlockEndInstr*
if (arm)
addBlock(arm);
else
for (ArrayRange<ArmInstr*> a = armRange(cond); !a.empty();)
addBlock(a.popFront());
break;
}
}
+ if (end->catch_blocks != NULL) {
+ for (CatchBlockRange r(end); !r.empty();)
+ addBlock(r.popFront());
+ }
}
void SCCP::analyzeSSA(Instr* instr) {
if (numDefs(instr) == 0) {
if (isBlockEnd(instr))
analyzeBranch((BlockEndInstr*)instr);
return;
}
@@ -273,18 +277,22 @@ void SCCP::analyzeSSA(Instr* instr) {
analyzer.computeTypes(instr);
// dev: check computation result
bool changed2 = false;
i = 0;
for (ArrayRange<Def> d = defRange(instr); !d.empty(); d.popFront(), ++i) {
assert(subtypeof(old_types[i], type(d.front())) && "illegal type narrowing");
changed2 |= *type(d.front()) != *old_types[i];
}
- if (changed2)
+ if (changed2) {
+ if (enable_typecheck) {
+ printInstr(instr);
+ }
addInstrUsers(instr);
+ }
}
/**
* propagate types through an InstrGraph, starting with root defs
* in start and constant instructions.
*
* Note that per SCCP, types in dead arms of constant conditionals
* are set to UN.
--- a/halfmoon/hm-typeinference.h
+++ b/halfmoon/hm-typeinference.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
/**
* Sparse Conditional Constant propagation. Reset all types of all defs,
--- a/halfmoon/hm-types.cpp
+++ b/halfmoon/hm-types.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
@@ -217,23 +217,30 @@ const Type* SimpleDataType<SELF_CLASS, T
if (t.isSubtypeOf(*this) && submodelof(&t, this))
return this;
if (t.kind == TYPE_KIND)
return makeUnion((SELF_CLASS&)t, lat);
if (isDataType(t)) {
// if we're null, reverse the test so we only need to handle the other-is-null case
- if (isNull())
+ if (isNull() && halfmoon::kind(this) != kTypeVoid) {
return t.makeUnion(*this, lat);
+ }
bool union_nullable = is_nullable || t.is_nullable;
Traits* union_traits = Verifier::findCommonBase(traits, getTraits(&t));
switch (builtinType(union_traits)) {
case BUILTIN_any:
+ if (union_traits == NULL) {
+ // null unioned with t just returns a nullable t, except for void
+ if (builtinType(getTraits(&t)) == BUILTIN_null && builtinType(traits) != BUILTIN_void) {
+ return lat.makeType(SELF_CLASS(model, traits, true, false, (VALUE_REP)0));
+ }
+ }
return lat.makeType(AnyType(union_traits, union_nullable));
case BUILTIN_object:
return lat.makeType(ObjectType(union_traits, union_nullable));
default:
if (union_traits == traits) {
assert(builtinType(getTraits(&t)) == BUILTIN_null);
return lat.makeType(SELF_CLASS(model, traits, true, false, (VALUE_REP)0));
} else {
@@ -267,17 +274,17 @@ ObjectType::ObjectType(Traits* traits, b
}
// --------------------------------------------------------------------
// VoidType
VoidType::VoidType(Traits* traits) :
SimpleDataType<VoidType, kTypeVoid, kModelAtom, Atom>
- (traits, kModelAtom, false, true, undefinedAtom) {
+ (traits, kModelAtom, true, true, undefinedAtom) {
assert(builtinType(traits) == BUILTIN_void);
}
// --------------------------------------------------------------------
// ScriptObjectType
ScriptObjectType::ScriptObjectType(ModelKind model, Traits* traits,
--- a/halfmoon/hm-types.h
+++ b/halfmoon/hm-types.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
namespace halfmoon {
using avmplus::AvmCore;
using avmplus::Binding;
using avmplus::BIND_AMBIGUOUS;
--- a/halfmoon/hm-util.h
+++ b/halfmoon/hm-util.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_UTIL_H_
#define HM_UTIL_H_
//
@@ -70,16 +70,42 @@ public:
private:
E* const frame;
const int stack_base;
const int stackp;
const int scopep;
int i;
};
+/**
+ * Range that accesses each active position in an ABC stack frame.
+ */
+class FrameIndexRange {
+public:
+ FrameIndexRange(int stackp, int scopep, int stack_base) :
+ stack_base(stack_base), stackp(stackp), scopep(scopep), i(0) {
+ }
+
+ bool empty() const {
+ return i > stackp;
+ }
+ int front() const {
+ return i;
+ }
+ void popFront() {
+ i = (i != scopep) ? i + 1 : stack_base;
+ }
+
+private:
+ const int stack_base;
+ const int stackp;
+ const int scopep;
+ int i;
+};
+
/// Return a FrameRange for frame, given the dimensions from state and signature.
///
template<class E>
FrameRange<E> range(E* frame, const FrameState* state,
MethodSignaturep signature) {
int stack_base = signature->stack_base();
int sp = stack_base + state->stackDepth - 1;
int scopep = signature->scope_base() + state->scopeDepth - 1;
--- a/halfmoon/hm-valnum.cpp
+++ b/halfmoon/hm-valnum.cpp
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "hm-main.h"
#ifdef VMCFG_HALFMOON
namespace halfmoon {
--- a/halfmoon/hm-valnum.h
+++ b/halfmoon/hm-valnum.h
@@ -1,10 +1,10 @@
-/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
-/* vi: set ts=4 sw=4 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
+/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 2 -*- */
+/* vi: set ts=2 sw=2 expandtab: (add to ~/.vimrc: set modeline modelines=5) */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef HM_VALNUM_H_
#define HM_VALNUM_H_
namespace halfmoon {
--- a/halfmoon/templates/ast.py
+++ b/halfmoon/templates/ast.py
@@ -317,16 +317,17 @@ callstmt3 = RepInfo("CallStmt3", shape(1
callstmt4 = RepInfo("CallStmt4", shape(1, 4, 1, 1, DATA_IN))
unaryexpr = RepInfo("UnaryExpr", shape(0, 1, 0, 1, NONE), gen = True)
unarystmt = RepInfo("UnaryStmt", shape(1, 1, 1, 1, NONE), gen = True)
binaryexpr = RepInfo("BinaryExpr", shape(0, 2, 0, 1, NONE), gen = True)
binarystmt = RepInfo("BinaryStmt", shape(1, 2, 1, 1, NONE), gen = True)
hasnext2stmt = RepInfo("Hasnext2Stmt", shape(1, 2, 1, 3, NONE))
voidstmt = RepInfo("VoidStmt", shape(1, 0, 1, 0, NONE))
constantexpr = RepInfo("ConstantExpr", shape(0, 0, 0, 1, NONE))
+debuginstr = RepInfo("DebugInstr", shape(1, 1, 1, 0, NONE))
# this list is used to populate reps, a map of shapes to reps
# used to choose representations for instrs. Not all shapes
# defined above are on this list, because some are used on
# an override basis only, as specified in instr_rep_overrides
# and shape_rep_overrides, below.
#
replist = [
@@ -336,81 +337,87 @@ replist = [
callstmt3,
callstmt4,
unaryexpr,
unarystmt,
binaryexpr,
binarystmt,
hasnext2stmt,
voidstmt,
- constantexpr
+ constantexpr,
+ debuginstr
]
# shape -> rep, used to pick reps for instrs
# based on instr shape (subject to overrides,
# see below)
#
reps = dict([(rep.shape, rep) for rep in replist])
# NOTE: these reps are only used in IR5 shape overrides
# (see instr_rep_overrides). They are *not* selectable
# via reps() by ordinary instructions.
#
startinstr = RepInfo("StartInstr", shape(0, 0, 1, 0, DATA_OUT))
+catchblockinstr = RepInfo("CatchBlockInstr", shape(0, 0, 1, 0, DATA_OUT))
stopinstr = RepInfo("StopInstr", shape(1, 0, 0, 0, DATA_IN))
# some instrs are made to use a non-default rep,
# irrespective of the instr shape.
# if an instr name is a key in this map, CG will
# use the specified rep, rather than trying to
# find a match for the instr's shape in reps
#
instr_rep_overrides = {
# these overrides allow a custom C++ class to
# store extra information.
#
- "safepoint": RepInfo("SafepointInstr", shape(1, 1, 1, 1, NONE)),
+ "safepoint": RepInfo("SafepointInstr", shape(1, 0, 2, 0, DATA_IN)),
"setlocal": RepInfo("SetlocalInstr", shape(0, 2, 0, 1, NONE)),
# DEOPT: I think I need this because deopt_safepoint has
# extra fields for vpc, scopep, sp, etc.
"deopt_safepoint": RepInfo("DeoptSafepointInstr", shape(1, 0, 1, 0, DATA_IN)),
"deopt_finish": RepInfo("DeoptFinishInstr", shape(1, 0, 1, 0, NONE)),
"deopt_finishcall": RepInfo("DeoptFinishCallInstr", shape(1, 1, 1, 0, NONE)),
+
+ "debugline": debuginstr,
+ "debugfile": debuginstr,
# we select IR5 (block delimiter) reps exclusively by
# override. this lets us keep the IR5 reps out of the
# standard reps dictionary, which ensures that ordinary
# instructions with compatible shapes never inadvertently
# select IR5 reps, which have special semantics.
#
"goto": RepInfo("GotoInstr", shape(0, 0, 0, 0, DATA_IN)),
"label": RepInfo("LabelInstr", shape(0, 0, 0, 0, DATA_OUT)),
"if": RepInfo("IfInstr", shape(0, 1, 0, 0, DATA_IN)),
"switch": RepInfo("SwitchInstr", shape(0, 1, 0, 0, DATA_IN)),
"arm": RepInfo("ArmInstr", shape(0, 0, 0, 0, DATA_OUT)),
"return": stopinstr,
"throw": stopinstr,
"start": startinstr,
"template": startinstr,
+ "catchblock": RepInfo("CatchBlockInstr", shape(0, 0, 0, 0, DATA_OUT)),
#
# fixed-arg instructions for which we want to use a
# specific vararg rep that provides VM call semantics.
#
"newfunction": narystmt1,
"newclass": narystmt2,
- "abc_findproperty": narystmt2,
- "abc_findpropertyx": narystmt3,
- "abc_findpropertyns": narystmt3,
+ "abc_findproperty": narystmt3,
+ "abc_findpropertyx": narystmt4,
+ "abc_findpropertyns": narystmt4,
"abc_findpropertynsx": narystmt4,
- "abc_findpropstrict": narystmt2,
- "abc_findpropstrictx": narystmt3,
- "abc_findpropstrictns": narystmt3,
+ "abc_findpropstrict": narystmt3,
+ "abc_findpropstrictx": narystmt4,
+ "abc_findpropstrictns": narystmt4,
"abc_findpropstrictnsx": narystmt4,
"findprop2getouter": narystmt1,
"findprop2finddef": narystmt1,
"abc_getsuper": callstmt2,
"abc_getsuperx": callstmt3,
"abc_getsuperns": callstmt3,
"abc_getsupernsx": callstmt4,
--- a/halfmoon/templates/hrdefs.py
+++ b/halfmoon/templates/hrdefs.py
@@ -36,16 +36,17 @@ hrdefs = '''
; use side, it means the required type is determined elsewhere,
; for example the constraint on goto inputs comes from the label.
; on the def side, it means the actual type is derived from uses
; (e.g. arm's def types come from if's uses) or a signature (start),
; or a-priori (const).
(start (-> Effect [Top])) ; start's defs include effect, state, env, and data
(template (-> Effect [Top]))
+(catchblock (-> [Top]))
(return (Effect [Top] -> )) ; some templates may return vm types
(throw (Effect Atom -> )) ; throw only wants 1 data value even tho StopInstr allows N.
(goto ([Top] -> ))
(label ( -> [Top]))
(if (Boolean [Top] -> ))
@@ -99,16 +100,17 @@ hrdefs = '''
(loadenv_boolean (Ord Boolean -> Env)) ; load MethodEnv* from Boolean
(loadenv_number (Ord Number~ -> Env)) ; load MethodEnv* from Number
(loadenv_string (Ord String~ -> Env)) ; load MethodEnv* from String
(loadenv_interface (Method ScriptObject~ -> Env)) ; load MethodEnv* from Method IID
(loadenv (Ord ScriptObject~ -> Env)) ; load MethodEnv* from ScriptObject->vtable->methods[disp_id]
(loadenv_atom (Ord Atom~ -> Env)) ; load MethodEnv from toVTable(obj)->methods[disp_id]
(loadinitenv (ScriptObject~ -> Env)) ; load MethodEnv from ScriptObject->vtable->init
(loadsuperinitenv (Env -> Env)) ; load MethodEnv from env->vtable->base->init
+(loadenv_env (Ord Env -> Env)) ; load MethodEnv from toVTable(obj)->methods[disp_id]
(newobject (Effect [Atom] -> Effect ScriptObject~)) ;;; TODO: result should be final with Object traits
(newarray (Effect [Atom] -> Effect Array~)) ;;; TODO: Array~ should be final, dense
(applytype (Effect [Atom] -> Effect Atom))
; fixme: input type is a non-null object whose traits has a nonnull itraits, e.g. a class
; output type is the instance type of that class.
(newinstance (Class~ -> ScriptObject~))
@@ -170,24 +172,24 @@ hrdefs = '''
(negi (Int -> Int))
(negd (Number -> Number))
(not (Boolean -> Boolean))
(newactivation (Effect Env -> Effect ScriptObject~))
(abc_finddef (Effect Name Env -> Effect ScriptObject~))
-(abc_findpropstrict (Effect Name Env [Atom~] -> Effect Atom~))
-(abc_findpropstrictx (Effect Name Env Atom [Atom~] -> Effect Atom~))
-(abc_findpropstrictns (Effect Name Env Atom [Atom~] -> Effect Atom~))
-(abc_findpropstrictnsx (Effect Name Env Atom Atom [Atom~] -> Effect Atom~))
-(abc_findproperty (Effect Name Env [Atom~] -> Effect Atom~))
-(abc_findpropertyx (Effect Name Env Atom [Atom~] -> Effect Atom~))
-(abc_findpropertyns (Effect Name Env Atom [Atom~] -> Effect Atom~))
-(abc_findpropertynsx (Effect Name Env Atom Atom [Atom~] -> Effect Atom~))
+(abc_findpropstrict (Effect Name Env Ord [Atom~] -> Effect Atom~))
+(abc_findpropstrictx (Effect Name Env Ord Atom [Atom~] -> Effect Atom~))
+(abc_findpropstrictns (Effect Name Env Ord Atom [Atom~] -> Effect Atom~))
+(abc_findpropstrictnsx (Effect Name Env Ord Atom [Atom~] -> Effect Atom~))
+(abc_findproperty (Effect Name Env Ord [Atom~] -> Effect Atom~))
+(abc_findpropertyx (Effect Name Env Ord Atom [Atom~] -> Effect Atom~))
+(abc_findpropertyns (Effect Name Env Ord Atom [Atom~] -> Effect Atom~))
+(abc_findpropertynsx (Effect Name Env Ord Atom [Atom~] -> Effect Atom~))
(newclass (Effect Traits~ Class [Atom~] -> Effect Class~)) ; TODO vararg is list of Scope, need type
(newfunction (Effect Method [Atom~] -> Effect Function~))
(abc_getsuper (Effect Name Atom~ -> Effect Atom)) ; same as getprop inputs
(abc_getsuperx (Effect Name Atom Atom~ -> Effect Atom)) ; same as getpropx inputs
(abc_getsuperns (Effect Name Atom Atom~ -> Effect Atom)) ; same as getpropns inputs
(abc_getsupernsx (Effect Name Atom Atom Atom~ -> Effect Atom)) ; same as getpropnsx inputs
@@ -214,56 +216,61 @@ hrdefs = '''
(abc_callsuper (Effect Name Atom~ [Atom] -> Effect Atom))
(abc_callsuperx (Effect Name Atom Atom~ [Atom] -> Effect Atom))
(abc_callsuperns (Effect Name Atom Atom~ [Atom] -> Effect Atom))
(abc_callsupernsx (Effect Name Atom Atom Atom~ [Atom] -> Effect Atom))
;; these are natively bound calls, they take TopData because
;; the real signature comes from the callee.
-(callstatic (Effect Ord TopData [TopData] -> Effect TopData))
+(callstatic (Effect Env TopData [TopData] -> Effect TopData))
(callmethod (Effect Env TopData [TopData] -> Effect TopData))
(callinterface (Effect Env TopData [TopData] -> Effect TopData))
-(newcatch (Effect Traits~ -> Effect ScriptObject~)) ; same as newactivation
+(newcatch (Effect Traits~ -> Effect Atom~))
(setslot (Effect Ord ScriptObject~ TopData -> Effect Bot)) ; actual arg type is slot type
(getslot (Effect Ord ScriptObject~ -> Effect TopData)) ; actual result type is slot type
(slottype (ScriptObject~ Ord -> Traits))
(getouterscope (Ord Env -> Atom~))
-(safepoint (Effect State -> Effect State))
+(safepoint (Effect [State] -> Effect State))
-(setlocal (State TopData -> State)) ; TopData allows safepoints to handle unboxed values.
+(setlocal (State Atom -> State)) ; setlocal is only used to store state for exception edges, which require Atom
(newstate (-> State)) ; create abstract VM state value
; DEOPT: new-style safepoints
(deopt_safepoint (Effect [TopData] -> Effect))
(deopt_finish (Effect -> Effect))
(deopt_finishcall (Effect TopData -> Effect))
+; debug
+(debugline (Effect Int -> Effect))
+(debugfile (Effect String -> Effect))
+
; conversions to atom
(string2atom (String -> Atom))
(double2atom (Number -> Atom~))
(int2atom (Int -> Atom~))
(uint2atom (Uint -> Atom~))
(scriptobject2atom (ScriptObject -> Atom))
(bool2atom (Boolean -> Atom~))
(ns2atom (Namespace -> Atom))
; conversions from atom
(atom2bool (Atom~ -> Boolean))
(atom2double (Atom -> Number))
(atom2string (Atom -> String))
(atom2int (Atom -> Int))
(atom2uint (Atom -> Uint))
(atom2scriptobject (Atom -> ScriptObject))
+(atom2ns (Atom -> Namespace))
; additional numeric conversions
(i2d (Int -> Number))
(u2d (Uint -> Number))
(d2i (Number -> Int)) ; should only be used when range is int32 already.
(d2u (Number -> Uint)) ; should only be used when range is uint32 already.
(toslot (ScriptObject Name -> Ord))
--- a/nanojit/Assembler.cpp
+++ b/nanojit/Assembler.cpp
@@ -1637,16 +1637,23 @@ typedef void* (*decode_instructions_ftyp
case LIR_reti:
CASE64(LIR_retq:)
case LIR_retd:
case LIR_retf:
case LIR_retf4:
countlir_ret();
ins->oprnd1()->setResultLive();
+#ifdef VMCFG_HALFMOON
+ // The halfmoon emitter may emit it's blocks in a different order which means
+ // that a ret may be the last thing emitted, so a call to handleLoopCarriedExprs
+ // is required here. It's probably not a bad idea to emit it in general but
+ // but it's ifdef'ed for now.
+ handleLoopCarriedExprs(pending_lives, 0);
+#endif
asm_ret(ins);
break;
// Allocate some stack space. The value of this instruction
// is the address of the stack space.
case LIR_allocp:
countlir_alloc();
if (ins->isExtant()) {