<commit_before>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorFilter.h"
#include "SkColorSpaceXform.h"
#include "SkColorSpaceXformCanvas.h"
#include "SkImage_Base.h"
#include "SkMakeUnique.h"
#include "SkNoDrawCanvas.h"
#include "SkSurface.h"
#include "SkTLazy.h"

class SkColorSpaceXformCanvas : public SkNoDrawCanvas {
public:
    SkColorSpaceXformCanvas(SkCanvas* target,
                            sk_sp<SkColorSpace> targetCS)
        : SkNoDrawCanvas(SkIRect::MakeSize(target->getBaseLayerSize()))
        , fTarget(target)
        , fTargetCS(std::move(targetCS)) {

        fFromSRGB = SkColorSpaceXform::New(SkColorSpace::MakeSRGB().get(), fTargetCS.get());
    }

    void xform(SkColor* xformed, const SkColor* srgb, int n) const {
        SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, xformed,
                                        SkColorSpaceXform::kBGRA_8888_ColorFormat, srgb,
                                        n, kUnpremul_SkAlphaType));
    }

    SkColor xform(SkColor srgb) const {
        SkColor xformed;
        this->xform(&xformed, &srgb, 1);
        return xformed;
    }

    const SkPaint& xform(const SkPaint& paint, SkTLazy<SkPaint>* lazy) const {
        const SkPaint* result = &paint;
        auto get_lazy = [&] {
            if (!lazy->isValid()) {
                lazy->init(paint);
                result = lazy->get();
            }
            return lazy->get();
        };

        // All SkColorSpaces have the same black point.
        if (paint.getColor() & 0xffffff) {
            get_lazy()->setColor(this->xform(paint.getColor()));
        }

        // As far as I know, SkModeColorFilter is the only color filter that holds a color.
        if (auto cf = paint.getColorFilter()) {
            SkColor color;
            SkBlendMode mode;
            if (cf->asColorMode(&color, &mode)) {
                get_lazy()->setColorFilter(SkColorFilter::MakeModeFilter(this->xform(color), mode));
            }
        }

        // TODO:
        //    - shaders
        //    - image filters?

        return *result;
    }

    const SkPaint* xform(const SkPaint* paint, SkTLazy<SkPaint>* lazy) const {
        return paint ? &this->xform(*paint, lazy) : nullptr;
    }

    sk_sp<const SkImage> xform(const SkImage* img) const {
        return as_IB(img)->makeColorSpace(fTargetCS);
    }

    void onDrawPaint(const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPaint(this->xform(paint, &lazy));
    }

    void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawRect(rect, this->xform(paint, &lazy));
    }
    void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawOval(oval, this->xform(paint, &lazy));
    }
    void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawRRect(rrect, this->xform(paint, &lazy));
    }
    void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawDRRect(outer, inner, this->xform(paint, &lazy));
    }
    void onDrawPath(const SkPath& path, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPath(path, this->xform(paint, &lazy));
    }
    void onDrawArc(const SkRect& oval, SkScalar start, SkScalar sweep, bool useCenter,
                   const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawArc(oval, start, sweep, useCenter, this->xform(paint, &lazy));
    }
    void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawRegion(region, this->xform(paint, &lazy));
    }
    void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4],
                     SkBlendMode mode, const SkPaint& paint) override {
        SkColor xformed[4];
        if (colors) {
            this->xform(xformed, colors, 4);
            colors = xformed;
        }

        SkTLazy<SkPaint> lazy;
        fTarget->drawPatch(cubics, colors, texs, mode, this->xform(paint, &lazy));
    }
    void onDrawPoints(PointMode mode, size_t count, const SkPoint* pts,
                      const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPoints(mode, count, pts, this->xform(paint, &lazy));
    }
    void onDrawVertices(VertexMode vmode, int count,
                        const SkPoint* verts, const SkPoint* texs, const SkColor* colors,
                        SkBlendMode mode,
                        const uint16_t* indices, int indexCount, const SkPaint& paint) override {
        SkTArray<SkColor> xformed;
        if (colors) {
            xformed.reset(count);
            this->xform(xformed.begin(), colors, count);
            colors = xformed.begin();
        }

        SkTLazy<SkPaint> lazy;
        fTarget->drawVertices(vmode, count, verts, texs, colors, mode, indices, indexCount,
                              this->xform(paint, &lazy));
    }

    void onDrawText(const void* ptr, size_t len,
                    SkScalar x, SkScalar y,
                    const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawText(ptr, len, x, y, this->xform(paint, &lazy));
    }
    void onDrawPosText(const void* ptr, size_t len,
                       const SkPoint* xys,
                       const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPosText(ptr, len, xys, this->xform(paint, &lazy));
    }
    void onDrawPosTextH(const void* ptr, size_t len,
                        const SkScalar* xs, SkScalar y,
                        const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPosTextH(ptr, len, xs, y, this->xform(paint, &lazy));
    }
    void onDrawTextOnPath(const void* ptr, size_t len,
                          const SkPath& path, const SkMatrix* matrix,
                          const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawTextOnPath(ptr, len, path, matrix, this->xform(paint, &lazy));
    }
    void onDrawTextRSXform(const void* ptr, size_t len,
                           const SkRSXform* xforms, const SkRect* cull,
                           const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawTextRSXform(ptr, len, xforms, cull, this->xform(paint, &lazy));
    }
    void onDrawTextBlob(const SkTextBlob* blob,
                        SkScalar x, SkScalar y,
                        const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawTextBlob(blob, x, y, this->xform(paint, &lazy));
    }

    void onDrawImage(const SkImage* img,
                     SkScalar l, SkScalar t,
                     const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImage(this->xform(img).get(),
                           l, t,
                           this->xform(paint, &lazy));
    }
    void onDrawImageRect(const SkImage* img,
                         const SkRect* src, const SkRect& dst,
                         const SkPaint* paint, SrcRectConstraint constraint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImageRect(this->xform(img).get(),
                               src ? *src : dst, dst,
                               this->xform(paint, &lazy), constraint);
    }
    void onDrawImageNine(const SkImage* img,
                         const SkIRect& center, const SkRect& dst,
                         const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImageNine(this->xform(img).get(),
                               center, dst,
                               this->xform(paint, &lazy));
    }
    void onDrawImageLattice(const SkImage* img,
                            const Lattice& lattice, const SkRect& dst,
                            const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImageLattice(this->xform(img).get(),
                                  lattice, dst,
                                  this->xform(paint, &lazy));
    }
    void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex,
                     const SkColor* colors, int count, SkBlendMode mode,
                     const SkRect* cull, const SkPaint* paint) override {
        SkTArray<SkColor> xformed;
        if (colors) {
            xformed.reset(count);
            this->xform(xformed.begin(), colors, count);
            colors = xformed.begin();
        }

        SkTLazy<SkPaint> lazy;
        fTarget->drawAtlas(this->xform(atlas).get(), xforms, tex, colors, count, mode, cull,
                           this->xform(paint, &lazy));
    }

    void onDrawBitmap(const SkBitmap& bitmap,
                      SkScalar l, SkScalar t,
                      const SkPaint* paint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImage(image.get(), l, t, paint);
        }
    }
    void onDrawBitmapRect(const SkBitmap& bitmap,
                          const SkRect* src, const SkRect& dst,
                          const SkPaint* paint, SrcRectConstraint constraint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImageRect(image.get(), src, dst, paint, constraint);
        }
    }
    void onDrawBitmapNine(const SkBitmap& bitmap,
                          const SkIRect& center, const SkRect& dst,
                          const SkPaint* paint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImageNine(image.get(), center, dst, paint);
        }
    }
    void onDrawBitmapLattice(const SkBitmap& bitmap,
                             const Lattice& lattice, const SkRect& dst,
                             const SkPaint* paint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImageLattice(image.get(), lattice, dst, paint);
        }
    }

    // TODO: May not be ideal to unfurl pictures.
    void onDrawPicture(const SkPicture* pic,
                       const SkMatrix* matrix,
                       const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        SkCanvas::onDrawPicture(pic, matrix, this->xform(paint, &lazy));
    }
    void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
        SkTLazy<SkPaint> lazy;
        SkCanvas::onDrawDrawable(drawable, matrix);
    }

    SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
        SkTLazy<SkPaint> lazy;
        fTarget->saveLayer({
            rec.fBounds,
            this->xform(rec.fPaint, &lazy),
            rec.fBackdrop,  // TODO: this is an image filter
            rec.fSaveLayerFlags,
        });
        return kNoLayer_SaveLayerStrategy;
    }

    // Everything from here on should be uninteresting strictly proxied state-change calls.
    void willSave()    override { fTarget->save(); }
    void willRestore() override { fTarget->restore(); }

    void didConcat   (const SkMatrix& m) override { fTarget->concat   (m); }
    void didSetMatrix(const SkMatrix& m) override { fTarget->setMatrix(m); }

    void onClipRect(const SkRect& clip, SkClipOp op, ClipEdgeStyle style) override {
        fTarget->clipRect(clip, op, style);
    }
    void onClipRRect(const SkRRect& clip, SkClipOp op, ClipEdgeStyle style) override {
        fTarget->clipRRect(clip, op, style);
    }
    void onClipPath(const SkPath& clip, SkClipOp op, ClipEdgeStyle style) override {
        fTarget->clipPath(clip, op, style);
    }
    void onClipRegion(const SkRegion& clip, SkClipOp op) override {
        fTarget->clipRegion(clip, op);
    }

    void onDrawAnnotation(const SkRect& rect, const char* key, SkData* val) override {
        fTarget->drawAnnotation(rect, key, val);
    }

    sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) override {
        return fTarget->makeSurface(info, &props);
    }

private:
    SkCanvas*                          fTarget;
    sk_sp<SkColorSpace>                fTargetCS;
    std::unique_ptr<SkColorSpaceXform> fFromSRGB;
};

std::unique_ptr<SkCanvas> SkCreateColorSpaceXformCanvas(SkCanvas* target,
                                                        sk_sp<SkColorSpace> targetCS) {
    return skstd::make_unique<SkColorSpaceXformCanvas>(target, std::move(targetCS));
}
<commit_msg>SkColorSpaceXformCanvas: simple support for shaders<commit_after>/*
 * Copyright 2017 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "SkColorFilter.h"
#include "SkColorSpaceXform.h"
#include "SkColorSpaceXformCanvas.h"
#include "SkGradientShader.h"
#include "SkImage_Base.h"
#include "SkMakeUnique.h"
#include "SkNoDrawCanvas.h"
#include "SkSurface.h"
#include "SkTLazy.h"

class SkColorSpaceXformCanvas : public SkNoDrawCanvas {
public:
    SkColorSpaceXformCanvas(SkCanvas* target,
                            sk_sp<SkColorSpace> targetCS)
        : SkNoDrawCanvas(SkIRect::MakeSize(target->getBaseLayerSize()))
        , fTarget(target)
        , fTargetCS(std::move(targetCS)) {

        fFromSRGB = SkColorSpaceXform::New(SkColorSpace::MakeSRGB().get(), fTargetCS.get());
    }

    sk_sp<const SkImage> xform(const SkImage* img) const {
        return as_IB(img)->makeColorSpace(fTargetCS);
    }

    void xform(SkColor* xformed, const SkColor* srgb, int n) const {
        SkAssertResult(fFromSRGB->apply(SkColorSpaceXform::kBGRA_8888_ColorFormat, xformed,
                                        SkColorSpaceXform::kBGRA_8888_ColorFormat, srgb,
                                        n, kUnpremul_SkAlphaType));
    }

    SkColor xform(SkColor srgb) const {
        SkColor xformed;
        this->xform(&xformed, &srgb, 1);
        return xformed;
    }

    // TODO: Is this introspection going to be enough, or do we need a new SkShader method?
    sk_sp<SkShader> xform(const SkShader* shader) const {
        SkColor color;
        if (shader->isConstant() && shader->asLuminanceColor(&color)) {
            return SkShader::MakeColorShader(this->xform(color));
        }

        SkShader::TileMode xy[2];
        SkMatrix local;
        if (auto img = shader->isAImage(&local, xy)) {
            return this->xform(img)->makeShader(xy[0], xy[1], &local);
        }

        SkShader::ComposeRec compose;
        if (shader->asACompose(&compose)) {
            auto A = this->xform(compose.fShaderA),
                 B = this->xform(compose.fShaderB);
            if (A && B) {
                return SkShader::MakeComposeShader(std::move(A), std::move(B), compose.fBlendMode);
            }
        }

        SkShader::GradientInfo gradient;
        sk_bzero(&gradient, sizeof(gradient));
        if (auto type = shader->asAGradient(&gradient)) {
            SkSTArray<8, SkColor>  colors(gradient.fColorCount);
            SkSTArray<8, SkScalar>    pos(gradient.fColorCount);

            gradient.fColors       = colors.begin();
            gradient.fColorOffsets =    pos.begin();
            shader->asAGradient(&gradient);

            SkSTArray<8, SkColor> xformed(gradient.fColorCount);
            this->xform(xformed.begin(), gradient.fColors, gradient.fColorCount);

            switch (type) {
                case SkShader::kNone_GradientType:
                case SkShader::kColor_GradientType:
                    SkASSERT(false);  // Should be unreachable.
                    break;

                case SkShader::kLinear_GradientType:
                    return SkGradientShader::MakeLinear(gradient.fPoint,
                                                        xformed.begin(),
                                                        gradient.fColorOffsets,
                                                        gradient.fColorCount,
                                                        gradient.fTileMode,
                                                        gradient.fGradientFlags,
                                                        &shader->getLocalMatrix());
                case SkShader::kRadial_GradientType:  break;  // TODO
                case SkShader::kSweep_GradientType:   break;  // TODO
                case SkShader::kConical_GradientType: break;  // TODO
            }
        }

        return nullptr;
    }

    const SkPaint& xform(const SkPaint& paint, SkTLazy<SkPaint>* lazy) const {
        const SkPaint* result = &paint;
        auto get_lazy = [&] {
            if (!lazy->isValid()) {
                lazy->init(paint);
                result = lazy->get();
            }
            return lazy->get();
        };

        // All SkColorSpaces have the same black point.
        if (paint.getColor() & 0xffffff) {
            get_lazy()->setColor(this->xform(paint.getColor()));
        }

        if (auto shader = paint.getShader()) {
            if (auto replacement = this->xform(shader)) {
                get_lazy()->setShader(std::move(replacement));
            }
        }

        // As far as I know, SkModeColorFilter is the only color filter that holds a color.
        if (auto cf = paint.getColorFilter()) {
            SkColor color;
            SkBlendMode mode;
            if (cf->asColorMode(&color, &mode)) {
                get_lazy()->setColorFilter(SkColorFilter::MakeModeFilter(this->xform(color), mode));
            }
        }

        // TODO:
        //    - image filters?

        return *result;
    }

    const SkPaint* xform(const SkPaint* paint, SkTLazy<SkPaint>* lazy) const {
        return paint ? &this->xform(*paint, lazy) : nullptr;
    }

    void onDrawPaint(const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPaint(this->xform(paint, &lazy));
    }

    void onDrawRect(const SkRect& rect, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawRect(rect, this->xform(paint, &lazy));
    }
    void onDrawOval(const SkRect& oval, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawOval(oval, this->xform(paint, &lazy));
    }
    void onDrawRRect(const SkRRect& rrect, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawRRect(rrect, this->xform(paint, &lazy));
    }
    void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawDRRect(outer, inner, this->xform(paint, &lazy));
    }
    void onDrawPath(const SkPath& path, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPath(path, this->xform(paint, &lazy));
    }
    void onDrawArc(const SkRect& oval, SkScalar start, SkScalar sweep, bool useCenter,
                   const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawArc(oval, start, sweep, useCenter, this->xform(paint, &lazy));
    }
    void onDrawRegion(const SkRegion& region, const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawRegion(region, this->xform(paint, &lazy));
    }
    void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4], const SkPoint texs[4],
                     SkBlendMode mode, const SkPaint& paint) override {
        SkColor xformed[4];
        if (colors) {
            this->xform(xformed, colors, 4);
            colors = xformed;
        }

        SkTLazy<SkPaint> lazy;
        fTarget->drawPatch(cubics, colors, texs, mode, this->xform(paint, &lazy));
    }
    void onDrawPoints(PointMode mode, size_t count, const SkPoint* pts,
                      const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPoints(mode, count, pts, this->xform(paint, &lazy));
    }
    void onDrawVertices(VertexMode vmode, int count,
                        const SkPoint* verts, const SkPoint* texs, const SkColor* colors,
                        SkBlendMode mode,
                        const uint16_t* indices, int indexCount, const SkPaint& paint) override {
        SkSTArray<8, SkColor> xformed;
        if (colors) {
            xformed.reset(count);
            this->xform(xformed.begin(), colors, count);
            colors = xformed.begin();
        }

        SkTLazy<SkPaint> lazy;
        fTarget->drawVertices(vmode, count, verts, texs, colors, mode, indices, indexCount,
                              this->xform(paint, &lazy));
    }

    void onDrawText(const void* ptr, size_t len,
                    SkScalar x, SkScalar y,
                    const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawText(ptr, len, x, y, this->xform(paint, &lazy));
    }
    void onDrawPosText(const void* ptr, size_t len,
                       const SkPoint* xys,
                       const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPosText(ptr, len, xys, this->xform(paint, &lazy));
    }
    void onDrawPosTextH(const void* ptr, size_t len,
                        const SkScalar* xs, SkScalar y,
                        const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawPosTextH(ptr, len, xs, y, this->xform(paint, &lazy));
    }
    void onDrawTextOnPath(const void* ptr, size_t len,
                          const SkPath& path, const SkMatrix* matrix,
                          const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawTextOnPath(ptr, len, path, matrix, this->xform(paint, &lazy));
    }
    void onDrawTextRSXform(const void* ptr, size_t len,
                           const SkRSXform* xforms, const SkRect* cull,
                           const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawTextRSXform(ptr, len, xforms, cull, this->xform(paint, &lazy));
    }
    void onDrawTextBlob(const SkTextBlob* blob,
                        SkScalar x, SkScalar y,
                        const SkPaint& paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawTextBlob(blob, x, y, this->xform(paint, &lazy));
    }

    void onDrawImage(const SkImage* img,
                     SkScalar l, SkScalar t,
                     const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImage(this->xform(img).get(),
                           l, t,
                           this->xform(paint, &lazy));
    }
    void onDrawImageRect(const SkImage* img,
                         const SkRect* src, const SkRect& dst,
                         const SkPaint* paint, SrcRectConstraint constraint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImageRect(this->xform(img).get(),
                               src ? *src : dst, dst,
                               this->xform(paint, &lazy), constraint);
    }
    void onDrawImageNine(const SkImage* img,
                         const SkIRect& center, const SkRect& dst,
                         const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImageNine(this->xform(img).get(),
                               center, dst,
                               this->xform(paint, &lazy));
    }
    void onDrawImageLattice(const SkImage* img,
                            const Lattice& lattice, const SkRect& dst,
                            const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        fTarget->drawImageLattice(this->xform(img).get(),
                                  lattice, dst,
                                  this->xform(paint, &lazy));
    }
    void onDrawAtlas(const SkImage* atlas, const SkRSXform* xforms, const SkRect* tex,
                     const SkColor* colors, int count, SkBlendMode mode,
                     const SkRect* cull, const SkPaint* paint) override {
        SkSTArray<8, SkColor> xformed;
        if (colors) {
            xformed.reset(count);
            this->xform(xformed.begin(), colors, count);
            colors = xformed.begin();
        }

        SkTLazy<SkPaint> lazy;
        fTarget->drawAtlas(this->xform(atlas).get(), xforms, tex, colors, count, mode, cull,
                           this->xform(paint, &lazy));
    }

    void onDrawBitmap(const SkBitmap& bitmap,
                      SkScalar l, SkScalar t,
                      const SkPaint* paint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImage(image.get(), l, t, paint);
        }
    }
    void onDrawBitmapRect(const SkBitmap& bitmap,
                          const SkRect* src, const SkRect& dst,
                          const SkPaint* paint, SrcRectConstraint constraint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImageRect(image.get(), src, dst, paint, constraint);
        }
    }
    void onDrawBitmapNine(const SkBitmap& bitmap,
                          const SkIRect& center, const SkRect& dst,
                          const SkPaint* paint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImageNine(image.get(), center, dst, paint);
        }
    }
    void onDrawBitmapLattice(const SkBitmap& bitmap,
                             const Lattice& lattice, const SkRect& dst,
                             const SkPaint* paint) override {
        if (auto image = SkImage::MakeFromBitmap(bitmap)) {
            this->onDrawImageLattice(image.get(), lattice, dst, paint);
        }
    }

    // TODO: May not be ideal to unfurl pictures.
    void onDrawPicture(const SkPicture* pic,
                       const SkMatrix* matrix,
                       const SkPaint* paint) override {
        SkTLazy<SkPaint> lazy;
        SkCanvas::onDrawPicture(pic, matrix, this->xform(paint, &lazy));
    }
    void onDrawDrawable(SkDrawable* drawable, const SkMatrix* matrix) override {
        SkTLazy<SkPaint> lazy;
        SkCanvas::onDrawDrawable(drawable, matrix);
    }

    SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec& rec) override {
        SkTLazy<SkPaint> lazy;
        fTarget->saveLayer({
            rec.fBounds,
            this->xform(rec.fPaint, &lazy),
            rec.fBackdrop,  // TODO: this is an image filter
            rec.fSaveLayerFlags,
        });
        return kNoLayer_SaveLayerStrategy;
    }

    // Everything from here on should be uninteresting strictly proxied state-change calls.
    void willSave()    override { fTarget->save(); }
    void willRestore() override { fTarget->restore(); }

    void didConcat   (const SkMatrix& m) override { fTarget->concat   (m); }
    void didSetMatrix(const SkMatrix& m) override { fTarget->setMatrix(m); }

    void onClipRect(const SkRect& clip, SkClipOp op, ClipEdgeStyle style) override {
        fTarget->clipRect(clip, op, style);
    }
    void onClipRRect(const SkRRect& clip, SkClipOp op, ClipEdgeStyle style) override {
        fTarget->clipRRect(clip, op, style);
    }
    void onClipPath(const SkPath& clip, SkClipOp op, ClipEdgeStyle style) override {
        fTarget->clipPath(clip, op, style);
    }
    void onClipRegion(const SkRegion& clip, SkClipOp op) override {
        fTarget->clipRegion(clip, op);
    }

    void onDrawAnnotation(const SkRect& rect, const char* key, SkData* val) override {
        fTarget->drawAnnotation(rect, key, val);
    }

    sk_sp<SkSurface> onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) override {
        return fTarget->makeSurface(info, &props);
    }

private:
    SkCanvas*                          fTarget;
    sk_sp<SkColorSpace>                fTargetCS;
    std::unique_ptr<SkColorSpaceXform> fFromSRGB;
};

std::unique_ptr<SkCanvas> SkCreateColorSpaceXformCanvas(SkCanvas* target,
                                                        sk_sp<SkColorSpace> targetCS) {
    return skstd::make_unique<SkColorSpaceXformCanvas>(target, std::move(targetCS));
}
<|endoftext|>


<commit_before>#pragma once
#include <eosiolib/print.hpp>
#include <eosiolib/action.hpp>

#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/std_tuple.hpp>

#include <boost/mp11/tuple.hpp>
#define N(X) ::eosio::string_to_name(#X)
namespace eosio {
   template<typename Contract, typename FirstAction>
   bool dispatch( uint64_t code, uint64_t act ) {
      if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
         Contract().on( unpack_action_data<FirstAction>() );
         return true;
      }
      return false;
   }

   /**
    * This method will dynamically dispatch an incoming set of actions to
    *
    * ```
    * static Contract::on( ActionType )
    * ```
    *
    * For this to work the Actions must be dervied from the
    *
    */
   template<typename Contract, typename FirstAction, typename SecondAction, typename... Actions>
   bool dispatch( uint64_t code, uint64_t act ) {
      if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
         Contract().on( unpack_action_data<FirstAction>() );
         return true;
      }
      return eosio::dispatch<Contract,SecondAction,Actions...>( code, act );
   }

   template<typename T, typename... Args>
   bool execute_action( T* obj, void (T::*func)(Args...)  ) {
      size_t size = action_data_size();
      char default_buffer[2048];
      //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions
      char* buffer = size <= sizeof(default_buffer) ? default_buffer : (char*)malloc(size);
      read_action_data( buffer, size );

      auto args = unpack<std::tuple<std::decay_t<Args>...>>( buffer, size );

      if ( buffer != default_buffer ) {
         free(buffer);
      }

      auto f2 = [&]( auto... a ){
         (obj->*func)( a... );
      };

      boost::mp11::tuple_apply( f2, args );
      return true;
   }

#define EOSIO_API_CALL( r, OP, elem ) \
   case ::eosio::string_to_name( BOOST_PP_STRINGIZE(elem) ): \
      eosio::execute_action( &thiscontract, &OP::elem ); \
      return;

#define EOSIO_API( TYPE,  MEMBERS ) \
   BOOST_PP_SEQ_FOR_EACH( EOSIO_API_CALL, TYPE, MEMBERS )

#define EOSIO_ABI( TYPE, MEMBERS ) \
extern "C" { \
   void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
      auto self = receiver; \
      if( code == self ) { \
         TYPE thiscontract( self ); \
         switch( action ) { \
            EOSIO_API( TYPE, MEMBERS ) \
         } \
         eosio_exit(0); \
      } \
   } \
} \

   /*
   template<typename T>
   struct dispatcher {
      dispatcher( account_name code ):_contract(code){}

      template<typename FuncPtr>
      void dispatch( account_name action, FuncPtr ) {
      }

      T contract;
   };

   void dispatch( account_name code, account_name action,
   */

}
<commit_msg>default_buffer size changed to 512 to avoid strange failures #1030<commit_after>#pragma once
#include <eosiolib/print.hpp>
#include <eosiolib/action.hpp>

#include <boost/fusion/adapted/std_tuple.hpp>
#include <boost/fusion/include/std_tuple.hpp>

#include <boost/mp11/tuple.hpp>
#define N(X) ::eosio::string_to_name(#X)
namespace eosio {
   template<typename Contract, typename FirstAction>
   bool dispatch( uint64_t code, uint64_t act ) {
      if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
         Contract().on( unpack_action_data<FirstAction>() );
         return true;
      }
      return false;
   }

   /**
    * This method will dynamically dispatch an incoming set of actions to
    *
    * ```
    * static Contract::on( ActionType )
    * ```
    *
    * For this to work the Actions must be dervied from the
    *
    */
   template<typename Contract, typename FirstAction, typename SecondAction, typename... Actions>
   bool dispatch( uint64_t code, uint64_t act ) {
      if( code == FirstAction::get_account() && FirstAction::get_name() == act ) {
         Contract().on( unpack_action_data<FirstAction>() );
         return true;
      }
      return eosio::dispatch<Contract,SecondAction,Actions...>( code, act );
   }

   template<typename T, typename... Args>
   bool execute_action( T* obj, void (T::*func)(Args...)  ) {
      size_t size = action_data_size();
      char default_buffer[512];
      //using malloc/free here potentially is not exception-safe, although WASM doesn't support exceptions
      char* buffer = size <= sizeof(default_buffer) ? default_buffer : (char*)malloc(size);
      read_action_data( buffer, size );

      auto args = unpack<std::tuple<std::decay_t<Args>...>>( buffer, size );

      if ( buffer != default_buffer ) {
         free(buffer);
      }

      auto f2 = [&]( auto... a ){
         (obj->*func)( a... );
      };

      boost::mp11::tuple_apply( f2, args );
      return true;
   }

#define EOSIO_API_CALL( r, OP, elem ) \
   case ::eosio::string_to_name( BOOST_PP_STRINGIZE(elem) ): \
      eosio::execute_action( &thiscontract, &OP::elem ); \
      return;

#define EOSIO_API( TYPE,  MEMBERS ) \
   BOOST_PP_SEQ_FOR_EACH( EOSIO_API_CALL, TYPE, MEMBERS )

#define EOSIO_ABI( TYPE, MEMBERS ) \
extern "C" { \
   void apply( uint64_t receiver, uint64_t code, uint64_t action ) { \
      auto self = receiver; \
      if( code == self ) { \
         TYPE thiscontract( self ); \
         switch( action ) { \
            EOSIO_API( TYPE, MEMBERS ) \
         } \
         eosio_exit(0); \
      } \
   } \
} \

   /*
   template<typename T>
   struct dispatcher {
      dispatcher( account_name code ):_contract(code){}

      template<typename FuncPtr>
      void dispatch( account_name action, FuncPtr ) {
      }

      T contract;
   };

   void dispatch( account_name code, account_name action,
   */

}
<|endoftext|>


