Commit abc35080 authored by danno's avatar danno Committed by Commit bot

Add a MathFloor stub generated with TurboFan

This stub will be used as the basis of a Math.floor-specific CallIC to
detect and track calls to floor that return -0.

Along the way:
- Create a TurboFanCodeStub super class from which the StringLength and
MathRound TF stubs derive.
- Fix the ugly hack that passes the first stub parameter as the "this"
pointer in the the TF-compiled JS function.
- Fix bugs in the ia32/x64 disassembler.

Review URL: https://codereview.chromium.org/1137703002

Cr-Commit-Position: refs/heads/master@{#28339}
parent f750cc09
......@@ -393,6 +393,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
data->Initialize(arraysize(registers), registers, representations,
&default_descriptor);
}
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
cp, // context
r1, // math rounding function
r3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
}
} // namespace v8::internal
......
......@@ -444,6 +444,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
data->Initialize(arraysize(registers), registers, representations,
&default_descriptor);
}
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
cp, // context
x1, // math rounding function
x3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
}
} // namespace v8::internal
......
......@@ -13,6 +13,7 @@
#include "src/ic/handler-compiler.h"
#include "src/ic/ic.h"
#include "src/macro-assembler.h"
#include "src/parser.h"
namespace v8 {
namespace internal {
......@@ -453,6 +454,35 @@ void CompareNilICStub::UpdateStatus(Handle<Object> object) {
}
namespace {
Handle<JSFunction> GetFunction(Isolate* isolate, const char* name) {
v8::ExtensionConfiguration no_extensions;
Handle<Context> ctx = isolate->bootstrapper()->CreateEnvironment(
MaybeHandle<JSGlobalProxy>(), v8::Handle<v8::ObjectTemplate>(),
&no_extensions);
Handle<JSBuiltinsObject> builtins = handle(ctx->builtins());
MaybeHandle<Object> fun = Object::GetProperty(isolate, builtins, name);
Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked());
DCHECK(!function->IsUndefined() &&
"JavaScript implementation of stub not found");
// Just to make sure nobody calls this...
function->set_code(isolate->builtins()->builtin(Builtins::kIllegal));
return function;
}
} // namespace
Handle<Code> TurboFanCodeStub::GenerateCode() {
Zone zone;
// Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair.
ParseInfo parse_info(&zone, GetFunction(isolate(), GetFunctionName()));
CompilationInfo info(&parse_info);
info.SetStub(this);
return info.GenerateCodeStub();
}
template<class StateType>
void HydrogenCodeStub::TraceTransition(StateType from, StateType to) {
// Note: Although a no-op transition is semantically OK, it is hinting at a
......
......@@ -89,6 +89,9 @@ namespace internal {
V(TransitionElementsKind) \
V(VectorRawKeyedLoad) \
V(VectorRawLoad) \
/* TurboFanCodeStubs */ \
V(StringLengthTF) \
V(MathFloor) \
/* IC Handler stubs */ \
V(ArrayBufferViewLoadField) \
V(LoadConstant) \
......@@ -152,6 +155,8 @@ namespace internal {
CODE_STUB_LIST_PPC(V) \
CODE_STUB_LIST_MIPS(V)
static const int kHasReturnedMinusZeroSentinel = 1;
// Stub is base classes of all stubs.
class CodeStub BASE_EMBEDDED {
public:
......@@ -206,6 +211,8 @@ class CodeStub BASE_EMBEDDED {
virtual CallInterfaceDescriptor GetCallInterfaceDescriptor() = 0;
virtual int GetStackParameterCount() const { return 0; }
virtual void InitializeDescriptor(CodeStubDescriptor* descriptor) {}
static void InitializeDescriptor(Isolate* isolate, uint32_t key,
......@@ -348,6 +355,19 @@ struct FakeStubForTesting : public CodeStub {
Handle<Code> GenerateCode() override; \
DEFINE_CODE_STUB(NAME, SUPER)
#define DEFINE_TURBOFAN_CODE_STUB(NAME, SUPER, DESC, STACK_PARAMS) \
public: \
NAME##Stub(Isolate* isolate) : SUPER(isolate) {} \
CallInterfaceDescriptor GetCallInterfaceDescriptor() override { \
return DESC(isolate()); \
}; \
virtual const char* GetFunctionName() const override { \
return #NAME "_STUB"; \
} \
int GetStackParameterCount() const override { return STACK_PARAMS; } \
Code::StubType GetStubType() const override { return Code::FAST; } \
DEFINE_CODE_STUB(NAME, SUPER)
#define DEFINE_HANDLER_CODE_STUB(NAME, SUPER) \
public: \
Handle<Code> GenerateCode() override; \
......@@ -518,6 +538,23 @@ class HydrogenCodeStub : public CodeStub {
};
class TurboFanCodeStub : public CodeStub {
public:
Code::Kind GetCodeKind() const override { return Code::STUB; }
// Retrieve the code for the stub. Generate the code if needed.
Handle<Code> GenerateCode() override;
virtual const char* GetFunctionName() const = 0;
protected:
explicit TurboFanCodeStub(Isolate* isolate) : CodeStub(isolate) {}
private:
DEFINE_CODE_STUB_BASE(TurboFanCodeStub, CodeStub);
};
// Helper interface to prepare to/restore after making runtime calls.
class RuntimeCallHelper {
public:
......@@ -584,6 +621,23 @@ class NopRuntimeCallHelper : public RuntimeCallHelper {
};
class MathFloorStub : public TurboFanCodeStub {
DEFINE_TURBOFAN_CODE_STUB(MathFloor, TurboFanCodeStub,
MathRoundVariantDescriptor, 1);
};
class StringLengthTFStub : public TurboFanCodeStub {
DEFINE_TURBOFAN_CODE_STUB(StringLengthTF, TurboFanCodeStub, LoadDescriptor,
0);
public:
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
InlineCacheState GetICState() const override { return MONOMORPHIC; }
ExtraICState GetExtraICState() const override { return Code::LOAD_IC; }
};
class NumberToStringStub final : public HydrogenCodeStub {
public:
explicit NumberToStringStub(Isolate* isolate) : HydrogenCodeStub(isolate) {}
......
......@@ -175,6 +175,14 @@ int CompilationInfo::num_parameters() const {
}
int CompilationInfo::num_parameters_including_this() const {
return num_parameters() + (is_this_defined() ? 1 : 0);
}
bool CompilationInfo::is_this_defined() const { return !IsStub(); }
int CompilationInfo::num_heap_slots() const {
return has_scope() ? scope()->num_heap_slots() : 0;
}
......@@ -273,6 +281,14 @@ void CompilationInfo::LogDeoptCallPosition(int pc_offset, int inlining_id) {
}
Handle<Code> CompilationInfo::GenerateCodeStub() {
// Run a "mini pipeline", extracted from compiler.cc.
CHECK(Parser::ParseStatic(parse_info()));
CHECK(Compiler::Analyze(parse_info()));
return compiler::Pipeline(this).GenerateCode();
}
class HOptimizedGraphBuilderWithPositions: public HOptimizedGraphBuilder {
public:
explicit HOptimizedGraphBuilderWithPositions(CompilationInfo* info)
......
......@@ -165,6 +165,8 @@ class CompilationInfo {
Handle<Code> unoptimized_code() const { return unoptimized_code_; }
int opt_count() const { return opt_count_; }
int num_parameters() const;
int num_parameters_including_this() const;
bool is_this_defined() const;
int num_heap_slots() const;
Code::Flags flags() const;
bool has_scope() const { return scope() != nullptr; }
......@@ -387,6 +389,8 @@ class CompilationInfo {
bool is_simple_parameter_list();
Handle<Code> GenerateCodeStub();
protected:
ParseInfo* parse_info_;
......
......@@ -150,6 +150,20 @@ ElementAccess AccessBuilder::ForSeqStringChar(String::Encoding encoding) {
return {kUntaggedBase, 0, Type::None(), kMachNone};
}
// static
FieldAccess AccessBuilder::ForJSFunctionSharedFunctionInfo() {
return {kTaggedBase, JSFunction::kSharedFunctionInfoOffset, Handle<Name>(),
Type::Any(), kMachAnyTagged};
}
// static
FieldAccess AccessBuilder::ForSharedFunctionInfoTypeFeedbackVector() {
return {kTaggedBase, SharedFunctionInfo::kFeedbackVectorOffset,
Handle<Name>(), Type::Any(), kMachAnyTagged};
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -65,6 +65,12 @@ class AccessBuilder final : public AllStatic {
// Provides access to the charaters of sequential strings.
static ElementAccess ForSeqStringChar(String::Encoding encoding);
// Provides access to the SharedFunctionInfo in a JSFunction.
static FieldAccess ForJSFunctionSharedFunctionInfo();
// Provides access to the TypeFeedbackVector in SharedFunctionInfo.
static FieldAccess ForSharedFunctionInfoTypeFeedbackVector();
private:
DISALLOW_IMPLICIT_CONSTRUCTORS(AccessBuilder);
};
......
......@@ -429,7 +429,7 @@ void AstGraphBuilder::CreateFunctionContext(bool constant_context) {
Node* AstGraphBuilder::NewOuterContextParam() {
// Parameter (arity + 1) is special for the outer context of the function
const Operator* op =
common()->Parameter(info()->num_parameters() + 1, "%context");
common()->Parameter(info()->num_parameters_including_this(), "%context");
return NewNode(op, graph()->start());
}
......@@ -437,8 +437,8 @@ Node* AstGraphBuilder::NewOuterContextParam() {
Node* AstGraphBuilder::NewCurrentContextOsrValue() {
// TODO(titzer): use a real OSR value here; a parameter works by accident.
// Parameter (arity + 1) is special for the outer context of the function
const Operator* op =
common()->Parameter(info()->num_parameters() + 1, "%osr-context");
const Operator* op = common()->Parameter(
info()->num_parameters_including_this(), "%osr-context");
return NewNode(op, graph()->start());
}
......@@ -615,16 +615,22 @@ AstGraphBuilder::Environment::Environment(AstGraphBuilder* builder,
DCHECK_EQ(scope->num_parameters() + 1, parameters_count());
// Bind the receiver variable.
Node* receiver = builder->graph()->NewNode(common()->Parameter(0, "%this"),
builder->graph()->start());
values()->push_back(receiver);
int param_num = 0;
if (builder->info()->is_this_defined()) {
Node* receiver = builder->graph()->NewNode(
common()->Parameter(param_num++, "%this"), builder->graph()->start());
values()->push_back(receiver);
} else {
values()->push_back(builder->jsgraph()->UndefinedConstant());
}
// Bind all parameter variables. The parameter indices are shifted by 1
// (receiver is parameter index -1 but environment index 0).
for (int i = 0; i < scope->num_parameters(); ++i) {
const char* debug_name = GetDebugParameterName(graph()->zone(), scope, i);
Node* parameter = builder->graph()->NewNode(
common()->Parameter(i + 1, debug_name), builder->graph()->start());
Node* parameter =
builder->graph()->NewNode(common()->Parameter(param_num++, debug_name),
builder->graph()->start());
values()->push_back(parameter);
}
......
......@@ -74,6 +74,12 @@ Reduction JSIntrinsicLowering::Reduce(Node* node) {
return ReduceUnLikely(node, BranchHint::kFalse);
case Runtime::kInlineValueOf:
return ReduceValueOf(node);
case Runtime::kInlineIsMinusZero:
return ReduceIsMinusZero(node);
case Runtime::kInlineFixedArraySet:
return ReduceFixedArraySet(node);
case Runtime::kInlineGetTypeFeedbackVector:
return ReduceGetTypeFeedbackVector(node);
default:
break;
}
......@@ -398,6 +404,67 @@ Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op) {
}
Reduction JSIntrinsicLowering::ReduceIsMinusZero(Node* node) {
Node* value = NodeProperties::GetValueInput(node, 0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* double_lo =
graph()->NewNode(machine()->Float64ExtractLowWord32(), value);
Node* check1 = graph()->NewNode(machine()->Word32Equal(), double_lo,
jsgraph()->ZeroConstant());
Node* double_hi =
graph()->NewNode(machine()->Float64ExtractHighWord32(), value);
Node* check2 = graph()->NewNode(
machine()->Word32Equal(), double_hi,
jsgraph()->Int32Constant(static_cast<int32_t>(0x80000000)));
NodeProperties::ReplaceWithValue(node, node, effect);
Node* and_result = graph()->NewNode(machine()->Word32And(), check1, check2);
return Change(node, machine()->Word32Equal(), and_result,
jsgraph()->Int32Constant(1));
}
Reduction JSIntrinsicLowering::ReduceFixedArraySet(Node* node) {
Node* base = node->InputAt(0);
Node* index = node->InputAt(1);
Node* value = node->InputAt(2);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
Node* store = (graph()->NewNode(
simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()), base,
index, value, effect, control));
NodeProperties::ReplaceWithValue(node, value, store);
return Changed(store);
}
Reduction JSIntrinsicLowering::ReduceGetTypeFeedbackVector(Node* node) {
Node* func = node->InputAt(0);
Node* effect = NodeProperties::GetEffectInput(node);
Node* control = NodeProperties::GetControlInput(node);
FieldAccess access = AccessBuilder::ForJSFunctionSharedFunctionInfo();
Node* load =
graph()->NewNode(simplified()->LoadField(access), func, effect, control);
access = AccessBuilder::ForSharedFunctionInfoTypeFeedbackVector();
return Change(node, simplified()->LoadField(access), load, load, control);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
Node* b) {
node->set_op(op);
node->ReplaceInput(0, a);
node->ReplaceInput(1, b);
node->TrimInputCount(2);
NodeProperties::ReplaceWithValue(node, node, node);
return Changed(node);
}
Reduction JSIntrinsicLowering::Change(Node* node, const Operator* op, Node* a,
Node* b, Node* c) {
node->set_op(op);
......
......@@ -34,6 +34,7 @@ class JSIntrinsicLowering final : public Reducer {
Reduction ReduceDoubleLo(Node* node);
Reduction ReduceHeapObjectGetMap(Node* node);
Reduction ReduceIncrementStatsCounter(Node* node);
Reduction ReduceIsMinusZero(Node* node);
Reduction ReduceIsInstanceType(Node* node, InstanceType instance_type);
Reduction ReduceIsNonNegativeSmi(Node* node);
Reduction ReduceIsSmi(Node* node);
......@@ -47,8 +48,11 @@ class JSIntrinsicLowering final : public Reducer {
Reduction ReduceStringGetLength(Node* node);
Reduction ReduceUnLikely(Node* node, BranchHint hint);
Reduction ReduceValueOf(Node* node);
Reduction ReduceFixedArraySet(Node* node);
Reduction ReduceGetTypeFeedbackVector(Node* node);
Reduction Change(Node* node, const Operator* op);
Reduction Change(Node* node, const Operator* op, Node* a, Node* b);
Reduction Change(Node* node, const Operator* op, Node* a, Node* b, Node* c);
Reduction ChangeToUndefined(Node* node, Node* effect = nullptr);
......
......@@ -51,11 +51,11 @@ bool CallDescriptor::HasSameReturnLocationsAs(
CallDescriptor* Linkage::ComputeIncoming(Zone* zone, CompilationInfo* info) {
if (info->code_stub() != NULL) {
// Use the code stub interface descriptor.
CallInterfaceDescriptor descriptor =
info->code_stub()->GetCallInterfaceDescriptor();
return GetStubCallDescriptor(info->isolate(), zone, descriptor, 0,
CallDescriptor::kNoFlags,
Operator::kNoProperties);
CodeStub* stub = info->code_stub();
CallInterfaceDescriptor descriptor = stub->GetCallInterfaceDescriptor();
return GetStubCallDescriptor(
info->isolate(), zone, descriptor, stub->GetStackParameterCount(),
CallDescriptor::kNoFlags, Operator::kNoProperties);
}
if (info->function() != NULL) {
// If we already have the function literal, use the number of parameters
......
......@@ -1576,6 +1576,7 @@ Bounds Typer::Visitor::TypeJSCallRuntime(Node* node) {
case Runtime::kInlineIsSmi:
case Runtime::kInlineIsNonNegativeSmi:
case Runtime::kInlineIsArray:
case Runtime::kInlineIsMinusZero:
case Runtime::kInlineIsFunction:
case Runtime::kInlineIsRegExp:
return Bounds(Type::None(zone()), Type::Boolean(zone()));
......
......@@ -1641,7 +1641,7 @@ int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
} else if (*data == 0x16) {
data++;
int mod, regop, rm;
get_modrm(*data, &mod, &regop, &rm);
get_modrm(*data, &mod, &rm, &regop);
int8_t imm8 = static_cast<int8_t>(data[1]);
AppendToBuffer("pextrd %s,%s,%d",
NameOfCPURegister(regop),
......
......@@ -370,6 +370,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
};
data->Initialize(arraysize(registers), registers, representations);
}
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
esi, // context
edi, // math rounding function
edx, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
}
} // namespace v8::internal
......
......@@ -58,6 +58,7 @@ class PlatformInterfaceDescriptor;
V(StoreArrayLiteralElement) \
V(MathPowTagged) \
V(MathPowInteger) \
V(MathRoundVariant) \
V(ContextOnly) \
V(GrowArrayElements)
......@@ -528,6 +529,12 @@ class MathPowIntegerDescriptor : public CallInterfaceDescriptor {
};
class MathRoundVariantDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(MathRoundVariantDescriptor, CallInterfaceDescriptor)
};
class ContextOnlyDescriptor : public CallInterfaceDescriptor {
public:
DECLARE_DESCRIPTOR(ContextOnlyDescriptor, CallInterfaceDescriptor)
......
......@@ -369,6 +369,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
};
data->Initialize(arraysize(registers), registers, representations);
}
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
a1, // context
a2, // math rounding function
a3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
}
} // namespace v8::internal
......
......@@ -369,6 +369,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
};
data->Initialize(arraysize(registers), registers, representations);
}
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
a1, // context
a2, // math rounding function
a3, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
}
} // namespace v8::internal
......
......@@ -62,7 +62,8 @@ var TO_NUMBER;
var TO_STRING;
var TO_NAME;
var STRING_LENGTH_STUB;
var StringLengthTF_STUB;
var MathFloor_STUB;
var $defaultNumber;
var $defaultString;
......@@ -750,11 +751,31 @@ TO_NAME = function TO_NAME() {
-----------------------------------------------
*/
STRING_LENGTH_STUB = function STRING_LENGTH_STUB(name) {
var receiver = this; // implicit first parameter
StringLengthTF_STUB = function StringLengthTF_STUB(receiver, name) {
return %_StringGetLength(%_JSValueGetValue(receiver));
}
MathFloor_STUB = function MathFloor_STUB(f, i, v) {
// |f| is calling function's JSFunction
// |i| is TypeFeedbackVector slot # of callee's CallIC for Math.floor call
// |v| is the value to floor
var r = %_MathFloor(+v);
if (%_IsMinusZero(r)) {
// Collect type feedback when the result of the floor is -0. This is
// accomplished by storing a sentinel in the second, "extra"
// TypeFeedbackVector slot corresponding to the Math.floor CallIC call in
// the caller's TypeVector.
%_FixedArraySet(%_GetTypeFeedbackVector(f), ((i|0)+1)|0, 1);
return -0;
}
// Return integers in smi range as smis.
var trunc = r|0;
if (trunc === r) {
return trunc;
}
return r;
}
/* -------------------------------------
- - - C o n v e r s i o n s - - -
......
......@@ -54,6 +54,26 @@ RUNTIME_FUNCTION(Runtime_SpecialArrayFunctions) {
}
RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
return object->get(index);
}
RUNTIME_FUNCTION(Runtime_FixedArraySet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
CONVERT_ARG_CHECKED(Object, value, 2);
object->set(index, value);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_TransitionElementsKind) {
HandleScope scope(isolate);
RUNTIME_ASSERT(args.length() == 2);
......
......@@ -27,26 +27,6 @@ RUNTIME_FUNCTION(Runtime_TheHole) {
}
RUNTIME_FUNCTION(Runtime_FixedArrayGet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 2);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
return object->get(index);
}
RUNTIME_FUNCTION(Runtime_FixedArraySet) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 3);
CONVERT_ARG_CHECKED(FixedArray, object, 0);
CONVERT_SMI_ARG_CHECKED(index, 1);
CONVERT_ARG_CHECKED(Object, value, 2);
object->set(index, value);
return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_JSCollectionGetTable) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
......
......@@ -408,5 +408,13 @@ RUNTIME_FUNCTION(Runtime_HarmonyToString) {
// TODO(caitp): Delete this runtime method when removing --harmony-tostring
return isolate->heap()->ToBoolean(FLAG_harmony_tostring);
}
RUNTIME_FUNCTION(Runtime_GetTypeFeedbackVector) {
SealHandleScope shs(isolate);
DCHECK(args.length() == 1);
CONVERT_ARG_CHECKED(JSFunction, function, 0);
return function->shared()->feedback_vector();
}
}
} // namespace v8::internal
......@@ -49,6 +49,8 @@ namespace internal {
F(IsArray, 1, 1) \
F(HasCachedArrayIndex, 1, 1) \
F(GetCachedArrayIndex, 1, 1) \
F(FixedArrayGet, 2, 1) \
F(FixedArraySet, 3, 1) \
F(FastOneByteArrayJoin, 2, 1)
......@@ -78,8 +80,6 @@ namespace internal {
#define FOR_EACH_INTRINSIC_COLLECTIONS(F) \
F(StringGetRawHashField, 1, 1) \
F(TheHole, 0, 1) \
F(FixedArrayGet, 2, 1) \
F(FixedArraySet, 3, 1) \
F(JSCollectionGetTable, 1, 1) \
F(GenericHash, 1, 1) \
F(SetInitialize, 1, 1) \
......@@ -302,7 +302,8 @@ namespace internal {
F(IncrementStatsCounter, 1, 1) \
F(Likely, 1, 1) \
F(Unlikely, 1, 1) \
F(HarmonyToString, 0, 1)
F(HarmonyToString, 0, 1) \
F(GetTypeFeedbackVector, 1, 1)
#define FOR_EACH_INTRINSIC_JSON(F) \
......
......@@ -4,6 +4,7 @@
#include "src/v8.h"
#include "src/code-stubs.h"
#include "src/ic/ic.h"
#include "src/ic/ic-state.h"
#include "src/objects.h"
......@@ -312,7 +313,8 @@ InlineCacheState CallICNexus::StateFromFeedback() const {
Isolate* isolate = GetIsolate();
Object* feedback = GetFeedback();
DCHECK(!FLAG_vector_ics ||
GetFeedbackExtra() == *vector()->UninitializedSentinel(isolate));
GetFeedbackExtra() == *vector()->UninitializedSentinel(isolate) ||
GetFeedbackExtra() == Smi::FromInt(kHasReturnedMinusZeroSentinel));
if (feedback == *vector()->MegamorphicSentinel(isolate)) {
return GENERIC;
......
......@@ -1390,7 +1390,7 @@ int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
AppendToBuffer(",%d", (*current) & 3);
current += 1;
} else if (third_byte == 0x16) {
get_modrm(*current, &mod, &regop, &rm);
get_modrm(*current, &mod, &rm, &regop);
AppendToBuffer("pextrd "); // reg/m32, xmm, imm8
current += PrintRightOperand(current);
AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
......
......@@ -371,6 +371,21 @@ void ApiAccessorDescriptor::Initialize(CallInterfaceDescriptorData* data) {
};
data->Initialize(arraysize(registers), registers, representations);
}
void MathRoundVariantDescriptor::Initialize(CallInterfaceDescriptorData* data) {
Register registers[] = {
rsi, // context
rdi, // math rounding function
rdx, // vector slot id
};
Representation representations[] = {
Representation::Tagged(), //
Representation::Tagged(), //
Representation::Tagged(), //
};
data->Initialize(arraysize(registers), registers, representations);
}
}
} // namespace v8::internal
......
......@@ -6,7 +6,10 @@
#include "src/code-stubs.h"
#include "src/compiler/common-operator.h"
#include "src/compiler/graph.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-operator.h"
#include "src/compiler/linkage.h"
#include "src/compiler/machine-operator.h"
#include "src/compiler/pipeline.h"
#include "src/parser.h"
#include "test/cctest/compiler/function-tester.h"
......@@ -17,60 +20,54 @@ using namespace v8::internal;
using namespace v8::internal::compiler;
static Handle<JSFunction> GetFunction(Isolate* isolate, const char* name) {
v8::ExtensionConfiguration no_extensions;
Handle<Context> ctx = isolate->bootstrapper()->CreateEnvironment(
MaybeHandle<JSGlobalProxy>(), v8::Handle<v8::ObjectTemplate>(),
&no_extensions);
Handle<JSBuiltinsObject> builtins = handle(ctx->builtins());
MaybeHandle<Object> fun = Object::GetProperty(isolate, builtins, name);
Handle<JSFunction> function = Handle<JSFunction>::cast(fun.ToHandleChecked());
// Just to make sure nobody calls this...
function->set_code(isolate->builtins()->builtin(Builtins::kIllegal));
return function;
}
class StringLengthStubTF : public CodeStub {
public:
explicit StringLengthStubTF(Isolate* isolate) : CodeStub(isolate) {}
TEST(RunMathFloorStub) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
StringLengthStubTF(uint32_t key, Isolate* isolate) : CodeStub(key, isolate) {}
// Create code and an accompanying descriptor.
MathFloorStub stub(isolate);
Handle<Code> code = stub.GenerateCode();
Zone* zone = scope.main_zone();
CallInterfaceDescriptor GetCallInterfaceDescriptor() override {
return LoadDescriptor(isolate());
};
CompilationInfo info(&stub, isolate, zone);
CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info);
Handle<Code> GenerateCode() override {
Zone zone;
// Build a "hybrid" CompilationInfo for a JSFunction/CodeStub pair.
ParseInfo parse_info(&zone, GetFunction(isolate(), "STRING_LENGTH_STUB"));
CompilationInfo info(&parse_info);
info.SetStub(this);
// Run a "mini pipeline", extracted from compiler.cc.
CHECK(Parser::ParseStatic(info.parse_info()));
CHECK(Compiler::Analyze(info.parse_info()));
return Pipeline(&info).GenerateCode();
}
// Create a function to call the code using the descriptor.
Graph graph(zone);
CommonOperatorBuilder common(zone);
JSOperatorBuilder javascript(zone);
MachineOperatorBuilder machine(zone);
JSGraph js(isolate, &graph, &common, &javascript, &machine);
Major MajorKey() const override { return StringLength; };
Code::Kind GetCodeKind() const override { return Code::HANDLER; }
InlineCacheState GetICState() const override { return MONOMORPHIC; }
ExtraICState GetExtraICState() const override { return Code::LOAD_IC; }
Code::StubType GetStubType() const override { return Code::FAST; }
// FunctionTester (ab)uses a 2-argument function
Node* start = graph.NewNode(common.Start(2));
// Parameter 0 is the number to round
Node* numberParam = graph.NewNode(common.Parameter(1), start);
Unique<HeapObject> u = Unique<HeapObject>::CreateImmovable(code);
Node* theCode = graph.NewNode(common.HeapConstant(u));
Node* dummyContext = graph.NewNode(common.NumberConstant(0.0));
Node* call = graph.NewNode(common.Call(descriptor), theCode,
js.UndefinedConstant(), js.UndefinedConstant(),
numberParam, dummyContext, start, start);
Node* ret = graph.NewNode(common.Return(), call, call, start);
Node* end = graph.NewNode(common.End(), ret);
graph.SetStart(start);
graph.SetEnd(end);
FunctionTester ft(&graph);
private:
DISALLOW_COPY_AND_ASSIGN(StringLengthStubTF);
};
Handle<Object> value = ft.Val(1.5);
Handle<Object> result = ft.Call(value, value).ToHandleChecked();
CHECK_EQ(1, Smi::cast(*result)->value());
}
TEST(RunStringLengthStubTF) {
TEST(RunStringLengthTFStub) {
HandleAndZoneScope scope;
Isolate* isolate = scope.main_isolate();
Zone* zone = scope.main_zone();
// Create code and an accompanying descriptor.
StringLengthStubTF stub(isolate);
StringLengthTFStub stub(isolate);
Handle<Code> code = stub.GenerateCode();
CompilationInfo info(&stub, isolate, zone);
CallDescriptor* descriptor = Linkage::ComputeIncoming(zone, &info);
......
// Copyright 2015 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.
// Flags: --allow-natives-syntax --expose-natives-as=builtins --noalways-opt
const kExtraTypeFeedbackMinusZeroSentinel = 1;
const kFirstSlotExtraTypeFeedbackIndex = 5;
(function(){
var floorFunc = function() {
Math.floor(NaN);
}
// Execute the function once to make sure it has a type feedback vector.
floorFunc(5);
assertTrue(kExtraTypeFeedbackMinusZeroSentinel !==
%FixedArrayGet(%GetTypeFeedbackVector(floorFunc),
kFirstSlotExtraTypeFeedbackIndex));
assertEquals(5.0, builtins.MathFloor_STUB(floorFunc, 4, 5.5));
assertTrue(kExtraTypeFeedbackMinusZeroSentinel !==
%FixedArrayGet(%GetTypeFeedbackVector(floorFunc),
kFirstSlotExtraTypeFeedbackIndex));
// Executing floor such that it returns -0 should set the proper sentinel in
// the feedback vector.
assertEquals(-Infinity, 1/builtins.MathFloor_STUB(floorFunc, 4, -0));
assertEquals(kExtraTypeFeedbackMinusZeroSentinel,
%FixedArrayGet(%GetTypeFeedbackVector(floorFunc),
kFirstSlotExtraTypeFeedbackIndex));
%ClearFunctionTypeFeedback(floorFunc);
})();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment