Ejemplo n.º 1
0
JSTrapStatus
ScriptDebugPrologue(JSContext *cx, StackFrame *fp)
{
    JS_ASSERT(fp == cx->fp());

    if (fp->isFramePushedByExecute()) {
        if (JSInterpreterHook hook = cx->debugHooks->executeHook)
            fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->executeHookData));
    } else {
        if (JSInterpreterHook hook = cx->debugHooks->callHook)
            fp->setHookData(hook(cx, Jsvalify(fp), true, 0, cx->debugHooks->callHookData));
    }

    Value rval;
    JSTrapStatus status = Debugger::onEnterFrame(cx, &rval);
    switch (status) {
      case JSTRAP_CONTINUE:
        break;
      case JSTRAP_THROW:
        cx->setPendingException(rval);
        break;
      case JSTRAP_ERROR:
        cx->clearPendingException();
        break;
      case JSTRAP_RETURN:
        fp->setReturnValue(rval);
        break;
      default:
        JS_NOT_REACHED("bad Debugger::onEnterFrame JSTrapStatus value");
    }
    return status;
}
Ejemplo n.º 2
0
static JSBool
HandleData(JSContext *cx, JSONParser *jp, JSONDataType type, const jschar *buf, uint32 len)
{
  JSBool ok = JS_FALSE;
 
  switch (type) {
    case JSON_DATA_STRING:
      ok = HandleString(cx, jp, buf, len);
      break;
 
    case JSON_DATA_KEYSTRING:
      jp->objectKey = JS_NewUCStringCopyN(cx, buf, len);
      ok = JS_TRUE;
      break;
 
    case JSON_DATA_NUMBER:
      ok = HandleNumber(cx, jp, buf, len);
      break;
 
    case JSON_DATA_KEYWORD:
      ok = HandleKeyword(cx, jp, buf, len);
      break;
 
    default:
      JS_NOT_REACHED("Should have a JSON data type");
  }
 
  js_FinishStringBuffer(jp->buffer);
  js_InitStringBuffer(jp->buffer);
 
  return ok;
}
Ejemplo n.º 3
0
bool
ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm)
{
    Label failure;
    // by wangqing, 2013-11-26
    masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister);
    masm.bne(R0.typeReg(), cmpTempRegister, &failure);
    masm.nop();

    switch (op) {
      case JSOP_BITNOT:
        masm.notl(R0.payloadReg());
        break;
      case JSOP_NEG:
        // Guard against 0 and MIN_INT, both result in a double.
		/* rewrite testl(reg, imm), avoid use cmpTemp2Register by wangqing, 2013-11-22*/
	    masm.movl(R0.payloadReg(), cmpTempRegister);
		masm.andl(Imm32(0x7fffffff), cmpTempRegister);
		masm.beq(cmpTempRegister, zero, &failure);
		masm.nop();
        masm.negl(R0.payloadReg());
        break;
      default:
        JS_NOT_REACHED("Unexpected op");
        return false;
    }

    EmitReturnFromIC(masm);

    masm.bindBranch(&failure);
    EmitStubGuardFailure(masm);
    return true;
}
Ejemplo n.º 4
0
bool
ICUnaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm)
{
    Label failure;
    masm.branchTestInt32(Assembler::NotEqual, R0, &failure);

    switch (op) {
      case JSOP_BITNOT:
        masm.notl(R0.payloadReg());
        break;
      case JSOP_NEG:
        // Guard against 0 and MIN_INT, both result in a double.
        masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure);
        masm.negl(R0.payloadReg());
        break;
      default:
        JS_NOT_REACHED("Unexpected op");
        return false;
    }

    EmitReturnFromIC(masm);

    masm.bind(&failure);
    EmitStubGuardFailure(masm);
    return true;
}
Ejemplo n.º 5
0
static JSBool
HandleData(JSContext *cx, JSONParser *jp, JSONDataType type)
{
  JSBool ok = JS_FALSE;

  if (!STRING_BUFFER_OK(jp->buffer))
      return JS_FALSE;

  switch (type) {
    case JSON_DATA_STRING:
      ok = HandleString(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
      break;

    case JSON_DATA_KEYSTRING:
      js_AppendUCString(jp->objectKey, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
      ok = STRING_BUFFER_OK(jp->objectKey);
      break;

    case JSON_DATA_NUMBER:
      ok = HandleNumber(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
      break;

    case JSON_DATA_KEYWORD:
      ok = HandleKeyword(cx, jp, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer));
      break;

    default:
      JS_NOT_REACHED("Should have a JSON data type");
  }

  js_FinishStringBuffer(jp->buffer);
  js_InitStringBuffer(jp->buffer);

  return ok;
}
Ejemplo n.º 6
0
 // The caller must hold the lock.
 void drop(T item) {
     for (T *p = busy.begin(); p != busy.end(); p++) {
         if (*p == item) {
             *p = busy.back();
             busy.popBack();
             return;
         }
     }
     JS_NOT_REACHED("removeBusy");
 }
Ejemplo n.º 7
0
Recompiler::PatchableAddress
Recompiler::findPatch(JITScript *jit, void **location)
{
    uint8* codeStart = (uint8 *)jit->code.m_code.executableAddress();
    CallSite *callSites_ = jit->callSites();
    for (uint32 i = 0; i < jit->nCallSites; i++) {
        if (callSites_[i].codeOffset + codeStart == *location) {
            PatchableAddress result;
            result.location = location;
            result.callSite = callSites_[i];
            return result;
        }
    }

    JS_NOT_REACHED("failed to find call site");
    return PatchableAddress();
}
Ejemplo n.º 8
0
void GetSizeAndThingsPerArena(int thingKind, size_t &thingSize, size_t &thingsPerArena)
{
    switch (thingKind) {
        case FINALIZE_OBJECT0:
        case FINALIZE_OBJECT0_BACKGROUND:
            GetSizeAndThings<JSObject>(thingSize, thingsPerArena);
            break;
        case FINALIZE_OBJECT2:
        case FINALIZE_OBJECT2_BACKGROUND:
            GetSizeAndThings<JSObject_Slots2>(thingSize, thingsPerArena);
            break;
        case FINALIZE_OBJECT4:
        case FINALIZE_OBJECT4_BACKGROUND:
            GetSizeAndThings<JSObject_Slots4>(thingSize, thingsPerArena);
            break;
        case FINALIZE_OBJECT8:
        case FINALIZE_OBJECT8_BACKGROUND:
            GetSizeAndThings<JSObject_Slots8>(thingSize, thingsPerArena);
            break;
        case FINALIZE_OBJECT12:
        case FINALIZE_OBJECT12_BACKGROUND:
            GetSizeAndThings<JSObject_Slots12>(thingSize, thingsPerArena);
            break;
        case FINALIZE_OBJECT16:
        case FINALIZE_OBJECT16_BACKGROUND:
            GetSizeAndThings<JSObject_Slots16>(thingSize, thingsPerArena);
            break;
        case FINALIZE_EXTERNAL_STRING:
        case FINALIZE_STRING:
            GetSizeAndThings<JSString>(thingSize, thingsPerArena);
            break;
        case FINALIZE_SHORT_STRING:
            GetSizeAndThings<JSShortString>(thingSize, thingsPerArena);
            break;
        case FINALIZE_FUNCTION:
            GetSizeAndThings<JSFunction>(thingSize, thingsPerArena);
            break;
#if JS_HAS_XML_SUPPORT
        case FINALIZE_XML:
            GetSizeAndThings<JSXML>(thingSize, thingsPerArena);
            break;
#endif
        default:
            JS_NOT_REACHED("wrong kind");
    }
}
Ejemplo n.º 9
0
static JS_REQUIRES_STACK void
AssertDownFrameIsConsistent(JSContext* cx, VMSideExit* anchor, FrameInfo* fi)
{
    JS_ASSERT(anchor->recursive_down);
    JS_ASSERT(anchor->recursive_down->callerHeight == fi->callerHeight);

    unsigned downPostSlots = fi->callerHeight;
    TraceType* typeMap = fi->get_typemap();

    CaptureStackTypes(cx, 1, typeMap);
    const TraceType* m1 = anchor->recursive_down->get_typemap();
    for (unsigned i = 0; i < downPostSlots; i++) {
        if (m1[i] == typeMap[i])
            continue;
        if ((typeMap[i] == TT_INT32 && m1[i] == TT_DOUBLE) ||
            (typeMap[i] == TT_DOUBLE && m1[i] == TT_INT32)) {
            continue;
        }
        JS_NOT_REACHED("invalid RECURSIVE_MISMATCH exit");
    }
    JS_ASSERT(memcmp(anchor->recursive_down, fi, sizeof(FrameInfo)) == 0);
}
Ejemplo n.º 10
0
JS_REQUIRES_STACK LIns*
TraceRecorder::slurpSlot(LIns* val_ins, jsval* vp, VMSideExit* exit)
{
    switch (exit->slurpType)
    {
    case TT_PSEUDOBOOLEAN:
        return slurpBoolSlot(val_ins, vp, exit);
    case TT_INT32:
        return slurpInt32Slot(val_ins, vp, exit);
    case TT_DOUBLE:
        return slurpDoubleSlot(val_ins, vp, exit);
    case TT_STRING:
        return slurpStringSlot(val_ins, vp, exit);
    case TT_NULL:
        return slurpNullSlot(val_ins, vp, exit);
    case TT_OBJECT:
        return slurpObjectSlot(val_ins, vp, exit);
    case TT_FUNCTION:
        return slurpFunctionSlot(val_ins, vp, exit);
    default:
        JS_NOT_REACHED("invalid type in typemap");
        return NULL;
    }
}
Ejemplo n.º 11
0
JSBool
js_ConsumeJSONText(JSContext *cx, JSONParser *jp, const jschar *data, uint32 len)
{
    uint32 i;
 
    if (*jp->statep == JSON_PARSE_STATE_INIT) {
        PushState(jp, JSON_PARSE_STATE_OBJECT_VALUE);
    }
 
    for (i = 0; i < len; i++) {        
        jschar c = data[i];
        switch (*jp->statep) {
            case JSON_PARSE_STATE_VALUE :
                if (c == ']') {
                    // empty array
                    if (!PopState(jp))
                        return JS_FALSE;
                    if (*jp->statep != JSON_PARSE_STATE_ARRAY) 
                        return JS_FALSE; // unexpected char
                    if (!CloseArray(cx, jp) || !PopState(jp))
                        return JS_FALSE;
                    break;
                }
 
                if (c == '}') {
                    // we should only find these in OBJECT_KEY state
                    return JS_FALSE; // unexpected failure
                }
 
                if (c == '"') {
                    *jp->statep = JSON_PARSE_STATE_STRING;
                    break;
                } 
 
                if (IsNumChar(c)) {
                    *jp->statep = JSON_PARSE_STATE_NUMBER;
                    js_AppendChar(jp->buffer, c);
                    break;
                }
 
                if (JS7_ISLET(c)) {
                    *jp->statep = JSON_PARSE_STATE_KEYWORD;
                    js_AppendChar(jp->buffer, c);
                    break;
                }
 
            // fall through in case the value is an object or array
            case JSON_PARSE_STATE_OBJECT_VALUE :
                if (c == '{') {
                  *jp->statep = JSON_PARSE_STATE_OBJECT;
                  if (!OpenObject(cx, jp) || !PushState(jp, JSON_PARSE_STATE_OBJECT_PAIR))
                      return JS_FALSE;
                } else if (c == '[') {
                  *jp->statep = JSON_PARSE_STATE_ARRAY;
                  if (!OpenArray(cx, jp) || !PushState(jp, JSON_PARSE_STATE_VALUE))
                      return JS_FALSE;
                } else if (!JS_ISXMLSPACE(c)) {
                  return JS_FALSE; // unexpected
                }
                break;
 
            case JSON_PARSE_STATE_OBJECT :
                if (c == '}') {                    
                    if (!CloseObject(cx, jp) || !PopState(jp))
                        return JS_FALSE;
                } else if (c == ',') {
                    if (!PushState(jp, JSON_PARSE_STATE_OBJECT_PAIR))
                        return JS_FALSE;
                } else if (c == ']' || !JS_ISXMLSPACE(c)) {
                    return JS_FALSE; // unexpected
                }
                break;
 
            case JSON_PARSE_STATE_ARRAY :
                if (c == ']') {
                    if (!CloseArray(cx, jp) || !PopState(jp))
                        return JS_FALSE;
                } else if (c == ',') {
                    if (!PushState(jp, JSON_PARSE_STATE_VALUE))
                        return JS_FALSE;
                } else if (!JS_ISXMLSPACE(c)) {
                    return JS_FALSE; // unexpected
                }
                break;
            case JSON_PARSE_STATE_OBJECT_PAIR :
                if (c == '"') {
                    // we want to be waiting for a : when the string has been read
                    *jp->statep = JSON_PARSE_STATE_OBJECT_IN_PAIR;
                    if (!PushState(jp, JSON_PARSE_STATE_STRING))
                        return JS_FALSE;
                } else if (c == '}') {
                    // pop off the object pair state and the object state
                    if (!CloseObject(cx, jp) || !PopState(jp) || !PopState(jp))
                        return JS_FALSE;
                } else if (c == ']' || !JS_ISXMLSPACE(c)) {
                  return JS_FALSE; // unexpected
                }
                break;
            case JSON_PARSE_STATE_OBJECT_IN_PAIR:
                if (c == ':') {
                    *jp->statep = JSON_PARSE_STATE_VALUE;
                } else if (!JS_ISXMLSPACE(c)) {
                    return JS_FALSE; // unexpected
                }
                break;
            case JSON_PARSE_STATE_STRING:
                if (c == '"') {
                    if (!PopState(jp))
                        return JS_FALSE;
                    JSONDataType jdt;
                    if (*jp->statep == JSON_PARSE_STATE_OBJECT_IN_PAIR) {
                        jdt = JSON_DATA_KEYSTRING;
                    } else {
                        jdt = JSON_DATA_STRING;
                    }
                    if (!HandleData(cx, jp, jdt, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
                        return JS_FALSE;
                } else if (c == '\\') {
                    *jp->statep = JSON_PARSE_STATE_STRING_ESCAPE;
                } else {
                    js_AppendChar(jp->buffer, c);
                }
                break;
        
            case JSON_PARSE_STATE_STRING_ESCAPE:
                switch(c) {
                    case '"':
                    case '\\':
                    case '/':
                        break;
                    case 'b' : c = '\b'; break;
                    case 'f' : c = '\f'; break;
                    case 'n' : c = '\n'; break;
                    case 'r' : c = '\r'; break;
                    case 't' : c = '\t'; break;
                    default :
                        if (c == 'u') {
                            jp->numHex = 0;
                            jp->hexChar = 0;
                            *jp->statep = JSON_PARSE_STATE_STRING_HEX;
                            continue;
                        } else {
                            return JS_FALSE; // unexpected
                        }
                }
 
                js_AppendChar(jp->buffer, c);
                *jp->statep = JSON_PARSE_STATE_STRING;
                break;
            case JSON_PARSE_STATE_STRING_HEX:
                if (('0' <= c) && (c <= '9'))
                  jp->hexChar = (jp->hexChar << 4) | (c - '0');
                else if (('a' <= c) && (c <= 'f'))
                  jp->hexChar = (jp->hexChar << 4) | (c - 'a' + 0x0a);
                else if (('A' <= c) && (c <= 'F'))
                  jp->hexChar = (jp->hexChar << 4) | (c - 'A' + 0x0a);
                else
                  return JS_FALSE; // unexpected
 
                if (++(jp->numHex) == 4) {
                    js_AppendChar(jp->buffer, jp->hexChar);
                    jp->hexChar = 0;
                    jp->numHex = 0;
                    *jp->statep = JSON_PARSE_STATE_STRING;
                }
                break;
            case JSON_PARSE_STATE_KEYWORD:
                if (JS7_ISLET(c)) {
                    js_AppendChar(jp->buffer, c);
                } else {
                    // this character isn't part of the keyword, process it again
                    i--;
                    if(!PopState(jp))
                        return JS_FALSE;
                
                    if (!HandleData(cx, jp, JSON_DATA_KEYWORD, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
                        return JS_FALSE;
                }
                break;
            case JSON_PARSE_STATE_NUMBER:
                if (IsNumChar(c)) {
                    js_AppendChar(jp->buffer, c);
                } else {
                    // this character isn't part of the number, process it again
                    i--;
                    if(!PopState(jp))
                        return JS_FALSE;
                    if (!HandleData(cx, jp, JSON_DATA_NUMBER, jp->buffer->base, STRING_BUFFER_OFFSET(jp->buffer)))
                        return JS_FALSE;
                }
                break;
            case JSON_PARSE_STATE_FINISHED:
                if (!JS_ISXMLSPACE(c))
                  return JS_FALSE; // extra input
 
                break;
            default:
                JS_NOT_REACHED("Invalid JSON parser state");
      }
    }
 
    return JS_TRUE;
}
Ejemplo n.º 12
0
void
GCMarker::dumpConservativeRoots()
{
    if (!conservativeDumpFileName)
        return;

    FILE *fp;
    if (!strcmp(conservativeDumpFileName, "stdout")) {
        fp = stdout;
    } else if (!strcmp(conservativeDumpFileName, "stderr")) {
        fp = stderr;
    } else if (!(fp = fopen(conservativeDumpFileName, "aw"))) {
        fprintf(stderr,
                "Warning: cannot open %s to dump the conservative roots\n",
                conservativeDumpFileName);
        return;
    }

    conservativeStats.dump(fp);

    for (void **thingp = conservativeRoots.begin(); thingp != conservativeRoots.end(); ++thingp) {
        void *thing = thingp;
        fprintf(fp, "  %p: ", thing);
        
        switch (GetGCThingTraceKind(thing)) {
          default:
            JS_NOT_REACHED("Unknown trace kind");

          case JSTRACE_OBJECT: {
            JSObject *obj = (JSObject *) thing;
            fprintf(fp, "object %s", obj->getClass()->name);
            break;
          }
          case JSTRACE_SHAPE: {
            fprintf(fp, "shape");
            break;
          }
          case JSTRACE_STRING: {
            JSString *str = (JSString *) thing;
            if (str->isLinear()) {
                char buf[50];
                PutEscapedString(buf, sizeof buf, &str->asLinear(), '"');
                fprintf(fp, "string %s", buf);
            } else {
                fprintf(fp, "rope: length %d", (int)str->length());
            }
            break;
          }
# if JS_HAS_XML_SUPPORT
          case JSTRACE_XML: {
            JSXML *xml = (JSXML *) thing;
            fprintf(fp, "xml %u", (unsigned)xml->xml_class);
            break;
          }
# endif
        }
        fputc('\n', fp);
    }
    fputc('\n', fp);

    if (fp != stdout && fp != stderr)
        fclose(fp);
}
Ejemplo n.º 13
0
// ICBinaryArith_Int32
// by wangqing, 2013-11-22
bool
ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm)
{
    // Guard that R0 is an integer and R1 is an integer.
    Label failure;
	
    masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister);
    masm.bne(R0.typeReg(), cmpTempRegister, &failure);
    masm.nop();

    masm.movl(ImmTag(JSVAL_TAG_INT32), cmpTempRegister);
    masm.bne(R1.typeReg(), cmpTempRegister, &failure);
    masm.nop();

    // Add R0 and R1.  Don't need to explicitly unbox, just use the TailCallReg which
    // should be available.
    Register scratchReg = BaselineTailCallReg;

    Label revertRegister, maybeNegZero;
    // xsb:fix me
    // fixed by weizhenwei, 2013.11.05
    switch(op_) {
      case JSOP_ADD:
        // Add R0 and R1.  Don't need to explicitly unbox.
      
        // mov tow oprand to cmp registers to prepared for Overflow check.
        masm.cmpl(R0.payloadReg(), R1.payloadReg());
        masm.negl(cmpTemp2Register);

        // do the add
        masm.movl(R0.payloadReg(), scratchReg);
        masm.addl(R1.payloadReg(), scratchReg);

        // Just jump to failure on overflow.  R0 and R1 are preserved, so we can just jump to
        // the next stub.
    	masm.xorInsn(dataTempRegister, cmpTempRegister, cmpTemp2Register);
		masm.bgez(dataTempRegister, 7);
		masm.nop();
		masm.subu(dataTempRegister, cmpTempRegister, cmpTemp2Register);
		masm.xorInsn(dataTempRegister, dataTempRegister, cmpTempRegister);
		masm.bgez(dataTempRegister, 3);
		masm.nop();
		masm.b(&failure);
		masm.nop();

        // Just overwrite the payload, the tag is still fine.
        masm.movl(scratchReg, R0.payloadReg());
        break;
      case JSOP_SUB:
        masm.cmpl(R0.payloadReg(), R1.payloadReg());

        masm.movl(R0.payloadReg(), scratchReg);
        masm.subl(R1.payloadReg(), scratchReg);

		// jump to failure on overflow, by wangqing, 2013-11-22
		masm.xorInsn(dataTempRegister, cmpTempRegister, cmpTemp2Register);
		masm.bgez(dataTempRegister, 7);
		masm.nop();
		masm.subu(dataTempRegister, cmpTempRegister, cmpTemp2Register);
		masm.xorInsn(dataTempRegister, dataTempRegister, cmpTempRegister);
		masm.bgez(dataTempRegister, 3);
		masm.nop();
		masm.b(&failure);
		masm.nop();

        masm.movl(scratchReg, R0.payloadReg());
        break;
      case JSOP_MUL:
        masm.movl(R0.payloadReg(), scratchReg);
        masm.imull(R1.payloadReg(), scratchReg);

        // test whether signed multiply overflow. by weizhenwei, 2013.11.01
        masm.mfhi(cmpTempRegister);
        masm.mflo(cmpTemp2Register);
        masm.sarl(Imm32(0x1f), cmpTemp2Register);
        masm.bne(cmpTempRegister, cmpTemp2Register, &failure);
		masm.nop();

		masm.beq(scratchReg, zero, &maybeNegZero);
		masm.nop();

        masm.movl(scratchReg, R0.payloadReg());
        break;
      case JSOP_DIV:
        // Prevent division by 0.
		masm.beq(R1.payloadReg(), zero, &failure);
		masm.nop();

        // Prevent negative 0 and -2147483648 / -1.
		/* rewrite testl(reg, imm), avoid use cmpTemp2Register by wangqing, 2013-11-22*/
		masm.movl(R0.payloadReg(), cmpTempRegister);
		masm.andl(Imm32(0x7fffffff), cmpTempRegister);
		masm.beq(cmpTempRegister, zero, &failure);
		masm.nop();

        // Preserve R0.payloadReg()
		masm.div(R0.payloadReg(), R1.payloadReg());

        // A remainder implies a double result.
        // by weizhenwei, 2013.11.02
        masm.mfhi(cmpTempRegister);
		masm.bne(cmpTempRegister, zero, &failure);
		masm.nop();

        // by weizhenwei, 2013.11.05
        masm.mflo(R0.payloadReg());
        break;
      case JSOP_MOD:
      {
        // x % 0 always results in NaN.
		masm.beq(R1.payloadReg(), zero, &failure);
		masm.nop();

        // Prevent negative 0 and -2147483648 % -1.
		/* rewrite testl(reg, imm), avoid use cmpTemp2Register by wangqing, 2013-11-22*/
		masm.movl(R0.payloadReg(), cmpTempRegister);
		masm.andl(Imm32(0x7fffffff), cmpTempRegister);
		masm.beq(cmpTempRegister, zero, &failure);
		masm.nop();

    	masm.div(R0.payloadReg(), R1.payloadReg());

        // Fail when we would need a negative remainder.
        Label done;
        masm.mfhi(cmpTempRegister);
	    masm.bne(cmpTempRegister, zero, &done);
	    masm.nop();

	    masm.bltz(R0.payloadReg(), &failure);
	    masm.nop();

	    masm.bltz(R1.payloadReg(), &failure);
	    masm.nop();

        masm.bindBranch(&done);

        //move reminder to R0.payloadReg, by weizhenwei, 2013.11.05
        masm.mfhi(R0.payloadReg());
        break;
      }
      case JSOP_BITOR:
        // We can overide R0, because the instruction is unfailable.
        // The R0.typeReg() is also still intact.
        masm.orl(R1.payloadReg(), R0.payloadReg());
        break;
      case JSOP_BITXOR:
        masm.xorl(R1.payloadReg(), R0.payloadReg());
        break;
      case JSOP_BITAND:
        masm.andl(R1.payloadReg(), R0.payloadReg());
        break;
      case JSOP_LSH:
        // R0.payloadReg() is result, R1.payloadReg90 is shiftAmount.
        // rewrite by weizhenwei, 2013.11.06
        masm.sllv(R0.payloadReg(), R0.payloadReg(), R1.payloadReg());

        // We need to tag again, because we overwrote it.
        masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
        break;
      case JSOP_RSH:
        // R0.payloadReg() is result, R1.payloadReg90 is shiftAmount.
        // rewrite by weizhenwei, 2013.11.06
        masm.srav(R0.payloadReg(), R0.payloadReg(), R1.payloadReg());

        // We need to tag again, because we overwrote it.
        masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
        break;
      case JSOP_URSH:
        if (!allowDouble_)
            masm.movl(R0.payloadReg(), scratchReg);

        // R0.payloadReg() is result, R1.payloadReg() is shiftAmount.
        // rewrite by weizhenwei, 2013.11.06
        masm.srlv(R0.payloadReg(), R0.payloadReg(), R1.payloadReg());

        // by wangqing. 2013-11-22
        if (allowDouble_) {
            Label toUint;
	        masm.bltz(R0.payloadReg(),&toUint);
	        masm.nop();

            // Box and return.
            masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
            EmitReturnFromIC(masm);

            masm.bindBranch(&toUint);
            masm.convertUInt32ToDouble(R0.payloadReg(), ScratchFloatReg);
            masm.boxDouble(ScratchFloatReg, R0);
        } else {
	        masm.bltz(R0.payloadReg(),&revertRegister);
	        masm.nop();
            masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
        }
        break;
      default:
       JS_NOT_REACHED("Unhandled op for BinaryArith_Int32.  ");
       return false;
    }

    // Return.
    EmitReturnFromIC(masm);

    switch(op_) {
      case JSOP_MUL:
        masm.bindBranch(&maybeNegZero);

        // Result is -0 if exactly one of lhs or rhs is negative.
        masm.movl(R0.payloadReg(), scratchReg);
        masm.orl(R1.payloadReg(), scratchReg);
        //add by QuQiuwen;
	    masm.bltz(scratchReg, &failure);
	    masm.nop();

        // Result is +0.
        masm.xorl(R0.payloadReg(), R0.payloadReg());
        EmitReturnFromIC(masm);
        break;
      case JSOP_URSH:
        // Revert the content of R0 in the fallible >>> case.
        if (!allowDouble_) {
            masm.bindBranch(&revertRegister);
            masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
        }
        break;
      default:
        // No special failure handling required.
        // Fall through to failure.
        break;
    }

    // Failure case - jump to next stub
    masm.bindBranch(&failure);
    EmitStubGuardFailure(masm);

    return true;
}
Ejemplo n.º 14
0
bool
ICBinaryArith_Int32::Compiler::generateStubCode(MacroAssembler &masm)
{
    // Guard that R0 is an integer and R1 is an integer.
    Label failure;
    masm.branchTestInt32(Assembler::NotEqual, R0, &failure);
    masm.branchTestInt32(Assembler::NotEqual, R1, &failure);

    // Add R0 and R1.  Don't need to explicitly unbox, just use the TailCallReg which
    // should be available.
    Register scratchReg = BaselineTailCallReg;

    Label revertRegister, maybeNegZero;
    switch(op_) {
      case JSOP_ADD:
        // Add R0 and R1.  Don't need to explicitly unbox.
        masm.movl(R0.payloadReg(), scratchReg);
        masm.addl(R1.payloadReg(), scratchReg);

        // Just jump to failure on overflow.  R0 and R1 are preserved, so we can just jump to
        // the next stub.
        masm.j(Assembler::Overflow, &failure);

        // Just overwrite the payload, the tag is still fine.
        masm.movl(scratchReg, R0.payloadReg());
        break;
      case JSOP_SUB:
        masm.movl(R0.payloadReg(), scratchReg);
        masm.subl(R1.payloadReg(), scratchReg);
        masm.j(Assembler::Overflow, &failure);
        masm.movl(scratchReg, R0.payloadReg());
        break;
      case JSOP_MUL:
        masm.movl(R0.payloadReg(), scratchReg);
        masm.imull(R1.payloadReg(), scratchReg);
        masm.j(Assembler::Overflow, &failure);

        masm.testl(scratchReg, scratchReg);
        masm.j(Assembler::Zero, &maybeNegZero);

        masm.movl(scratchReg, R0.payloadReg());
        break;
      case JSOP_DIV:
        // Prevent division by 0.
        masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure);

        // Prevent negative 0 and -2147483648 / -1.
        masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure);

        // For idiv we need eax.
        JS_ASSERT(R1.typeReg() == eax);
        masm.movl(R0.payloadReg(), eax);
        // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32.
        masm.movl(R0.payloadReg(), scratchReg);
        // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit.
        masm.cdq();
        masm.idiv(R1.payloadReg());

        // A remainder implies a double result.
        masm.branchTest32(Assembler::NonZero, edx, edx, &revertRegister);

        masm.movl(eax, R0.payloadReg());
        break;
      case JSOP_MOD:
      {
        // x % 0 always results in NaN.
        masm.branchTest32(Assembler::Zero, R1.payloadReg(), R1.payloadReg(), &failure);

        // Prevent negative 0 and -2147483648 % -1.
        masm.branchTest32(Assembler::Zero, R0.payloadReg(), Imm32(0x7fffffff), &failure);

        // For idiv we need eax.
        JS_ASSERT(R1.typeReg() == eax);
        masm.movl(R0.payloadReg(), eax);
        // Preserve R0.payloadReg()/edx, eax is JSVAL_TYPE_INT32.
        masm.movl(R0.payloadReg(), scratchReg);
        // Sign extend eax into edx to make (edx:eax), since idiv is 64-bit.
        masm.cdq();
        masm.idiv(R1.payloadReg());

        // Fail when we would need a negative remainder.
        Label done;
        masm.branchTest32(Assembler::NonZero, edx, edx, &done);
        masm.branchTest32(Assembler::Signed, scratchReg, scratchReg, &revertRegister);
        masm.branchTest32(Assembler::Signed, R1.payloadReg(), R1.payloadReg(), &revertRegister);

        masm.bind(&done);
        // Result is in edx, tag in ecx remains untouched.
        JS_ASSERT(R0.payloadReg() == edx);
        JS_ASSERT(R0.typeReg() == ecx);
        break;
      }
      case JSOP_BITOR:
        // We can overide R0, because the instruction is unfailable.
        // The R0.typeReg() is also still intact.
        masm.orl(R1.payloadReg(), R0.payloadReg());
        break;
      case JSOP_BITXOR:
        masm.xorl(R1.payloadReg(), R0.payloadReg());
        break;
      case JSOP_BITAND:
        masm.andl(R1.payloadReg(), R0.payloadReg());
        break;
      case JSOP_LSH:
        // RHS needs to be in ecx for shift operations.
        JS_ASSERT(R0.typeReg() == ecx);
        masm.movl(R1.payloadReg(), ecx);
        masm.shll_cl(R0.payloadReg());
        // We need to tag again, because we overwrote it.
        masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
        break;
      case JSOP_RSH:
        masm.movl(R1.payloadReg(), ecx);
        masm.sarl_cl(R0.payloadReg());
        masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
        break;
      case JSOP_URSH:
        if (!allowDouble_)
            masm.movl(R0.payloadReg(), scratchReg);

        masm.movl(R1.payloadReg(), ecx);
        masm.shrl_cl(R0.payloadReg());
        masm.testl(R0.payloadReg(), R0.payloadReg());
        if (allowDouble_) {
            Label toUint;
            masm.j(Assembler::Signed, &toUint);

            // Box and return.
            masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
            EmitReturnFromIC(masm);

            masm.bind(&toUint);
            masm.convertUInt32ToDouble(R0.payloadReg(), ScratchFloatReg);
            masm.boxDouble(ScratchFloatReg, R0);
        } else {
            masm.j(Assembler::Signed, &revertRegister);
            masm.tagValue(JSVAL_TYPE_INT32, R0.payloadReg(), R0);
        }
        break;
      default:
       JS_NOT_REACHED("Unhandled op for BinaryArith_Int32.  ");
       return false;
    }

    // Return.
    EmitReturnFromIC(masm);

    switch(op_) {
      case JSOP_MUL:
        masm.bind(&maybeNegZero);

        // Result is -0 if exactly one of lhs or rhs is negative.
        masm.movl(R0.payloadReg(), scratchReg);
        masm.orl(R1.payloadReg(), scratchReg);
        masm.j(Assembler::Signed, &failure);

        // Result is +0.
        masm.xorl(R0.payloadReg(), R0.payloadReg());
        EmitReturnFromIC(masm);
        break;
      case JSOP_DIV:
      case JSOP_MOD:
        masm.bind(&revertRegister);
        masm.movl(scratchReg, R0.payloadReg());
        masm.movl(ImmType(JSVAL_TYPE_INT32), R1.typeReg());
        break;
      case JSOP_URSH:
        // Revert the content of R0 in the fallible >>> case.
        if (!allowDouble_) {
            masm.bind(&revertRegister);
            masm.tagValue(JSVAL_TYPE_INT32, scratchReg, R0);
        }
        break;
      default:
        // No special failure handling required.
        // Fall through to failure.
        break;
    }

    // Failure case - jump to next stub
    masm.bind(&failure);
    EmitStubGuardFailure(masm);

    return true;
}
Ejemplo n.º 15
0
JS_REQUIRES_STACK AbortableRecordingStatus
TraceRecorder::slurpDownFrames(jsbytecode* return_pc)
{
    /* Missing - no go */
    if (cx->fp->argc != cx->fp->fun->nargs)
        RETURN_STOP_A("argc != nargs");

    LIns* argv_ins;
    unsigned frameDepth;
    unsigned downPostSlots;

    JSStackFrame* fp = cx->fp;
    LIns* fp_ins = addName(lir->insLoad(LIR_ldp, cx_ins, offsetof(JSContext, fp)), "fp");

    /*
     * When first emitting slurp code, do so against the down frame. After
     * popping the interpreter frame, it is illegal to resume here, as the
     * down frame has been moved up. So all this code should be skipped if
     * anchoring off such an exit.
     */
    if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
        fp_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, down)), "downFp");
        fp = fp->down;

        argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv)), "argv");

        /* If recovering from a SLURP_MISMATCH, all of this is unnecessary. */
        if (!anchor || anchor->exitType != RECURSIVE_SLURP_MISMATCH_EXIT) {
            /* fp->down should not be NULL. */
            guard(false, lir->ins_peq0(fp_ins), RECURSIVE_LOOP_EXIT);

            /* fp->down->argv should not be NULL. */
            guard(false, lir->ins_peq0(argv_ins), RECURSIVE_LOOP_EXIT);

            /*
             * Guard on the script being the same. This might seem unnecessary,
             * but it lets the recursive loop end cleanly if it doesn't match.
             * With only the pc check, it is harder to differentiate between
             * end-of-recursion and recursion-returns-to-different-pc.
             */
            guard(true,
                  lir->ins2(LIR_peq,
                            addName(lir->insLoad(LIR_ldp,
                                                 fp_ins,
                                                 offsetof(JSStackFrame, script)),
                                    "script"),
                            INS_CONSTPTR(cx->fp->down->script)),
                  RECURSIVE_LOOP_EXIT);
        }

        /* fp->down->regs->pc should be == pc. */
        guard(true,
              lir->ins2(LIR_peq,
                        lir->insLoad(LIR_ldp,
                                     addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, regs)),
                                             "regs"),
                                     offsetof(JSFrameRegs, pc)),
                        INS_CONSTPTR(return_pc)),
              RECURSIVE_SLURP_MISMATCH_EXIT);

        /* fp->down->argc should be == argc. */
        guard(true,
              lir->ins2(LIR_eq,
                        addName(lir->insLoad(LIR_ld, fp_ins, offsetof(JSStackFrame, argc)),
                                "argc"),
                        INS_CONST(cx->fp->argc)),
              MISMATCH_EXIT);

        /* Pop the interpreter frame. */
        LIns* args[] = { lirbuf->state, cx_ins };
        guard(false, lir->ins_eq0(lir->insCall(&js_PopInterpFrame_ci, args)), MISMATCH_EXIT);

        /* Compute slots for the down frame. */
        downPostSlots = NativeStackSlots(cx, 1) - NativeStackSlots(cx, 0);
        frameDepth = 1;
    } else {
        /* Note: loading argv from fp, not fp->down. */
        argv_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argv)), "argv");

        /* Slots for this frame, minus the return value. */
        downPostSlots = NativeStackSlots(cx, 0) - 1;
        frameDepth = 0;
    }

    /*
     * This is a special exit used as a template for the stack-slurping code.
     * LeaveTree will ignore all but the final slot, which contains the return
     * value. The slurpSlot variable keeps track of the last slot that has been
     * unboxed, as to avoid re-unboxing when taking a SLURP_FAIL exit.
     */
    unsigned numGlobalSlots = tree->globalSlots->length();
    unsigned safeSlots = NativeStackSlots(cx, frameDepth) + 1 + numGlobalSlots;
    jsbytecode* recursive_pc = return_pc + JSOP_CALL_LENGTH;
    VMSideExit* exit = (VMSideExit*)
        traceMonitor->traceAlloc->alloc(sizeof(VMSideExit) + sizeof(TraceType) * safeSlots);
    memset(exit, 0, sizeof(VMSideExit));
    exit->pc = (jsbytecode*)recursive_pc;
    exit->from = fragment;
    exit->exitType = RECURSIVE_SLURP_FAIL_EXIT;
    exit->numStackSlots = downPostSlots + 1;
    exit->numGlobalSlots = numGlobalSlots;
    exit->sp_adj = ((downPostSlots + 1) * sizeof(double)) - tree->nativeStackBase;
    exit->recursive_pc = recursive_pc;

    /*
     * Build the exit typemap. This may capture extra types, but they are
     * thrown away.
     */
    TraceType* typeMap = exit->stackTypeMap();
    jsbytecode* oldpc = cx->fp->regs->pc;
    cx->fp->regs->pc = exit->pc;
    CaptureStackTypes(cx, frameDepth, typeMap);
    cx->fp->regs->pc = oldpc;
    if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT)
        typeMap[downPostSlots] = determineSlotType(&stackval(-1));
    else
        typeMap[downPostSlots] = anchor->stackTypeMap()[anchor->numStackSlots - 1];
    determineGlobalTypes(&typeMap[exit->numStackSlots]);
#if defined JS_JIT_SPEW
    TreevisLogExit(cx, exit);
#endif

    /*
     * Return values are tricky because there are two cases. Anchoring off a
     * slurp failure (the second case) means the return value has already been
     * moved. However it can still be promoted to link trees together, so we
     * load it from the new location.
     *
     * In all other cases, the return value lives in the tracker and it can be
     * grabbed safely.
     */
    LIns* rval_ins;
    TraceType returnType = exit->stackTypeMap()[downPostSlots];
    if (!anchor || anchor->exitType != RECURSIVE_SLURP_FAIL_EXIT) {
        rval_ins = get(&stackval(-1));
        if (returnType == TT_INT32) {
            JS_ASSERT(determineSlotType(&stackval(-1)) == TT_INT32);
            JS_ASSERT(isPromoteInt(rval_ins));
            rval_ins = demote(lir, rval_ins);
        }
        /*
         * The return value must be written out early, before slurping can fail,
         * otherwise it will not be available when there's a type mismatch.
         */
        lir->insStorei(rval_ins, lirbuf->sp, exit->sp_adj - sizeof(double));
    } else {
        switch (returnType)
        {
          case TT_PSEUDOBOOLEAN:
          case TT_INT32:
            rval_ins = lir->insLoad(LIR_ld, lirbuf->sp, exit->sp_adj - sizeof(double));
            break;
          case TT_DOUBLE:
            rval_ins = lir->insLoad(LIR_ldf, lirbuf->sp, exit->sp_adj - sizeof(double));
            break;
          case TT_FUNCTION:
          case TT_OBJECT:
          case TT_STRING:
          case TT_NULL:
            rval_ins = lir->insLoad(LIR_ldp, lirbuf->sp, exit->sp_adj - sizeof(double));
            break;
          default:
            JS_NOT_REACHED("unknown type");
            RETURN_STOP_A("unknown type"); 
        }
    }

    /* Slurp */
    SlurpInfo info;
    info.curSlot = 0;
    info.exit = exit;
    info.typeMap = typeMap;
    info.slurpFailSlot = (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT) ?
                         anchor->slurpFailSlot : 0;

    /* callee */
    slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -2 * ptrdiff_t(sizeof(jsval))),
              &fp->argv[-2],
              &info);
    /* this */
    slurpSlot(lir->insLoad(LIR_ldp, argv_ins, -1 * ptrdiff_t(sizeof(jsval))),
              &fp->argv[-1],
              &info);
    /* args[0..n] */
    for (unsigned i = 0; i < JS_MAX(fp->argc, fp->fun->nargs); i++)
        slurpSlot(lir->insLoad(LIR_ldp, argv_ins, i * sizeof(jsval)), &fp->argv[i], &info);
    /* argsobj */
    slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, argsobj)), "argsobj"),
              &fp->argsobj,
              &info);
    /* scopeChain */
    slurpSlot(addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, scopeChain)), "scopeChain"),
              (jsval*) &fp->scopeChain,
              &info);
    /* vars */
    LIns* slots_ins = addName(lir->insLoad(LIR_ldp, fp_ins, offsetof(JSStackFrame, slots)),
                              "slots");
    for (unsigned i = 0; i < fp->script->nfixed; i++)
        slurpSlot(lir->insLoad(LIR_ldp, slots_ins, i * sizeof(jsval)), &fp->slots[i], &info);
    /* stack vals */
    unsigned nfixed = fp->script->nfixed;
    jsval* stack = StackBase(fp);
    LIns* stack_ins = addName(lir->ins2(LIR_piadd,
                                        slots_ins,
                                        INS_CONSTWORD(nfixed * sizeof(jsval))),
                              "stackBase");
    size_t limit = size_t(fp->regs->sp - StackBase(fp));
    if (anchor && anchor->exitType == RECURSIVE_SLURP_FAIL_EXIT)
        limit--;
    else
        limit -= fp->fun->nargs + 2;
    for (size_t i = 0; i < limit; i++)
        slurpSlot(lir->insLoad(LIR_ldp, stack_ins, i * sizeof(jsval)), &stack[i], &info);

    JS_ASSERT(info.curSlot == downPostSlots);

    /* Jump back to the start */
    exit = copy(exit);
    exit->exitType = UNSTABLE_LOOP_EXIT;
#if defined JS_JIT_SPEW
    TreevisLogExit(cx, exit);
#endif

    RecursiveSlotMap slotMap(*this, downPostSlots, rval_ins);
    for (unsigned i = 0; i < downPostSlots; i++)
        slotMap.addSlot(typeMap[i]);
    slotMap.addSlot(&stackval(-1), typeMap[downPostSlots]);
    VisitGlobalSlots(slotMap, cx, *tree->globalSlots);
    debug_only_print0(LC_TMTracer, "Compiling up-recursive slurp...\n");
    exit = copy(exit);
    if (exit->recursive_pc == fragment->root->ip)
        exit->exitType = UNSTABLE_LOOP_EXIT;
    else
        exit->exitType = RECURSIVE_UNLINKED_EXIT;
    debug_only_printf(LC_TMTreeVis, "TREEVIS CHANGEEXIT EXIT=%p TYPE=%s\n", (void*)exit,
                      getExitName(exit->exitType));
    JS_ASSERT(tree->recursion >= Recursion_Unwinds);
    return closeLoop(slotMap, exit);
}