<commit_before>#include "CallBackWrapper.hpp"
#include "CommonData.hpp"
#include "Config.hpp"
#include "EventOutputQueue.hpp"
#include "PressDownKeys.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  List* PressDownKeys::list_;
  IOLock* PressDownKeys::lock_;

  void
  PressDownKeys::initialize(void)
  {
    lock_ = IOLockWrapper::alloc();
    list_ = new List();
  }

  void
  PressDownKeys::terminate(void)
  {
    IOLockWrapper::free(lock_);
    if (list_) {
      delete list_;
    }
  }

  void
  PressDownKeys::add(KeyCode key, KeyboardType keyboardType)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    if (! list_) return;

    if (key == KeyCode::VK_NONE) return;

    list_->push_back(new Item(key, keyboardType));

    IOLOG_DEVEL("PressDownKeys::add key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::remove(KeyCode key, KeyboardType keyboardType)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    if (! list_) return;

    Item* p = static_cast<Item*>(list_->front());
    for (;;) {
      if (! p) break;

      if (p->key == key &&
          p->keyboardType == keyboardType) {
        p = static_cast<Item*>(list_->erase(p));
      } else {
        p = static_cast<Item*>(p->getnext());
      }
    }

    IOLOG_DEVEL("PressDownKeys::remove key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::clear(void)
  {
    IOLockWrapper::ScopedLock lk(lock_);

    if (! list_) return;

    IOLOG_DEVEL("PressDownKeys::clear list_->size = %d\n", static_cast<int>(list_->size()));

    Item* p = static_cast<Item*>(list_->front());
    for (;;) {
      if (! p) break;

      Params_KeyboardEventCallBack::auto_ptr ptr(Params_KeyboardEventCallBack::alloc(EventType::UP, Flags(0), p->key, p->keyboardType, false));
      if (! ptr) break;

      EventOutputQueue::push(*ptr);
      IOLOG_DEVEL("PressDownKeys::clear key:%d, keyboardType:%d\n", (p->key).get(), (p->keyboardType).get());

      p = static_cast<Item*>(list_->erase(p));
    }
  }
}
<commit_msg>Add IOLock check<commit_after>#include "CallBackWrapper.hpp"
#include "CommonData.hpp"
#include "Config.hpp"
#include "EventOutputQueue.hpp"
#include "PressDownKeys.hpp"

namespace org_pqrs_KeyRemap4MacBook {
  List* PressDownKeys::list_;
  IOLock* PressDownKeys::lock_;

  void
  PressDownKeys::initialize(void)
  {
    lock_ = IOLockWrapper::alloc();
    list_ = new List();
  }

  void
  PressDownKeys::terminate(void)
  {
    {
      IOLockWrapper::ScopedLock lk(lock_);

      if (list_) {
        delete list_;
      }
    }
    IOLockWrapper::free(lock_);
  }

  void
  PressDownKeys::add(KeyCode key, KeyboardType keyboardType)
  {
    IOLockWrapper::ScopedLock lk(lock_);
    if (! lk) return;

    if (! list_) return;

    if (key == KeyCode::VK_NONE) return;

    list_->push_back(new Item(key, keyboardType));

    IOLOG_DEVEL("PressDownKeys::add key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::remove(KeyCode key, KeyboardType keyboardType)
  {
    IOLockWrapper::ScopedLock lk(lock_);
    if (! lk) return;

    if (! list_) return;

    Item* p = static_cast<Item*>(list_->front());
    for (;;) {
      if (! p) break;

      if (p->key == key &&
          p->keyboardType == keyboardType) {
        p = static_cast<Item*>(list_->erase(p));
      } else {
        p = static_cast<Item*>(p->getnext());
      }
    }

    IOLOG_DEVEL("PressDownKeys::remove key:%d, keyboardType:%d\n", key.get(), keyboardType.get());
  }

  void
  PressDownKeys::clear(void)
  {
    IOLockWrapper::ScopedLock lk(lock_);
    if (! lk) return;

    if (! list_) return;

    IOLOG_DEVEL("PressDownKeys::clear list_->size = %d\n", static_cast<int>(list_->size()));

    Item* p = static_cast<Item*>(list_->front());
    for (;;) {
      if (! p) break;

      Params_KeyboardEventCallBack::auto_ptr ptr(Params_KeyboardEventCallBack::alloc(EventType::UP, Flags(0), p->key, p->keyboardType, false));
      if (! ptr) break;

      EventOutputQueue::push(*ptr);
      IOLOG_DEVEL("PressDownKeys::clear key:%d, keyboardType:%d\n", (p->key).get(), (p->keyboardType).get());

      p = static_cast<Item*>(list_->erase(p));
    }
  }
}
<|endoftext|>


<commit_before>#include "MCOperation.h"

using namespace mailcore;

Operation::Operation()
{
	mCallback = NULL;
	mCancelled = false;
	pthread_mutex_init(&mLock, NULL);
#if __APPLE__
    mCallbackDispatchQueue = dispatch_get_current_queue();
#else
    mCallbackDispatchQueue = NULL;
#endif
}

Operation::~Operation()
{
	pthread_mutex_destroy(&mLock);
}

void Operation::setCallback(OperationCallback * callback)
{
	mCallback = callback;
}

OperationCallback * Operation::callback()
{
	return mCallback;
}

void Operation::cancel()
{
	pthread_mutex_lock(&mLock);
	mCancelled = true;
	pthread_mutex_unlock(&mLock);
}

bool Operation::isCancelled()
{
	pthread_mutex_lock(&mLock);
	bool value = mCancelled;
	pthread_mutex_unlock(&mLock);

	return value;
}

void Operation::beforeMain()
{
}

void Operation::main()
{
}

void Operation::afterMain()
{
}

void Operation::start()
{
}

void Operation::setCallbackDispatchQueue(dispatch_queue_t callbackDispatchQueue)
{
    mCallbackDispatchQueue = callbackDispatchQueue;
}

dispatch_queue_t Operation::callbackDispatchQueue()
{
    return mCallbackDispatchQueue;
}
<commit_msg>Assume main, rather than current, queue for callbacks<commit_after>#include "MCOperation.h"

using namespace mailcore;

Operation::Operation()
{
	mCallback = NULL;
	mCancelled = false;
	pthread_mutex_init(&mLock, NULL);
#if __APPLE__
    mCallbackDispatchQueue = dispatch_get_main_queue();
#else
    mCallbackDispatchQueue = NULL;
#endif
}

Operation::~Operation()
{
	pthread_mutex_destroy(&mLock);
}

void Operation::setCallback(OperationCallback * callback)
{
	mCallback = callback;
}

OperationCallback * Operation::callback()
{
	return mCallback;
}

void Operation::cancel()
{
	pthread_mutex_lock(&mLock);
	mCancelled = true;
	pthread_mutex_unlock(&mLock);
}

bool Operation::isCancelled()
{
	pthread_mutex_lock(&mLock);
	bool value = mCancelled;
	pthread_mutex_unlock(&mLock);

	return value;
}

void Operation::beforeMain()
{
}

void Operation::main()
{
}

void Operation::afterMain()
{
}

void Operation::start()
{
}

void Operation::setCallbackDispatchQueue(dispatch_queue_t callbackDispatchQueue)
{
    mCallbackDispatchQueue = callbackDispatchQueue;
}

dispatch_queue_t Operation::callbackDispatchQueue()
{
    return mCallbackDispatchQueue;
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkDbf.h"

namespace rtk
{

DbfField::DbfField(std::string name, char type, unsigned char length, short recOffset) :
  m_Name(name),
  m_Type(type),
  m_Length(length),
  m_RecOffset(recOffset)
{
}

DbfFile::DbfFile(std::string fileName)
{
  m_Stream.open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
  if(!m_Stream.is_open() )
    return;

  // Ignore version and date
  m_Stream.seekg(4);

  // Read number of records, header size, record size
  m_Stream.read( (char*)&m_NumRecords, sizeof(m_NumRecords) );
  m_Stream.read( (char*)&m_HeaderSize, sizeof(m_HeaderSize) );
  m_Stream.read( (char*)&m_RecordSize, sizeof(m_RecordSize) );

  // Record allocation
  m_Record = new char[m_RecordSize];

  // The number of fields depends on the header size (32 are the blocks
  // describing the global part and each field, 1 is the terminator length)
  const unsigned int numFields = (m_HeaderSize - 32 - 1) / 32;

  // First byte is the deletion character. Then the field data are concatenated
  short fldRecOffset = 1;
  for(unsigned int i=0; i<numFields; i++) {

    // Go to beginning of current field structure description
    m_Stream.seekg(32 * (1 + i) );

    // Field names
    char fldName[11];
    m_Stream.read(fldName, 11);

    // Field types
    char fldType;
    m_Stream.read( (char*)&fldType, sizeof(fldType) );

    // Skip displacement of field in record?
    m_Stream.seekg(4, std::ios_base::cur);

    // Field length
    unsigned char fldLength;
    m_Stream.read( (char*)&fldLength, sizeof(fldLength) );

    // Add field and go to next
    m_Fields.push_back(DbfField(fldName, fldType, fldLength, fldRecOffset) );
    m_MapFieldNameIndex[m_Fields.back().GetName()] = i;

    fldRecOffset += fldLength;
    }

  // Seek to first record
  m_Stream.seekg(m_HeaderSize);
}

DbfFile::~DbfFile()
{
  free(m_Record);
}

bool DbfFile::ReadNextRecord()
{
  do
    {
    m_Stream.read(m_Record, m_RecordSize);
    }
  while(m_Stream.gcount() == m_RecordSize && m_Record[0] == 0x2A);
  return m_Stream.gcount() == m_RecordSize;
}

std::string DbfFile::GetFieldAsString(std::string fldName){
  DbfField &  field = m_Fields[ m_MapFieldNameIndex[fldName] ];
  std::string result( m_Record + field.GetRecOffset(), field.GetLength() );

  // Revome begin/end spaces
  std::string::size_type pos = result.find_last_not_of(' ');

  if(pos != std::string::npos) {
    result.erase(pos + 1);
    pos = result.find_first_not_of(' ');
    if(pos != std::string::npos)
      result.erase(0, pos);
    }
  else
    result.erase(result.begin(), result.end() );

  return result;
}

}
<commit_msg>BUG: delete[] instead of free()<commit_after>/*=========================================================================
 *
 *  Copyright RTK Consortium
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

#include "rtkDbf.h"

namespace rtk
{

DbfField::DbfField(std::string name, char type, unsigned char length, short recOffset) :
  m_Name(name),
  m_Type(type),
  m_Length(length),
  m_RecOffset(recOffset)
{
}

DbfFile::DbfFile(std::string fileName)
{
  m_Stream.open(fileName.c_str(), std::ios_base::in | std::ios_base::binary);
  if(!m_Stream.is_open() )
    return;

  // Ignore version and date
  m_Stream.seekg(4);

  // Read number of records, header size, record size
  m_Stream.read( (char*)&m_NumRecords, sizeof(m_NumRecords) );
  m_Stream.read( (char*)&m_HeaderSize, sizeof(m_HeaderSize) );
  m_Stream.read( (char*)&m_RecordSize, sizeof(m_RecordSize) );

  // Record allocation
  m_Record = new char[m_RecordSize];

  // The number of fields depends on the header size (32 are the blocks
  // describing the global part and each field, 1 is the terminator length)
  const unsigned int numFields = (m_HeaderSize - 32 - 1) / 32;

  // First byte is the deletion character. Then the field data are concatenated
  short fldRecOffset = 1;
  for(unsigned int i=0; i<numFields; i++) {

    // Go to beginning of current field structure description
    m_Stream.seekg(32 * (1 + i) );

    // Field names
    char fldName[11];
    m_Stream.read(fldName, 11);

    // Field types
    char fldType;
    m_Stream.read( (char*)&fldType, sizeof(fldType) );

    // Skip displacement of field in record?
    m_Stream.seekg(4, std::ios_base::cur);

    // Field length
    unsigned char fldLength;
    m_Stream.read( (char*)&fldLength, sizeof(fldLength) );

    // Add field and go to next
    m_Fields.push_back(DbfField(fldName, fldType, fldLength, fldRecOffset) );
    m_MapFieldNameIndex[m_Fields.back().GetName()] = i;

    fldRecOffset += fldLength;
    }

  // Seek to first record
  m_Stream.seekg(m_HeaderSize);
}

DbfFile::~DbfFile()
{
  delete [] m_Record;
}

bool DbfFile::ReadNextRecord()
{
  do
    {
    m_Stream.read(m_Record, m_RecordSize);
    }
  while(m_Stream.gcount() == m_RecordSize && m_Record[0] == 0x2A);
  return m_Stream.gcount() == m_RecordSize;
}

std::string DbfFile::GetFieldAsString(std::string fldName){
  DbfField &  field = m_Fields[ m_MapFieldNameIndex[fldName] ];
  std::string result( m_Record + field.GetRecOffset(), field.GetLength() );

  // Revome begin/end spaces
  std::string::size_type pos = result.find_last_not_of(' ');

  if(pos != std::string::npos) {
    result.erase(pos + 1);
    pos = result.find_first_not_of(' ');
    if(pos != std::string::npos)
      result.erase(0, pos);
    }
  else
    result.erase(result.begin(), result.end() );

  return result;
}

}
<|endoftext|>


<commit_before>
#include "function.h"
#include "value.h"

using namespace v8;

namespace GINode {

static Handle<Value> FunctionInvoker(const Arguments &args) {
    HandleScope scope;
    GIBaseInfo *info = (GIBaseInfo *) External::Unwrap (args.Data ());
    GIFunctionInfo *function_info = (GIFunctionInfo *) info;
    GError *error = NULL;

    /* XXX: For now, only work on functions without any OUT args at all.
     * Just assume everything is an in arg. */
    int n_in_args = g_callable_info_get_n_args ((GICallableInfo *) info);
    GIArgument in_args[n_in_args];

    if (args.Length() < n_in_args) {
        ThrowException (Exception::TypeError (String::New ("Not enough arguments.")));
        return scope.Close (Undefined ());
    }

    for (int i = 0; i < n_in_args; i++) {
        GIArgInfo *arg_info = g_callable_info_get_arg ((GICallableInfo *) info, i);
        GITypeInfo type_info;
        g_arg_info_load_type (arg_info, &type_info);
        V8ToGIArgument (&type_info, &in_args[i], args[i]);
        g_base_info_unref ((GIBaseInfo *) arg_info);
    }

    GIArgument return_value;
    g_function_info_invoke (function_info,
                            in_args, n_in_args,
                            NULL, 0,
                            &return_value,
                            &error);

    for (int i = 0; i < n_in_args; i++) {
        GIArgInfo *arg_info = g_callable_info_get_arg ((GICallableInfo *) info, i);
        GITypeInfo type_info;
        g_arg_info_load_type (arg_info, &type_info);
        FreeGIArgument (&type_info, &in_args[i]);
        g_base_info_unref ((GIBaseInfo *) arg_info);
    }

    if (error) {
        ThrowException (Exception::TypeError (String::New (error->message)));
        return scope.Close (Undefined ());
    }

    GITypeInfo return_value_type;
    g_callable_info_load_return_type ((GICallableInfo *) info, &return_value_type);
    return scope.Close (GIArgumentToV8 (&return_value_type, &return_value));
}

static void FunctionDestroyed (Persistent<Value> object, void *data) {
    GIBaseInfo *info = (GIBaseInfo *) data;
    g_base_info_unref (info);
}

Handle<Function> MakeFunction(GIBaseInfo *info) {
    HandleScope scope;

    Persistent<FunctionTemplate> tpl = Persistent<FunctionTemplate>::New (FunctionTemplate::New (FunctionInvoker, External::New (info)));
    tpl.MakeWeak (g_base_info_ref (info), FunctionDestroyed);
    Local<Function> fn = tpl->GetFunction ();

    const char *function_name = g_base_info_get_name (info);
    fn->SetName (String::NewSymbol (function_name));

    return scope.Close (fn);
}

};
<commit_msg>function: Fix whitespace<commit_after>
#include "function.h"
#include "value.h"

using namespace v8;

namespace GINode {

static Handle<Value> FunctionInvoker(const Arguments &args) {
    HandleScope scope;
    GIBaseInfo *info = (GIBaseInfo *) External::Unwrap (args.Data ());
    GIFunctionInfo *function_info = (GIFunctionInfo *) info;
    GError *error = NULL;

    /* XXX: For now, only work on functions without any OUT args at all.
     * Just assume everything is an in arg. */
    int n_in_args = g_callable_info_get_n_args ((GICallableInfo *) info);
    GIArgument in_args[n_in_args];

    if (args.Length() < n_in_args) {
        ThrowException (Exception::TypeError (String::New ("Not enough arguments.")));
        return scope.Close (Undefined ());
    }

    for (int i = 0; i < n_in_args; i++) {
        GIArgInfo *arg_info = g_callable_info_get_arg ((GICallableInfo *) info, i);
        GITypeInfo type_info;
        g_arg_info_load_type (arg_info, &type_info);
        V8ToGIArgument (&type_info, &in_args[i], args[i]);
        g_base_info_unref ((GIBaseInfo *) arg_info);
    }

    GIArgument return_value;
    g_function_info_invoke (function_info,
                            in_args, n_in_args,
                            NULL, 0,
                            &return_value,
                            &error);

    for (int i = 0; i < n_in_args; i++) {
        GIArgInfo *arg_info = g_callable_info_get_arg ((GICallableInfo *) info, i);
        GITypeInfo type_info;
        g_arg_info_load_type (arg_info, &type_info);
        FreeGIArgument (&type_info, &in_args[i]);
        g_base_info_unref ((GIBaseInfo *) arg_info);
    }

    if (error) {
        ThrowException (Exception::TypeError (String::New (error->message)));
        return scope.Close (Undefined ());
    }

    GITypeInfo return_value_type;
    g_callable_info_load_return_type ((GICallableInfo *) info, &return_value_type);
    return scope.Close (GIArgumentToV8 (&return_value_type, &return_value));
}

static void FunctionDestroyed(Persistent<Value> object, void *data) {
    GIBaseInfo *info = (GIBaseInfo *) data;
    g_base_info_unref (info);
}

Handle<Function> MakeFunction(GIBaseInfo *info) {
    HandleScope scope;

    Persistent<FunctionTemplate> tpl = Persistent<FunctionTemplate>::New (FunctionTemplate::New (FunctionInvoker, External::New (info)));
    tpl.MakeWeak (g_base_info_ref (info), FunctionDestroyed);
    Local<Function> fn = tpl->GetFunction ();

    const char *function_name = g_base_info_get_name (info);
    fn->SetName (String::NewSymbol (function_name));

    return scope.Close (fn);
}

};
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2004-2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Kevin Lim
 *          Korey Sewell
 */

#include "arch/registers.hh"
#include "config/the_isa.hh"
#include "cpu/o3/thread_context.hh"
#include "cpu/quiesce_event.hh"

#if FULL_SYSTEM
template <class Impl>
VirtualPort *
O3ThreadContext<Impl>::getVirtPort()
{
    return thread->getVirtPort();
}

template <class Impl>
void
O3ThreadContext<Impl>::dumpFuncProfile()
{
    thread->dumpFuncProfile();
}
#endif

template <class Impl>
void
O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
{
    // some things should already be set up
    assert(getSystemPtr() == old_context->getSystemPtr());
#if !FULL_SYSTEM
    assert(getProcessPtr() == old_context->getProcessPtr());
#endif

    // copy over functional state
    setStatus(old_context->status());
    copyArchRegs(old_context);
    setContextId(old_context->contextId());
    setThreadId(old_context->threadId());

#if !FULL_SYSTEM
    thread->funcExeInst = old_context->readFuncExeInst();
#else
    EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
    if (other_quiesce) {
        // Point the quiesce event's TC at this TC so that it wakes up
        // the proper CPU.
        other_quiesce->tc = this;
    }
    if (thread->quiesceEvent) {
        thread->quiesceEvent->tc = this;
    }

    // Transfer kernel stats from one CPU to the other.
    thread->kernelStats = old_context->getKernelStats();
//    storeCondFailures = 0;
    cpu->lockFlag = false;
#endif

    old_context->setStatus(ThreadContext::Halted);

    thread->inSyscall = false;
    thread->trapPending = false;
}

template <class Impl>
void
O3ThreadContext<Impl>::activate(int delay)
{
    DPRINTF(O3CPU, "Calling activate on Thread Context %d\n",
            threadId());

    if (thread->status() == ThreadContext::Active)
        return;

#if FULL_SYSTEM
    thread->lastActivate = curTick;
#endif

    thread->setStatus(ThreadContext::Active);

    // status() == Suspended
    cpu->activateContext(thread->threadId(), delay);
}

template <class Impl>
void
O3ThreadContext<Impl>::suspend(int delay)
{
    DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n",
            threadId());

    if (thread->status() == ThreadContext::Suspended)
        return;

#if FULL_SYSTEM
    thread->lastActivate = curTick;
    thread->lastSuspend = curTick;
#endif
/*
#if FULL_SYSTEM
    // Don't change the status from active if there are pending interrupts
    if (cpu->checkInterrupts()) {
        assert(status() == ThreadContext::Active);
        return;
    }
#endif
*/
    thread->setStatus(ThreadContext::Suspended);
    cpu->suspendContext(thread->threadId());
}

template <class Impl>
void
O3ThreadContext<Impl>::halt(int delay)
{
    DPRINTF(O3CPU, "Calling halt on Thread Context %d\n",
            threadId());

    if (thread->status() == ThreadContext::Halted)
        return;

    thread->setStatus(ThreadContext::Halted);
    cpu->haltContext(thread->threadId());
}

template <class Impl>
void
O3ThreadContext<Impl>::regStats(const std::string &name)
{
#if FULL_SYSTEM
    thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system);
    thread->kernelStats->regStats(name + ".kern");
#endif
}

