| Index: test/cctest/test-code-stub-sh4.cc
|
| diff --git a/test/cctest/test-code-stub-sh4.cc b/test/cctest/test-code-stub-sh4.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..dba83d5d9e4225890210971414166c14b416ea10
|
| --- /dev/null
|
| +++ b/test/cctest/test-code-stub-sh4.cc
|
| @@ -0,0 +1,719 @@
|
| +// Copyright 2011 the V8 project authors. 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 Google Inc. 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.
|
| +
|
| +#include "v8.h"
|
| +
|
| +#include "macro-assembler.h"
|
| +#include "code-stubs.h"
|
| +#include "factory.h"
|
| +#include "platform.h"
|
| +#include "serialize.h"
|
| +#include "cctest.h"
|
| +
|
| +using namespace v8::internal;
|
| +
|
| +Handle<JSFunction>
|
| +CreateJSFunctionFromCode(const char *name, Code *code, Isolate* isolate) {
|
| + Factory* factory = isolate->factory();
|
| +
|
| + // Allocate the function
|
| + Handle<String> symbol = factory->LookupAsciiSymbol(name);
|
| + Handle<JSFunction> new_function =
|
| + factory->NewFunctionWithoutPrototype(symbol, CLASSIC_MODE);
|
| +
|
| + // Bind the code
|
| + new_function->set_code(code);
|
| + new_function->shared()->set_code(code);
|
| + Handle<String> source = factory->NewStringFromAscii(CStrVector("() {}"));
|
| + Handle<Script> script = factory->NewScript(source);
|
| + script->set_type(Smi::FromInt(Script::TYPE_NATIVE));
|
| + new_function->shared()->set_script(*script);
|
| + new_function->shared()->set_start_position(0);
|
| + new_function->shared()->set_end_position(source->length());
|
| + new_function->shared()->DontAdaptArguments();
|
| +
|
| + return new_function;
|
| +}
|
| +
|
| +#define BEGIN() \
|
| + FLAG_disable_native_files = true; \
|
| + FLAG_code_comments = true; \
|
| + v8::HandleScope scope; \
|
| + Isolate* isolate = Isolate::Current(); \
|
| + LocalContext env; \
|
| + MacroAssembler assm(Isolate::Current(), NULL, 0);
|
| +
|
| +
|
| +#define JIT() \
|
| + CodeDesc desc; \
|
| + assm.GetCode(&desc); \
|
| + Code* code = Code::cast(HEAP-> \
|
| + CreateCode(desc, \
|
| + Code::ComputeFlags(Code::BUILTIN), \
|
| + Handle<Object>(HEAP->null_value()))-> \
|
| + ToObjectChecked()); \
|
| + Handle<JSFunction> func = CreateJSFunctionFromCode(__FUNCTION__, \
|
| + code, isolate);
|
| +
|
| +#define CALL() \
|
| + CHECK(func->code()->IsCode()); \
|
| + bool exc; \
|
| + Handle<Object> receiver(isolate->context()->global_proxy(), isolate); \
|
| + Handle<Object> result = Execution::Call(func, receiver, 0, NULL, &exc); \
|
| + if (exc) { result = isolate->factory()->nan_value(); } \
|
| + (void)0
|
| +
|
| +// #define NOPRINT
|
| +#if defined(DEBUG) && !defined(NOPRINT)
|
| +#define PRINT() Code::cast(func->code())->Print()
|
| +#else
|
| +#define PRINT() (void)0
|
| +#endif
|
| +
|
| +#define GLOBAL_FUNCTION_PTR() (isolate->global_context()->closure())
|
| +#define GLOBAL_PTR() (*(isolate->global_object()))
|
| +#define GLOBAL_CONTEXT_PTR() (*(isolate->global_context()))
|
| +#define GLOBAL_CLOSURE_PTR() (isolate->global_context()->closure())
|
| +#define GLOBAL_OBJECT_FUNCTION_PTR() \
|
| + (isolate->global_context()->object_function())
|
| +#define GLOBAL_BUILTINS_PTR() (*isolate->builtins())
|
| +
|
| +#define CMT(msg) do { Comment cmnt(&assm, msg); } while (0)
|
| +
|
| +#define __ assm.
|
| +
|
| +// This macro stores in r10 the line number before branching to the error label.
|
| +// At the error label r10 can be moved to r0 such that return code of the
|
| +// function if not 0 indicates an error at the line of the branch.
|
| +#define B_LINE(cond, target) do { \
|
| + __ mov(r10, Operand(__LINE__)); \
|
| + if (cond == al) { \
|
| + __ b(target); \
|
| + } else { \
|
| + __ b(cond, target); \
|
| + } \
|
| + } while (0);
|
| +
|
| +
|
| +// Test Empty function call
|
| +// This covers JSEntryStub (call to the empty function) builtin.
|
| +// This covers CEntryStub (call to kEmptyFunction) builtin.
|
| +// This Covers also Generate_Adaptor() and JumpToExternalReference()
|
| +TEST(sh4_cs_0) {
|
| + BEGIN();
|
| +
|
| + // Force use of empty function (global_context()->closure())
|
| + Handle<JSFunction> func =
|
| + Handle<JSFunction>(isolate->global_context()->closure(), isolate);
|
| +
|
| + fprintf(stderr, "isolate = Isolate::Current(): %p\n",
|
| + reinterpret_cast<void *>(isolate));
|
| + fprintf(stderr, "isolate_context = isolate->context(): %p\n",
|
| + reinterpret_cast<void *>(isolate->context()));
|
| + fprintf(stderr, "global_context = isolate->global_context(): %p\n",
|
| + reinterpret_cast<void *>(*isolate->global_context()));
|
| + fprintf(stderr, "global_context_closure = global_context->closure(): %p\n",
|
| + reinterpret_cast<void *>(isolate->global_context()->closure()));
|
| + fprintf(stderr, "global = isolate->global_object(): %p\n",
|
| + reinterpret_cast<void *>(*isolate->global_object()));
|
| + fprintf(stderr, "global_proxy = isolate->global_proxy(): %p\n",
|
| + reinterpret_cast<void *>(isolate->context()->global_proxy()));
|
| + fprintf(stderr, "closure_code = global_context_closure->code(): %p \n",
|
| + reinterpret_cast<void *>(func->code()));
|
| + fprintf(stderr, "closure_entry = code->entry(): %p \n",
|
| + reinterpret_cast<void *>(func->code()->entry()));
|
| +
|
| + PRINT();
|
| +
|
| + CALL();
|
| +
|
| + // The empty function returns the undefined value.
|
| + CHECK(result->IsHeapObject());
|
| + CHECK(HeapObject::cast(*result)->IsUndefined());
|
| +}
|
| +
|
| +// Test empty function that scratches all JS registers
|
| +// (except roots, cp, fp, sp)
|
| +TEST(sh4_cs_1) {
|
| + BEGIN();
|
| +
|
| + // We are in a JS context, thus we can scratch caller and callee saved
|
| + __ Dead(r0, r1, r2, r3);
|
| + __ Dead(r4, r5, r6, r7);
|
| + __ Dead(r8, r9, r10, r11);
|
| +
|
| + __ mov(r0, Operand(Smi::FromInt(0)));
|
| + __ rts();
|
| +
|
| + JIT();
|
| +
|
| + PRINT();
|
| +
|
| + CALL();
|
| +
|
| + // The function must return a result as Smi.
|
| + CHECK(result->IsSmi());
|
| + CHECK_EQ(0, Smi::cast(*result)->value());
|
| +}
|
| +
|
| +
|
| +// Test CompareInstanceType(), CompareObjectType()
|
| +TEST(sh4_cs_2) {
|
| + BEGIN();
|
| +
|
| + Label error;
|
| +
|
| + // Check that roots is actually te root object
|
| + CMT("Check roots");
|
| + __ mov(r0, Operand(ExternalReference::roots_array_start(assm.isolate())));
|
| + __ cmp(r0, roots);
|
| + B_LINE(ne, &error);
|
| +
|
| + // Check that cp is actually the current context
|
| + CMT("Check cp");
|
| + __ mov(r0, Operand((intptr_t)GLOBAL_CONTEXT_PTR(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, cp);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check MemOperand(cp, GLOBAL_OBJECT_INDEX) == GLOBAL_PTR())");
|
| + __ ldr(r0, MemOperand(cp, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
| + __ mov(r1, Operand((intptr_t)GLOBAL_PTR(), RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check FieldMemOperand(GLOBAL_PTR(), GlobalContextOffset) "
|
| + "== GLOBAL_CONTEXT_PTR())");
|
| + __ ldr(r0, FieldMemOperand(r0,
|
| + GlobalObject::kGlobalContextOffset));
|
| + __ mov(r1, Operand((intptr_t)GLOBAL_CONTEXT_PTR(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check MemOperand(GLOBAL_CONTEXT_PTR(), CLOSURE_INDEX) "
|
| + "== GLOBAL_CLOSURE_PTR())");
|
| + __ ldr(r0, MemOperand(r0,
|
| + Context::SlotOffset(Context::CLOSURE_INDEX)));
|
| + __ mov(r1, Operand((intptr_t)GLOBAL_CLOSURE_PTR(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check CompareInstanceType(GLOBAL_PTR()) == JS_GLOBAL_OBJECT_TYPE");
|
| + __ mov(r0, Operand((intptr_t)GLOBAL_PTR(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
|
| + __ CompareInstanceType(r1, r2/*type*/ , JS_GLOBAL_OBJECT_TYPE, eq);
|
| + B_LINE(f, &error);
|
| + __ cmp(r2, Operand(JS_GLOBAL_OBJECT_TYPE));
|
| + B_LINE(f, &error);
|
| + CMT("Check CompareInstanceType(GLOBAL_PTR()) != JS_VALUE_TYPE");
|
| + __ CompareInstanceType(r1, r2/*type*/ , JS_VALUE_TYPE, eq);
|
| + B_LINE(t, &error);
|
| + CMT("Check CompareInstanceType(GLOBAL_PTR()) >= (ge) FIRST_SPEC_OBJECT_TYPE");
|
| + __ CompareInstanceType(r1, r2/*type*/ , FIRST_SPEC_OBJECT_TYPE, ge);
|
| + B_LINE(f, &error);
|
| + CMT("Check CompareInstanceType(GLOBAL_PTR()) > (hs) FIRST_SPEC_OBJECT_TYPE");
|
| + __ CompareInstanceType(r1, r2/*type*/ , FIRST_SPEC_OBJECT_TYPE, hs);
|
| + B_LINE(f, &error);
|
| +
|
| + CMT("Check CompareObjectType(GLOBAL_PTR()) == JS_GLOBAL_OBJECT_TYPE");
|
| + __ CompareObjectType(r0, r3/*map*/, r4/*type*/ , JS_GLOBAL_OBJECT_TYPE, eq);
|
| + B_LINE(f, &error);
|
| + __ cmp(r1, r3); // check that map matches
|
| + B_LINE(f, &error);
|
| + __ cmp(r2, r4); // check that type matches
|
| +
|
| + // All ok.
|
| + __ mov(r0, Operand(Smi::FromInt(0)));
|
| + __ rts();
|
| +
|
| + __ bind(&error);
|
| + __ SmiTag(r0, r10);
|
| + __ rts();
|
| +
|
| + JIT();
|
| +
|
| + PRINT();
|
| +
|
| + CALL();
|
| +
|
| + // The function must return a result as Smi.
|
| + CHECK(result->IsSmi());
|
| + CHECK_EQ(0, Smi::cast(*result)->value());
|
| +}
|
| +
|
| +
|
| +// Test LoadGlobalFunction(), LoadContext(), LoadGlobalFunctionInitialMap()
|
| +// TryGetFunctionPrototype()
|
| +TEST(sh4_cs_3) {
|
| + BEGIN();
|
| +
|
| + Label error;
|
| +
|
| + CMT("Check LoadContext() == @(isolate+kContextAddress)");
|
| + __ LoadContext(r0, 0);
|
| + __ mov(r1, Operand(ExternalReference(Isolate::kContextAddress, isolate)));
|
| + __ ldr(r1, MemOperand(r1));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check LoadContext() == isolate->context()");
|
| + __ mov(r1, Operand((intptr_t)isolate->context(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check LoadContext() == isolate->global_context()");
|
| + __ mov(r1, Operand((intptr_t)GLOBAL_CONTEXT_PTR(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check LoadContext() == LoadContext()->global_object->global_context");
|
| + __ ldr(r1, MemOperand(r0, Context::SlotOffset(Context::GLOBAL_OBJECT_INDEX)));
|
| + __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalContextOffset));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check LoadContext(level 1) == NULL");
|
| + __ LoadContext(r0, 1);
|
| + __ mov(r1, Operand(0));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| +
|
| + CMT("Check LoadGlobalFunction() == Global Closure");
|
| + // Check
|
| + __ LoadGlobalFunction(Context::CLOSURE_INDEX, r0/* Resulting closure*/);
|
| + __ mov(r1, Operand((intptr_t)GLOBAL_CLOSURE_PTR(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check LoadGlobalFunctionInitialMap() == "
|
| + "Global Object Function->initial_map()");
|
| + __ LoadGlobalFunction(Context::OBJECT_FUNCTION_INDEX,
|
| + r0/* Resulting closure*/);
|
| + __ mov(r1, Operand((intptr_t)GLOBAL_OBJECT_FUNCTION_PTR(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| +
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| + __ LoadGlobalFunctionInitialMap(r0, r1/*result map*/, r2/*scratch*/);
|
| + __ mov(r0, Operand((intptr_t)GLOBAL_OBJECT_FUNCTION_PTR()->
|
| + prototype_or_initial_map(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r1, r0);
|
| + B_LINE(ne, &error);
|
| +
|
| + Label miss1, miss2, miss3, miss4, skip_proto4;
|
| + CMT("Check TryGetFunctionPrototype: Smi");
|
| + __ mov(r0, Operand(Smi::FromInt(1)));
|
| + __ TryGetFunctionPrototype(r0, r1 /*proto*/, r2 /*scratch*/, &miss1);
|
| + B_LINE(al, &error);
|
| + __ bind(&miss1);
|
| + CMT("Check TryGetFunctionPrototype: Not a function");
|
| + __ LoadRoot(r0, Heap::kTheHoleValueRootIndex);
|
| + __ TryGetFunctionPrototype(r0, r1 /*proto*/, r2 /*scratch*/, &miss2);
|
| + B_LINE(al, &error);
|
| + __ bind(&miss2);
|
| + CMT("Check TryGetFunctionPrototype(empty_function) == the_hole_value");
|
| + __ LoadGlobalFunction(Context::CLOSURE_INDEX, r0/* Resulting closure*/);
|
| + __ TryGetFunctionPrototype(r0, r1 /*proto*/, r2 /*scratch*/, &miss3);
|
| + B_LINE(al, &error);
|
| + __ bind(&miss3);
|
| + __ LoadRoot(r2, Heap::kTheHoleValueRootIndex);
|
| + __ cmp(r1, r2);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check TryGetFunctionPrototype(global_object_function) == "
|
| + "initial_map->prototype()");
|
| + __ LoadGlobalFunction(Context::OBJECT_FUNCTION_INDEX,
|
| + r0/* Resulting closure*/);
|
| + __ TryGetFunctionPrototype(r0, r1 /*proto*/, r2 /*scratch*/, &miss4);
|
| + __ jmp(&skip_proto4);
|
| + __ bind(&miss4);
|
| + B_LINE(al, &error);
|
| + __ bind(&skip_proto4);
|
| + __ LoadGlobalFunctionInitialMap(r0, r3/*result map*/, r2/*scratch*/);
|
| + __ ldr(r3, FieldMemOperand(r3, Map::kPrototypeOffset));
|
| + __ cmp(r1, r3);
|
| + B_LINE(ne, &error);
|
| +
|
| + // All ok.
|
| + __ mov(r0, Operand(Smi::FromInt(0)));
|
| + __ rts();
|
| +
|
| + __ bind(&error);
|
| + __ SmiTag(r0, r10);
|
| + __ rts();
|
| +
|
| + JIT();
|
| +
|
| + PRINT();
|
| +
|
| + CALL();
|
| +
|
| + // The function must return a result as Smi.
|
| + CHECK(result->IsSmi());
|
| + CHECK_EQ(0, Smi::cast(*result)->value());
|
| +}
|
| +
|
| +
|
| +// Test GetBuiltinFunction()/GetBuiltinEntry()
|
| +TEST(sh4_cs_4) {
|
| + BEGIN();
|
| +
|
| + Label error;
|
| +
|
| + // First check that the builtin function is actually undefined
|
| + // as we do not activate natives.
|
| + // Then install the empty function for the purpose of the tests.
|
| + CHECK(isolate->global_object()->builtins()->
|
| + javascript_builtin(Builtins::MUL)->IsUndefined());
|
| + isolate->global_object()->builtins()->
|
| + set_javascript_builtin(Builtins::MUL,
|
| + isolate->global_context()->closure());
|
| + isolate->global_object()->builtins()->
|
| + set_javascript_builtin_code(Builtins::MUL,
|
| + isolate->global_context()->closure()->code());
|
| + CMT("Check GetBuiltinFunction(Builtins::MUL)");
|
| + __ GetBuiltinFunction(r0, Builtins::MUL);
|
| + __ mov(r1, Operand((intptr_t)isolate->global_object()->builtins()->
|
| + javascript_builtin(Builtins::MUL),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check GetBuiltinEntry(Builtins::MUL)");
|
| + __ GetBuiltinEntry(r0, Builtins::MUL);
|
| + __ mov(r1, Operand((intptr_t)isolate->global_object()->builtins()->
|
| + javascript_builtin_code(Builtins::MUL)->entry(),
|
| + RelocInfo::EXTERNAL_REFERENCE));
|
| + __ cmp(r0, r1);
|
| + B_LINE(ne, &error);
|
| +
|
| + // All ok.
|
| + __ mov(r0, Operand(Smi::FromInt(0)));
|
| + __ rts();
|
| +
|
| + __ bind(&error);
|
| + __ SmiTag(r0, r10);
|
| + __ rts();
|
| +
|
| + JIT();
|
| +
|
| + PRINT();
|
| +
|
| + CALL();
|
| +
|
| + // The function must return a result as Smi.
|
| + CHECK(result->IsSmi());
|
| + CHECK_EQ(0, Smi::cast(*result)->value());
|
| +}
|
| +
|
| +
|
| +static double
|
| +ObjectToNumber(Object *object) {
|
| + double cast_value;
|
| + if (object->IsSmi()) {
|
| + int int_value = Smi::cast(object)->value();
|
| + cast_value = static_cast<double>(int_value);
|
| + } else if (object->IsHeapNumber()) {
|
| + cast_value = HeapNumber::cast(object)->value();
|
| + } else {
|
| + // Return 0 when not a number
|
| + cast_value = 0;
|
| + }
|
| + return cast_value;
|
| +}
|
| +
|
| +// Test TailCallRuntime()
|
| +TEST(sh4_cs_5) {
|
| + {
|
| + BEGIN();
|
| + CMT("Check TailCallRuntime: NumberToJSint32(13)");
|
| + __ mov(r0, Operand(Smi::FromInt(13)));
|
| + __ push(r0);
|
| + __ TailCallRuntime(Runtime::kNumberToJSInt32, 1, 1);
|
| +
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(13.0, ObjectToNumber(*result));
|
| + }
|
| + {
|
| + BEGIN();
|
| + CMT("Check CallRuntime: NumberAdd(7, 27)");
|
| + {
|
| + FrameScope scpe(&assm, StackFrame::INTERNAL);
|
| + __ mov(r0, Operand(Smi::FromInt(7)));
|
| + __ mov(r1, Operand(Smi::FromInt(27)));
|
| + __ Push(r0, r1);
|
| + __ CallRuntime(Runtime::kNumberAdd, 2);
|
| + }
|
| + __ Ret();
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(34.0, ObjectToNumber(*result));
|
| + }
|
| + {
|
| + BEGIN();
|
| + CMT("Check CallRuntime: NumberToString(1234)");
|
| + {
|
| + FrameScope scpe(&assm, StackFrame::INTERNAL);
|
| + __ mov(r0, Operand(Smi::FromInt(1234)));
|
| + __ push(r0);
|
| + __ CallRuntime(Runtime::kNumberToString, 1);
|
| + CMT("Check CallRuntime: GlobalPrint(\"1234\")");
|
| + __ push(r0);
|
| + __ CallRuntime(Runtime::kGlobalPrint, 1);
|
| + }
|
| + __ Ret();
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsString());
|
| + CHECK(String::cast(*result)->IsEqualTo(CStrVector("1234")));
|
| + }
|
| +}
|
| +
|
| +#undef __
|
| +#define __ assm->
|
| +static void
|
| +GenerateNumberFromReg(MacroAssembler *assm, Register heap, Register reg) {
|
| + ASSERT(!reg.is(r4) && !reg.is(r5) && !reg.is(r6) && !reg.is(r7));
|
| + Label gc_required, skip, not_smi;
|
| +
|
| + {
|
| + FrameScope scpe(assm, StackFrame::INTERNAL);
|
| + __ Push(r4, r5, r6, r7);
|
| + __ TrySmiTag(reg, ¬_smi, r5/*scratch*/);
|
| + __ mov(heap, reg);
|
| + __ jmp(&skip);
|
| + __ bind(¬_smi);
|
| + __ LoadRoot(r7, Heap::kHeapNumberMapRootIndex);
|
| + __ AllocateHeapNumber(r4/*result heap number*/, r5/*scratch*/,
|
| + r6/*scratch*/, r7/*heap_number_map*/, &gc_required);
|
| + WriteInt32ToHeapNumberStub stub(reg, r4, r5/*scratch*/);
|
| + __ CallStub(&stub);
|
| + __ mov(heap, r4);
|
| + __ Pop(r6, r7);
|
| + __ Pop(r4, r5);
|
| + }
|
| + __ jmp(&skip);
|
| + __ bind(&gc_required);
|
| + __ Abort("GC required while dumping number");
|
| + __ bind(&skip);
|
| +}
|
| +#undef __
|
| +#define __ assm.
|
| +
|
| +// Test WriteInt32ToHeapNumberStub()
|
| +TEST(sh4_cs_6) {
|
| + {
|
| + BEGIN();
|
| +
|
| + __ mov(r0, Operand(0));
|
| + GenerateNumberFromReg(&assm, r0, r0);
|
| + __ Ret();
|
| +
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(0, static_cast<int>(ObjectToNumber(*result)));
|
| + }
|
| + {
|
| + BEGIN();
|
| +
|
| + __ mov(r0, Operand(1234));
|
| + GenerateNumberFromReg(&assm, r0, r0);
|
| + __ Ret();
|
| +
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(1234, static_cast<int>(ObjectToNumber(*result)));
|
| + }
|
| + {
|
| + BEGIN();
|
| +
|
| + __ mov(r0, Operand(0x7fffffff));
|
| + GenerateNumberFromReg(&assm, r0, r0);
|
| + __ Ret();
|
| +
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(0x7fffffff, static_cast<int>(ObjectToNumber(*result)));
|
| + }
|
| + {
|
| + BEGIN();
|
| +
|
| + __ mov(r0, Operand(0x80000000u));
|
| + GenerateNumberFromReg(&assm, r0, r0);
|
| + __ Ret();
|
| +
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(0x80000000u, static_cast<int>(ObjectToNumber(*result)));
|
| + }
|
| +}
|
| +
|
| +#undef __
|
| +#define __ assm->
|
| +static void
|
| +GeneratePrintReg(MacroAssembler *assm, Register reg) {
|
| + ASSERT(!reg.is(r4) && !reg.is(r5) && !reg.is(r6) && !reg.is(r7));
|
| + Label gc_required, skip, not_smi;
|
| + {
|
| + FrameScope scpe(assm, StackFrame::INTERNAL);
|
| + // Save reg as it is scratched by WriteInt32ToHeapNumberStub()
|
| + __ push(reg);
|
| + __ pushm(kJSCallerSaved);
|
| + __ TrySmiTag(reg, ¬_smi, r5/*scratch*/);
|
| + __ mov(r4, reg);
|
| + __ jmp(&skip);
|
| + __ bind(¬_smi);
|
| + __ LoadRoot(r7, Heap::kHeapNumberMapRootIndex);
|
| + __ AllocateHeapNumber(r4/*result heap number*/, r5/*scratch*/,
|
| + r6/*scratch*/, r7/*heap_number_map*/, &gc_required);
|
| + WriteInt32ToHeapNumberStub stub(reg, r4, r5/*scratch*/);
|
| + __ CallStub(&stub);
|
| + __ jmp(&skip);
|
| + __ bind(&gc_required);
|
| + __ Abort("GC required while dumping number");
|
| + __ bind(&skip);
|
| + __ push(r4);
|
| + __ CallRuntime(Runtime::kNumberToString, 1);
|
| + __ push(r0);
|
| + __ CallRuntime(Runtime::kGlobalPrint, 1);
|
| + __ popm(kJSCallerSaved);
|
| + __ pop(reg);
|
| + }
|
| +}
|
| +#undef __
|
| +#define __ assm.
|
| +
|
| +// Test GeneratePrintReg()
|
| +TEST(sh4_cs_7) {
|
| + BEGIN();
|
| +
|
| + __ mov(r0, Operand(1234));
|
| + GeneratePrintReg(&assm, r0);
|
| + __ mov(r0, Operand(0x7fffffff));
|
| + GeneratePrintReg(&assm, r0);
|
| + __ mov(r0, Operand(0x80000000));
|
| + GeneratePrintReg(&assm, r0);
|
| + __ PrintRegisterValue(r0);
|
| + __ mov(r0, Operand(0));
|
| + __ Ret();
|
| +
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(0.0, ObjectToNumber(*result));
|
| +}
|
| +
|
| +
|
| +// Test CompareStub()
|
| +TEST(sh4_cs_8) {
|
| + BEGIN();
|
| +
|
| + Label error;
|
| +
|
| + // Enter Fram before call stubs
|
| + {
|
| + FrameScope scpe(&assm, StackFrame::INTERNAL);
|
| +
|
| + CompareStub stub(eq/*cond*/, true/*strict*/, NO_COMPARE_FLAGS, r0, r1);
|
| +#if 1 && defined(DEBUG)
|
| + stub.GetCode()->Print();
|
| +#endif
|
| +
|
| + CMT("Check CompareStub(0, 0) == 0");
|
| + __ mov(r0, Operand(Smi::FromInt(0)));
|
| + __ mov(r1, Operand(Smi::FromInt(0)));
|
| + __ CallStub(&stub);
|
| + __ cmp(r0, Operand(0));
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check CompareStub(1, 1) == 0");
|
| + __ mov(r0, Operand(Smi::FromInt(1)));
|
| + __ mov(r1, Operand(Smi::FromInt(1)));
|
| + __ CallStub(&stub);
|
| + __ cmp(r0, Operand(0));
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check CompareStub(0, 1) > 0");
|
| + __ mov(r0, Operand(Smi::FromInt(0)));
|
| + __ mov(r1, Operand(Smi::FromInt(1)));
|
| + __ CallStub(&stub);
|
| + __ cmpgt(r0, Operand(0));
|
| + B_LINE(ne, &error);
|
| +
|
| + CMT("Check CompareStub(-1, 2) > 0");
|
| + __ mov(r0, Operand(Smi::FromInt(-1)));
|
| + __ mov(r1, Operand(Smi::FromInt(2)));
|
| + __ CallStub(&stub);
|
| + __ cmp(r0, Operand(0));
|
| + B_LINE(eq, &error);
|
| +
|
| + // CMT("Check CompareStub(0, heap(0)) == 0");
|
| + // __ mov(r0, Operand(Smi::FromInt(0)));
|
| + // __ mov(r1, Operand(0));
|
| + // GenerateNumberFromReg(&assm, r1, r1);
|
| + // __ CallStub(&stub);
|
| + // __ cmp(r0, Operand(0));
|
| + // B_LINE(ne, &error);
|
| +
|
| + // All ok.
|
| + __ mov(r0, Operand(Smi::FromInt(0)));
|
| + __ rts();
|
| +
|
| + __ bind(&error);
|
| + __ SmiTag(r0, r10);
|
| + __ rts();
|
| + }
|
| +
|
| + JIT();
|
| + PRINT();
|
| + CALL();
|
| + CHECK(result->IsNumber());
|
| + CHECK_EQ(0, static_cast<int>(ObjectToNumber(*result)));
|
| +}
|
|
|