template <class Impl>
void
O3ThreadContext<Impl>::serialize(std::ostream &os)
{
#if FULL_SYSTEM
    if (thread->kernelStats)
        thread->kernelStats->serialize(os);
#endif

}

template <class Impl>
void
O3ThreadContext<Impl>::unserialize(Checkpoint *cp, const std::string &section)
{
#if FULL_SYSTEM
    if (thread->kernelStats)
        thread->kernelStats->unserialize(cp, section);
#endif

}

#if FULL_SYSTEM
template <class Impl>
Tick
O3ThreadContext<Impl>::readLastActivate()
{
    return thread->lastActivate;
}

template <class Impl>
Tick
O3ThreadContext<Impl>::readLastSuspend()
{
    return thread->lastSuspend;
}

template <class Impl>
void
O3ThreadContext<Impl>::profileClear()
{
    thread->profileClear();
}

template <class Impl>
void
O3ThreadContext<Impl>::profileSample()
{
    thread->profileSample();
}
#endif

template <class Impl>
TheISA::MachInst
O3ThreadContext<Impl>:: getInst()
{
    return thread->getInst();
}

template <class Impl>
void
O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc)
{
    // This function will mess things up unless the ROB is empty and
    // there are no instructions in the pipeline.
    ThreadID tid = thread->threadId();
    PhysRegIndex renamed_reg;

    // First loop through the integer registers.
    for (int i = 0; i < TheISA::NumIntRegs; ++i) {
        renamed_reg = cpu->renameMap[tid].lookup(i);

        DPRINTF(O3CPU, "Copying over register %i, had data %lli, "
                "now has data %lli.\n",
                renamed_reg, cpu->readIntReg(renamed_reg),
                tc->readIntReg(i));

        cpu->setIntReg(renamed_reg, tc->readIntReg(i));
    }

    // Then loop through the floating point registers.
    for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
        renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag);
        cpu->setFloatRegBits(renamed_reg,
                             tc->readFloatRegBits(i));
    }

    // Copy the misc regs.
    TheISA::copyMiscRegs(tc, this);

    // Then finally set the PC, the next PC, the nextNPC, the micropc, and the
    // next micropc.
    cpu->setPC(tc->readPC(), tid);
    cpu->setNextPC(tc->readNextPC(), tid);
    cpu->setNextNPC(tc->readNextNPC(), tid);
    cpu->setMicroPC(tc->readMicroPC(), tid);
    cpu->setNextMicroPC(tc->readNextMicroPC(), tid);
#if !FULL_SYSTEM
    this->thread->funcExeInst = tc->readFuncExeInst();
#endif
}

template <class Impl>
void
O3ThreadContext<Impl>::clearArchRegs()
{}

template <class Impl>
uint64_t
O3ThreadContext<Impl>::readIntReg(int reg_idx)
{
    reg_idx = cpu->isa[thread->threadId()].flattenIntIndex(reg_idx);
    return cpu->readArchIntReg(reg_idx, thread->threadId());
}

template <class Impl>
TheISA::FloatReg
O3ThreadContext<Impl>::readFloatReg(int reg_idx)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    return cpu->readArchFloatReg(reg_idx, thread->threadId());
}

template <class Impl>
TheISA::FloatRegBits
O3ThreadContext<Impl>::readFloatRegBits(int reg_idx)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    return cpu->readArchFloatRegInt(reg_idx, thread->threadId());
}

template <class Impl>
void
O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val)
{
    reg_idx = cpu->isa[thread->threadId()].flattenIntIndex(reg_idx);
    cpu->setArchIntReg(reg_idx, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    cpu->setArchFloatReg(reg_idx, val, thread->threadId());

    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    cpu->setArchFloatRegInt(reg_idx, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setPC(uint64_t val)
{
    cpu->setPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setNextPC(uint64_t val)
{
    cpu->setNextPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setMicroPC(uint64_t val)
{
    cpu->setMicroPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setNextMicroPC(uint64_t val)
{
    cpu->setNextMicroPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
int
O3ThreadContext<Impl>::flattenIntIndex(int reg)
{
    return cpu->isa[thread->threadId()].flattenIntIndex(reg);
}

template <class Impl>
int
O3ThreadContext<Impl>::flattenFloatIndex(int reg)
{
    return cpu->isa[thread->threadId()].flattenFloatIndex(reg);
}

template <class Impl>
void
O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
    cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setMiscReg(int misc_reg,
                                                const MiscReg &val)
{
    cpu->setMiscReg(misc_reg, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

<commit_msg>O3ThreadContext: When taking over from a previous context, only assert that the system pointers match in Full System mode.<commit_after>/*
 * Copyright (c) 2004-2006 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Kevin Lim
 *          Korey Sewell
 */

#include "arch/registers.hh"
#include "config/the_isa.hh"
#include "cpu/o3/thread_context.hh"
#include "cpu/quiesce_event.hh"

#if FULL_SYSTEM
template <class Impl>
VirtualPort *
O3ThreadContext<Impl>::getVirtPort()
{
    return thread->getVirtPort();
}

template <class Impl>
void
O3ThreadContext<Impl>::dumpFuncProfile()
{
    thread->dumpFuncProfile();
}
#endif

template <class Impl>
void
O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
{
    // some things should already be set up
#if FULL_SYSTEM
    assert(getSystemPtr() == old_context->getSystemPtr());
#else
    assert(getProcessPtr() == old_context->getProcessPtr());
#endif

    // copy over functional state
    setStatus(old_context->status());
    copyArchRegs(old_context);
    setContextId(old_context->contextId());
    setThreadId(old_context->threadId());

#if !FULL_SYSTEM
    thread->funcExeInst = old_context->readFuncExeInst();
#else
    EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
    if (other_quiesce) {
        // Point the quiesce event's TC at this TC so that it wakes up
        // the proper CPU.
        other_quiesce->tc = this;
    }
    if (thread->quiesceEvent) {
        thread->quiesceEvent->tc = this;
    }

    // Transfer kernel stats from one CPU to the other.
    thread->kernelStats = old_context->getKernelStats();
//    storeCondFailures = 0;
    cpu->lockFlag = false;
#endif

    old_context->setStatus(ThreadContext::Halted);

    thread->inSyscall = false;
    thread->trapPending = false;
}

template <class Impl>
void
O3ThreadContext<Impl>::activate(int delay)
{
    DPRINTF(O3CPU, "Calling activate on Thread Context %d\n",
            threadId());

    if (thread->status() == ThreadContext::Active)
        return;

#if FULL_SYSTEM
    thread->lastActivate = curTick;
#endif

    thread->setStatus(ThreadContext::Active);

    // status() == Suspended
    cpu->activateContext(thread->threadId(), delay);
}

template <class Impl>
void
O3ThreadContext<Impl>::suspend(int delay)
{
    DPRINTF(O3CPU, "Calling suspend on Thread Context %d\n",
            threadId());

    if (thread->status() == ThreadContext::Suspended)
        return;

#if FULL_SYSTEM
    thread->lastActivate = curTick;
    thread->lastSuspend = curTick;
#endif
/*
#if FULL_SYSTEM
    // Don't change the status from active if there are pending interrupts
    if (cpu->checkInterrupts()) {
        assert(status() == ThreadContext::Active);
        return;
    }
#endif
*/
    thread->setStatus(ThreadContext::Suspended);
    cpu->suspendContext(thread->threadId());
}

template <class Impl>
void
O3ThreadContext<Impl>::halt(int delay)
{
    DPRINTF(O3CPU, "Calling halt on Thread Context %d\n",
            threadId());

    if (thread->status() == ThreadContext::Halted)
        return;

    thread->setStatus(ThreadContext::Halted);
    cpu->haltContext(thread->threadId());
}

template <class Impl>
void
O3ThreadContext<Impl>::regStats(const std::string &name)
{
#if FULL_SYSTEM
    thread->kernelStats = new TheISA::Kernel::Statistics(cpu->system);
    thread->kernelStats->regStats(name + ".kern");
#endif
}

template <class Impl>
void
O3ThreadContext<Impl>::serialize(std::ostream &os)
{
#if FULL_SYSTEM
    if (thread->kernelStats)
        thread->kernelStats->serialize(os);
#endif

}

template <class Impl>
void
O3ThreadContext<Impl>::unserialize(Checkpoint *cp, const std::string &section)
{
#if FULL_SYSTEM
    if (thread->kernelStats)
        thread->kernelStats->unserialize(cp, section);
#endif

}

#if FULL_SYSTEM
template <class Impl>
Tick
O3ThreadContext<Impl>::readLastActivate()
{
    return thread->lastActivate;
}

template <class Impl>
Tick
O3ThreadContext<Impl>::readLastSuspend()
{
    return thread->lastSuspend;
}

template <class Impl>
void
O3ThreadContext<Impl>::profileClear()
{
    thread->profileClear();
}

template <class Impl>
void
O3ThreadContext<Impl>::profileSample()
{
    thread->profileSample();
}
#endif

template <class Impl>
TheISA::MachInst
O3ThreadContext<Impl>:: getInst()
{
    return thread->getInst();
}

template <class Impl>
void
O3ThreadContext<Impl>::copyArchRegs(ThreadContext *tc)
{
    // This function will mess things up unless the ROB is empty and
    // there are no instructions in the pipeline.
    ThreadID tid = thread->threadId();
    PhysRegIndex renamed_reg;

    // First loop through the integer registers.
    for (int i = 0; i < TheISA::NumIntRegs; ++i) {
        renamed_reg = cpu->renameMap[tid].lookup(i);

        DPRINTF(O3CPU, "Copying over register %i, had data %lli, "
                "now has data %lli.\n",
                renamed_reg, cpu->readIntReg(renamed_reg),
                tc->readIntReg(i));

        cpu->setIntReg(renamed_reg, tc->readIntReg(i));
    }

    // Then loop through the floating point registers.
    for (int i = 0; i < TheISA::NumFloatRegs; ++i) {
        renamed_reg = cpu->renameMap[tid].lookup(i + TheISA::FP_Base_DepTag);
        cpu->setFloatRegBits(renamed_reg,
                             tc->readFloatRegBits(i));
    }

    // Copy the misc regs.
    TheISA::copyMiscRegs(tc, this);

    // Then finally set the PC, the next PC, the nextNPC, the micropc, and the
    // next micropc.
    cpu->setPC(tc->readPC(), tid);
    cpu->setNextPC(tc->readNextPC(), tid);
    cpu->setNextNPC(tc->readNextNPC(), tid);
    cpu->setMicroPC(tc->readMicroPC(), tid);
    cpu->setNextMicroPC(tc->readNextMicroPC(), tid);
#if !FULL_SYSTEM
    this->thread->funcExeInst = tc->readFuncExeInst();
#endif
}

template <class Impl>
void
O3ThreadContext<Impl>::clearArchRegs()
{}

template <class Impl>
uint64_t
O3ThreadContext<Impl>::readIntReg(int reg_idx)
{
    reg_idx = cpu->isa[thread->threadId()].flattenIntIndex(reg_idx);
    return cpu->readArchIntReg(reg_idx, thread->threadId());
}

template <class Impl>
TheISA::FloatReg
O3ThreadContext<Impl>::readFloatReg(int reg_idx)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    return cpu->readArchFloatReg(reg_idx, thread->threadId());
}

template <class Impl>
TheISA::FloatRegBits
O3ThreadContext<Impl>::readFloatRegBits(int reg_idx)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    return cpu->readArchFloatRegInt(reg_idx, thread->threadId());
}

template <class Impl>
void
O3ThreadContext<Impl>::setIntReg(int reg_idx, uint64_t val)
{
    reg_idx = cpu->isa[thread->threadId()].flattenIntIndex(reg_idx);
    cpu->setArchIntReg(reg_idx, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setFloatReg(int reg_idx, FloatReg val)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    cpu->setArchFloatReg(reg_idx, val, thread->threadId());

    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setFloatRegBits(int reg_idx, FloatRegBits val)
{
    reg_idx = cpu->isa[thread->threadId()].flattenFloatIndex(reg_idx);
    cpu->setArchFloatRegInt(reg_idx, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setPC(uint64_t val)
{
    cpu->setPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setNextPC(uint64_t val)
{
    cpu->setNextPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setMicroPC(uint64_t val)
{
    cpu->setMicroPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setNextMicroPC(uint64_t val)
{
    cpu->setNextMicroPC(val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
int
O3ThreadContext<Impl>::flattenIntIndex(int reg)
{
    return cpu->isa[thread->threadId()].flattenIntIndex(reg);
}

template <class Impl>
int
O3ThreadContext<Impl>::flattenFloatIndex(int reg)
{
    return cpu->isa[thread->threadId()].flattenFloatIndex(reg);
}

template <class Impl>
void
O3ThreadContext<Impl>::setMiscRegNoEffect(int misc_reg, const MiscReg &val)
{
    cpu->setMiscRegNoEffect(misc_reg, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

template <class Impl>
void
O3ThreadContext<Impl>::setMiscReg(int misc_reg,
                                                const MiscReg &val)
{
    cpu->setMiscReg(misc_reg, val, thread->threadId());

    // Squash if we're not already in a state update mode.
    if (!thread->trapPending && !thread->inSyscall) {
        cpu->squashFromTC(thread->threadId());
    }
}

<|endoftext|>