Revert of Implement Fast Accessor Builder (patchset #14 id:260001 of https://codereview.chromium.org/1474543004/ )
Reason for revert: Broke the build, apparently. Original issue's description: > Implement FastAccessorBuilder. > > ... using the RawMachineAssembler and the work in cl/1407313004 > > BUG=chromium:508898 > LOG=Y > > Committed: https://crrev.com/515d9ccd8e6df7bf2ca01e2a55aaad30226399e1 > Cr-Commit-Position: refs/heads/master@{#32742} TBR=epertoso@chromium.org,bmeurer@chromium.org,jochen@chromium.org,mstarzinger@chromium.org,mvstanton@chromium.org NOPRESUBMIT=true NOTREECHECKS=true NOTRY=true BUG=chromium:508898 Review URL: https://codereview.chromium.org/1513203002 Cr-Commit-Position: refs/heads/master@{#32744}
This commit is contained in:
parent
ce47fc8b72
commit
0a50af8625
5
BUILD.gn
5
BUILD.gn
@ -596,7 +596,6 @@ source_set("v8_base") {
|
||||
|
||||
sources = [
|
||||
"include/v8-debug.h",
|
||||
"include/v8-experimental.h",
|
||||
"include/v8-platform.h",
|
||||
"include/v8-profiler.h",
|
||||
"include/v8-testing.h",
|
||||
@ -614,8 +613,6 @@ source_set("v8_base") {
|
||||
"src/allocation-site-scopes.h",
|
||||
"src/api.cc",
|
||||
"src/api.h",
|
||||
"src/api-experimental.cc",
|
||||
"src/api-experimental.h",
|
||||
"src/api-natives.cc",
|
||||
"src/api-natives.h",
|
||||
"src/arguments.cc",
|
||||
@ -727,8 +724,6 @@ source_set("v8_base") {
|
||||
"src/compiler/escape-analysis.h",
|
||||
"src/compiler/escape-analysis-reducer.cc",
|
||||
"src/compiler/escape-analysis-reducer.h",
|
||||
"src/compiler/fast-accessor-assembler.cc",
|
||||
"src/compiler/fast-accessor-assembler.h",
|
||||
"src/compiler/frame.cc",
|
||||
"src/compiler/frame.h",
|
||||
"src/compiler/frame-elider.cc",
|
||||
|
@ -1,53 +0,0 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* This header contains a set of experimental V8 APIs. We hope these will
|
||||
* become a part of standard V8, but they may also be removed if we deem the
|
||||
* experiment to not be successul.
|
||||
*/
|
||||
#ifndef V8_INCLUDE_V8_EXPERIMENTAL_H_
|
||||
#define V8_INCLUDE_V8_EXPERIMENTAL_H_
|
||||
|
||||
#include "include/v8.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace experimental {
|
||||
|
||||
// Allow the embedder to construct accessors that V8 can compile and use
|
||||
// directly, without jumping into the runtime.
|
||||
class V8_EXPORT FastAccessorBuilder {
|
||||
public:
|
||||
struct ValueId {
|
||||
size_t value_id;
|
||||
};
|
||||
struct LabelId {
|
||||
size_t label_id;
|
||||
};
|
||||
|
||||
static FastAccessorBuilder* New(Isolate* isolate);
|
||||
|
||||
ValueId IntegerConstant(int int_constant);
|
||||
ValueId GetReceiver();
|
||||
ValueId LoadInternalField(ValueId value_id, int field_no);
|
||||
ValueId LoadValue(ValueId value_id, int offset);
|
||||
ValueId LoadObject(ValueId value_id, int offset);
|
||||
void ReturnValue(ValueId value_id);
|
||||
void CheckFlagSetOrReturnNull(ValueId value_id, int mask);
|
||||
void CheckNotZeroOrReturnNull(ValueId value_id);
|
||||
LabelId MakeLabel();
|
||||
void SetLabel(LabelId label_id);
|
||||
void CheckNotZeroOrJump(ValueId value_id, LabelId label_id);
|
||||
|
||||
private:
|
||||
FastAccessorBuilder() = delete;
|
||||
FastAccessorBuilder(const FastAccessorBuilder&) = delete;
|
||||
~FastAccessorBuilder() = delete;
|
||||
void operator=(const FastAccessorBuilder&) = delete;
|
||||
};
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_INCLUDE_V8_EXPERIMENTAL_H_
|
13
include/v8.h
13
include/v8.h
@ -136,10 +136,6 @@ class CallHandlerHelper;
|
||||
class EscapableHandleScope;
|
||||
template<typename T> class ReturnValue;
|
||||
|
||||
namespace experimental {
|
||||
class FastAccessorBuilder;
|
||||
} // namespace experimental
|
||||
|
||||
namespace internal {
|
||||
class Arguments;
|
||||
class Heap;
|
||||
@ -4423,8 +4419,7 @@ class V8_EXPORT FunctionTemplate : public Template {
|
||||
* the callback cannot be null.
|
||||
*/
|
||||
static Local<FunctionTemplate> NewWithFastHandler(
|
||||
Isolate* isolate, FunctionCallback callback,
|
||||
experimental::FastAccessorBuilder* fast_handler = nullptr,
|
||||
Isolate* isolate, FunctionCallback callback, Local<Value> fast_handler,
|
||||
Local<Value> data = Local<Value>(),
|
||||
Local<Signature> signature = Local<Signature>(), int length = 0);
|
||||
|
||||
@ -4438,9 +4433,9 @@ class V8_EXPORT FunctionTemplate : public Template {
|
||||
* callback is called whenever the function created from this
|
||||
* FunctionTemplate is called.
|
||||
*/
|
||||
void SetCallHandler(
|
||||
FunctionCallback callback, Local<Value> data = Local<Value>(),
|
||||
experimental::FastAccessorBuilder* fast_handler = nullptr);
|
||||
void SetCallHandler(FunctionCallback callback,
|
||||
Local<Value> data = Local<Value>(),
|
||||
Local<Value> fast_handler = Local<Value>());
|
||||
|
||||
/** Set the predefined length property for the FunctionTemplate. */
|
||||
void SetLength(int length);
|
||||
|
3
src/DEPS
3
src/DEPS
@ -25,7 +25,4 @@ specific_include_rules = {
|
||||
"d8\.cc": [
|
||||
"+include/libplatform/libplatform.h",
|
||||
],
|
||||
"api-experimental\.cc": [
|
||||
"+src/compiler/fast-accessor-assembler.h",
|
||||
],
|
||||
}
|
||||
|
@ -1,126 +0,0 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
/**
|
||||
* Implementation for v8-experimental.h.
|
||||
*/
|
||||
|
||||
#include "src/api-experimental.h"
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "include/v8-experimental.h"
|
||||
#include "src/api.h"
|
||||
#include "src/compiler/fast-accessor-assembler.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
v8::internal::compiler::FastAccessorAssembler* FromApi(
|
||||
v8::experimental::FastAccessorBuilder* builder) {
|
||||
return reinterpret_cast<v8::internal::compiler::FastAccessorAssembler*>(
|
||||
builder);
|
||||
}
|
||||
|
||||
|
||||
v8::experimental::FastAccessorBuilder* FromInternal(
|
||||
v8::internal::compiler::FastAccessorAssembler* fast_accessor_assembler) {
|
||||
return reinterpret_cast<v8::experimental::FastAccessorBuilder*>(
|
||||
fast_accessor_assembler);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace experimental {
|
||||
|
||||
|
||||
MaybeHandle<Code> BuildCodeFromFastAccessorBuilder(
|
||||
v8::experimental::FastAccessorBuilder* fast_handler) {
|
||||
i::MaybeHandle<i::Code> code;
|
||||
if (fast_handler != nullptr) {
|
||||
auto faa = FromApi(fast_handler);
|
||||
code = faa->Build();
|
||||
CHECK(!code.is_null());
|
||||
delete faa;
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace internal
|
||||
|
||||
|
||||
namespace experimental {
|
||||
|
||||
|
||||
FastAccessorBuilder* FastAccessorBuilder::New(Isolate* isolate) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
internal::compiler::FastAccessorAssembler* faa =
|
||||
new internal::compiler::FastAccessorAssembler(i_isolate);
|
||||
return FromInternal(faa);
|
||||
}
|
||||
|
||||
|
||||
FastAccessorBuilder::ValueId FastAccessorBuilder::IntegerConstant(
|
||||
int const_value) {
|
||||
return FromApi(this)->IntegerConstant(const_value);
|
||||
}
|
||||
|
||||
|
||||
FastAccessorBuilder::ValueId FastAccessorBuilder::GetReceiver() {
|
||||
return FromApi(this)->GetReceiver();
|
||||
}
|
||||
|
||||
|
||||
FastAccessorBuilder::ValueId FastAccessorBuilder::LoadInternalField(
|
||||
ValueId value, int field_no) {
|
||||
return FromApi(this)->LoadInternalField(value, field_no);
|
||||
}
|
||||
|
||||
|
||||
FastAccessorBuilder::ValueId FastAccessorBuilder::LoadValue(ValueId value_id,
|
||||
int offset) {
|
||||
return FromApi(this)->LoadValue(value_id, offset);
|
||||
}
|
||||
|
||||
|
||||
FastAccessorBuilder::ValueId FastAccessorBuilder::LoadObject(ValueId value_id,
|
||||
int offset) {
|
||||
return FromApi(this)->LoadObject(value_id, offset);
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorBuilder::ReturnValue(ValueId value) {
|
||||
FromApi(this)->ReturnValue(value);
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorBuilder::CheckFlagSetOrReturnNull(ValueId value_id, int mask) {
|
||||
FromApi(this)->CheckFlagSetOrReturnNull(value_id, mask);
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorBuilder::CheckNotZeroOrReturnNull(ValueId value_id) {
|
||||
FromApi(this)->CheckNotZeroOrReturnNull(value_id);
|
||||
}
|
||||
|
||||
|
||||
FastAccessorBuilder::LabelId FastAccessorBuilder::MakeLabel() {
|
||||
return FromApi(this)->MakeLabel();
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorBuilder::SetLabel(LabelId label_id) {
|
||||
FromApi(this)->SetLabel(label_id);
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorBuilder::CheckNotZeroOrJump(ValueId value_id,
|
||||
LabelId label_id) {
|
||||
FromApi(this)->CheckNotZeroOrJump(value_id, label_id);
|
||||
}
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace v8
|
@ -1,28 +0,0 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_API_EXPERIMENTAL_H_
|
||||
#define V8_API_EXPERIMENTAL_H_
|
||||
|
||||
#include "src/handles.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
class Code;
|
||||
} // internal;
|
||||
namespace experimental {
|
||||
class FastAccessorBuilder;
|
||||
} // experimental
|
||||
|
||||
namespace internal {
|
||||
namespace experimental {
|
||||
|
||||
v8::internal::MaybeHandle<v8::internal::Code> BuildCodeFromFastAccessorBuilder(
|
||||
v8::experimental::FastAccessorBuilder* fast_handler);
|
||||
|
||||
} // namespace experimental
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_API_EXPERIMENTAL_H_
|
29
src/api.cc
29
src/api.cc
@ -12,10 +12,8 @@
|
||||
#include <limits>
|
||||
#include <vector>
|
||||
#include "include/v8-debug.h"
|
||||
#include "include/v8-experimental.h"
|
||||
#include "include/v8-profiler.h"
|
||||
#include "include/v8-testing.h"
|
||||
#include "src/api-experimental.h"
|
||||
#include "src/api-natives.h"
|
||||
#include "src/assert-scope.h"
|
||||
#include "src/background-parsing-task.h"
|
||||
@ -1001,7 +999,7 @@ void FunctionTemplate::Inherit(v8::Local<FunctionTemplate> value) {
|
||||
|
||||
static Local<FunctionTemplate> FunctionTemplateNew(
|
||||
i::Isolate* isolate, FunctionCallback callback,
|
||||
experimental::FastAccessorBuilder* fast_handler, v8::Local<Value> data,
|
||||
v8::Local<Value> fast_handler, v8::Local<Value> data,
|
||||
v8::Local<Signature> signature, int length, bool do_not_cache) {
|
||||
i::Handle<i::Struct> struct_obj =
|
||||
isolate->factory()->NewStruct(i::FUNCTION_TEMPLATE_INFO_TYPE);
|
||||
@ -1042,15 +1040,14 @@ Local<FunctionTemplate> FunctionTemplate::New(Isolate* isolate,
|
||||
DCHECK(!i_isolate->serializer_enabled());
|
||||
LOG_API(i_isolate, "FunctionTemplate::New");
|
||||
ENTER_V8(i_isolate);
|
||||
return FunctionTemplateNew(i_isolate, callback, nullptr, data, signature,
|
||||
length, false);
|
||||
return FunctionTemplateNew(i_isolate, callback, v8::Local<Value>(), data,
|
||||
signature, length, false);
|
||||
}
|
||||
|
||||
|
||||
Local<FunctionTemplate> FunctionTemplate::NewWithFastHandler(
|
||||
Isolate* isolate, FunctionCallback callback,
|
||||
experimental::FastAccessorBuilder* fast_handler, v8::Local<Value> data,
|
||||
v8::Local<Signature> signature, int length) {
|
||||
Isolate* isolate, FunctionCallback callback, v8::Local<Value> fast_handler,
|
||||
v8::Local<Value> data, v8::Local<Signature> signature, int length) {
|
||||
// TODO(vogelheim): 'fast_handler' should have a more specific type than
|
||||
// Local<Value>.
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
@ -1080,9 +1077,9 @@ Local<AccessorSignature> AccessorSignature::New(
|
||||
} while (false)
|
||||
|
||||
|
||||
void FunctionTemplate::SetCallHandler(
|
||||
FunctionCallback callback, v8::Local<Value> data,
|
||||
experimental::FastAccessorBuilder* fast_handler) {
|
||||
void FunctionTemplate::SetCallHandler(FunctionCallback callback,
|
||||
v8::Local<Value> data,
|
||||
v8::Local<Value> fast_handler) {
|
||||
auto info = Utils::OpenHandle(this);
|
||||
EnsureNotInstantiated(info, "v8::FunctionTemplate::SetCallHandler");
|
||||
i::Isolate* isolate = info->GetIsolate();
|
||||
@ -1093,10 +1090,10 @@ void FunctionTemplate::SetCallHandler(
|
||||
i::Handle<i::CallHandlerInfo> obj =
|
||||
i::Handle<i::CallHandlerInfo>::cast(struct_obj);
|
||||
SET_FIELD_WRAPPED(obj, set_callback, callback);
|
||||
i::MaybeHandle<i::Code> code =
|
||||
i::experimental::BuildCodeFromFastAccessorBuilder(fast_handler);
|
||||
if (!code.is_null()) {
|
||||
obj->set_fast_handler(*code.ToHandleChecked());
|
||||
if (!fast_handler.IsEmpty()) {
|
||||
i::Handle<i::Object> code = Utils::OpenHandle(*fast_handler);
|
||||
CHECK(code->IsCode());
|
||||
obj->set_fast_handler(*code);
|
||||
}
|
||||
if (data.IsEmpty()) {
|
||||
data = v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
|
||||
@ -4371,7 +4368,7 @@ MaybeLocal<Function> Function::New(Local<Context> context,
|
||||
i::Isolate* isolate = Utils::OpenHandle(*context)->GetIsolate();
|
||||
LOG_API(isolate, "Function::New");
|
||||
ENTER_V8(isolate);
|
||||
return FunctionTemplateNew(isolate, callback, nullptr, data,
|
||||
return FunctionTemplateNew(isolate, callback, Local<Value>(), data,
|
||||
Local<Signature>(), length, true)
|
||||
->GetFunction(context);
|
||||
}
|
||||
|
@ -1,221 +0,0 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "src/compiler/fast-accessor-assembler.h"
|
||||
|
||||
#include "src/base/logging.h"
|
||||
#include "src/compiler/graph.h"
|
||||
#include "src/compiler/linkage.h"
|
||||
#include "src/compiler/pipeline.h"
|
||||
#include "src/compiler/raw-machine-assembler.h"
|
||||
#include "src/compiler/schedule.h"
|
||||
#include "src/compiler/verifier.h"
|
||||
#include "src/handles-inl.h"
|
||||
#include "src/objects.h" // For FAA::GetInternalField impl.
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
namespace compiler {
|
||||
|
||||
FastAccessorAssembler::FastAccessorAssembler(Isolate* isolate)
|
||||
: zone_(),
|
||||
assembler_(new RawMachineAssembler(
|
||||
isolate, new (zone()) Graph(zone()),
|
||||
Linkage::GetJSCallDescriptor(&zone_, false, 1,
|
||||
CallDescriptor::kNoFlags))),
|
||||
state_(kBuilding) {}
|
||||
|
||||
|
||||
FastAccessorAssembler::~FastAccessorAssembler() {}
|
||||
|
||||
|
||||
FastAccessorAssembler::ValueId FastAccessorAssembler::IntegerConstant(
|
||||
int const_value) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
return FromRaw(assembler_->NumberConstant(const_value));
|
||||
}
|
||||
|
||||
|
||||
FastAccessorAssembler::ValueId FastAccessorAssembler::GetReceiver() {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
|
||||
// For JS call descriptor, the receiver is parameter 0. If we use other
|
||||
// call descriptors, this may or may not hold. So let's check.
|
||||
CHECK(assembler_->call_descriptor()->IsJSFunctionCall());
|
||||
return FromRaw(assembler_->Parameter(0));
|
||||
}
|
||||
|
||||
|
||||
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadInternalField(
|
||||
ValueId value, int field_no) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
// Determine the 'value' object's instance type.
|
||||
Node* object_map =
|
||||
assembler_->Load(kMachPtr, FromId(value),
|
||||
assembler_->IntPtrConstant(
|
||||
Internals::kHeapObjectMapOffset - kHeapObjectTag));
|
||||
Node* instance_type = assembler_->WordAnd(
|
||||
assembler_->Load(
|
||||
kMachUint16, object_map,
|
||||
assembler_->IntPtrConstant(
|
||||
Internals::kMapInstanceTypeAndBitFieldOffset - kHeapObjectTag)),
|
||||
assembler_->IntPtrConstant(0xff));
|
||||
|
||||
// Check whether we have a proper JSObject.
|
||||
RawMachineLabel is_jsobject, is_not_jsobject, merge;
|
||||
assembler_->Branch(
|
||||
assembler_->WordEqual(
|
||||
instance_type, assembler_->IntPtrConstant(Internals::kJSObjectType)),
|
||||
&is_jsobject, &is_not_jsobject);
|
||||
|
||||
// JSObject? Then load the internal field field_no.
|
||||
assembler_->Bind(&is_jsobject);
|
||||
Node* internal_field = assembler_->Load(
|
||||
kMachPtr, FromId(value),
|
||||
assembler_->IntPtrConstant(JSObject::kHeaderSize - kHeapObjectTag +
|
||||
kPointerSize * field_no));
|
||||
assembler_->Goto(&merge);
|
||||
|
||||
// No JSObject? Return undefined.
|
||||
// TODO(vogelheim): Check whether this is the appropriate action, or whether
|
||||
// the method should take a label instead.
|
||||
assembler_->Bind(&is_not_jsobject);
|
||||
Node* fail_value = assembler_->UndefinedConstant();
|
||||
assembler_->Goto(&merge);
|
||||
|
||||
// Return.
|
||||
assembler_->Bind(&merge);
|
||||
Node* phi = assembler_->Phi(kMachAnyTagged, internal_field, fail_value);
|
||||
return FromRaw(phi);
|
||||
}
|
||||
|
||||
|
||||
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadValue(ValueId value,
|
||||
int offset) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
return FromRaw(assembler_->Load(kMachIntPtr, FromId(value),
|
||||
assembler_->IntPtrConstant(offset)));
|
||||
}
|
||||
|
||||
|
||||
FastAccessorAssembler::ValueId FastAccessorAssembler::LoadObject(ValueId value,
|
||||
int offset) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
return FromRaw(assembler_->Load(
|
||||
kMachAnyTagged, assembler_->Load(kMachPtr, FromId(value),
|
||||
assembler_->IntPtrConstant(offset))));
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorAssembler::ReturnValue(ValueId value) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
assembler_->Return(FromId(value));
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorAssembler::CheckFlagSetOrReturnNull(ValueId value, int mask) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
RawMachineLabel pass, fail;
|
||||
assembler_->Branch(
|
||||
assembler_->Word32Equal(
|
||||
assembler_->Word32And(FromId(value), assembler_->Int32Constant(mask)),
|
||||
assembler_->Int32Constant(0)),
|
||||
&pass, &fail);
|
||||
assembler_->Bind(&fail);
|
||||
assembler_->Return(assembler_->NullConstant());
|
||||
assembler_->Bind(&pass);
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorAssembler::CheckNotZeroOrReturnNull(ValueId value) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
RawMachineLabel is_null, not_null;
|
||||
assembler_->Branch(
|
||||
assembler_->IntPtrEqual(FromId(value), assembler_->IntPtrConstant(0)),
|
||||
&is_null, ¬_null);
|
||||
assembler_->Bind(&is_null);
|
||||
assembler_->Return(assembler_->NullConstant());
|
||||
assembler_->Bind(¬_null);
|
||||
}
|
||||
|
||||
|
||||
FastAccessorAssembler::LabelId FastAccessorAssembler::MakeLabel() {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
RawMachineLabel* label =
|
||||
new (zone()->New(sizeof(RawMachineLabel))) RawMachineLabel;
|
||||
return FromRaw(label);
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorAssembler::SetLabel(LabelId label_id) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
assembler_->Bind(FromId(label_id));
|
||||
}
|
||||
|
||||
|
||||
void FastAccessorAssembler::CheckNotZeroOrJump(ValueId value_id,
|
||||
LabelId label_id) {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
RawMachineLabel pass;
|
||||
assembler_->Branch(
|
||||
assembler_->IntPtrEqual(FromId(value_id), assembler_->IntPtrConstant(0)),
|
||||
&pass, FromId(label_id));
|
||||
assembler_->Bind(&pass);
|
||||
}
|
||||
|
||||
|
||||
MaybeHandle<Code> FastAccessorAssembler::Build() {
|
||||
CHECK_EQ(kBuilding, state_);
|
||||
|
||||
// Cleanup: We no longer need this.
|
||||
nodes_.clear();
|
||||
labels_.clear();
|
||||
|
||||
// Export the schedule and call the compiler.
|
||||
CompilationInfo info("FastAccessorAssembler", assembler_->isolate(), zone());
|
||||
Schedule* schedule = assembler_->Export();
|
||||
|
||||
// TODO(vogelheim): Pipeline should have a dedicated entry point for this
|
||||
// assembler.
|
||||
MaybeHandle<Code> code = Pipeline::GenerateCodeForTesting(
|
||||
&info, assembler_->call_descriptor(), assembler_->graph(), schedule);
|
||||
|
||||
// Update state & return.
|
||||
state_ = !code.is_null() ? kBuilt : kError;
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
FastAccessorAssembler::ValueId FastAccessorAssembler::FromRaw(Node* node) {
|
||||
nodes_.push_back(node);
|
||||
ValueId value = {nodes_.size() - 1};
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
FastAccessorAssembler::LabelId FastAccessorAssembler::FromRaw(
|
||||
RawMachineLabel* label) {
|
||||
labels_.push_back(label);
|
||||
LabelId label_id = {labels_.size() - 1};
|
||||
return label_id;
|
||||
}
|
||||
|
||||
|
||||
Node* FastAccessorAssembler::FromId(ValueId value) const {
|
||||
CHECK_LT(value.value_id, nodes_.size());
|
||||
CHECK_NOT_NULL(nodes_.at(value.value_id));
|
||||
return nodes_.at(value.value_id);
|
||||
}
|
||||
|
||||
|
||||
RawMachineLabel* FastAccessorAssembler::FromId(LabelId label) const {
|
||||
CHECK_LT(label.label_id, labels_.size());
|
||||
CHECK_NOT_NULL(labels_.at(label.label_id));
|
||||
return labels_.at(label.label_id);
|
||||
}
|
||||
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
@ -1,106 +0,0 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef V8_COMPILER_FAST_ACCESSOR_ASSEMBLER_H_
|
||||
#define V8_COMPILER_FAST_ACCESSOR_ASSEMBLER_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
// Clients of this interface shouldn't depend on lots of compiler internals.
|
||||
// Do not include anything from src/compiler here!
|
||||
#include "include/v8-experimental.h"
|
||||
#include "src/base/macros.h"
|
||||
#include "src/base/smart-pointers.h"
|
||||
#include "src/handles.h"
|
||||
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
class Code;
|
||||
class Isolate;
|
||||
class Zone;
|
||||
|
||||
namespace compiler {
|
||||
|
||||
class Node;
|
||||
class RawMachineAssembler;
|
||||
class RawMachineLabel;
|
||||
|
||||
|
||||
// This interface "exports" an aggregated subset of RawMachineAssembler, for
|
||||
// use by the API to implement Fast Dom Accessors.
|
||||
//
|
||||
// This interface is made for this single purpose only and does not attempt
|
||||
// to implement a general purpose solution. If you need one, please look at
|
||||
// RawMachineAssembler instead.
|
||||
//
|
||||
// The life cycle of a FastAccessorAssembler has two phases:
|
||||
// - After creating the instance, you can call an arbitrary sequence of
|
||||
// builder functions to build the desired function.
|
||||
// - When done, you can Build() the accessor and query for the build results.
|
||||
//
|
||||
// You cannot call any result getters before Build() was called & successful;
|
||||
// and you cannot call any builder functions after Build() was called.
|
||||
class FastAccessorAssembler {
|
||||
public:
|
||||
typedef v8::experimental::FastAccessorBuilder::ValueId ValueId;
|
||||
typedef v8::experimental::FastAccessorBuilder::LabelId LabelId;
|
||||
|
||||
explicit FastAccessorAssembler(Isolate* isolate);
|
||||
~FastAccessorAssembler();
|
||||
|
||||
// Builder / assembler functions:
|
||||
ValueId IntegerConstant(int int_constant);
|
||||
ValueId GetReceiver();
|
||||
ValueId LoadInternalField(ValueId value_id, int field_no);
|
||||
ValueId LoadValue(ValueId value_id, int offset);
|
||||
ValueId LoadObject(ValueId value_id, int offset);
|
||||
|
||||
// Builder / assembler functions for control flow.
|
||||
void ReturnValue(ValueId value_id);
|
||||
void CheckFlagSetOrReturnNull(ValueId value_id, int mask);
|
||||
void CheckNotZeroOrReturnNull(ValueId value_id);
|
||||
|
||||
// TODO(vogelheim): Implement a C++ callback.
|
||||
// void CheckNotNullOrCallback(ValueId value_id, ..c++-callback type...,
|
||||
// ValueId arg1, ValueId arg2, ...);
|
||||
|
||||
LabelId MakeLabel();
|
||||
void SetLabel(LabelId label_id);
|
||||
void CheckNotZeroOrJump(ValueId value_id, LabelId label_id);
|
||||
|
||||
// Assemble the code.
|
||||
MaybeHandle<Code> Build();
|
||||
|
||||
private:
|
||||
ValueId FromRaw(Node* node);
|
||||
LabelId FromRaw(RawMachineLabel* label);
|
||||
Node* FromId(ValueId value) const;
|
||||
RawMachineLabel* FromId(LabelId value) const;
|
||||
|
||||
Zone* zone() { return &zone_; }
|
||||
|
||||
Zone zone_;
|
||||
base::SmartPointer<RawMachineAssembler> assembler_;
|
||||
|
||||
// To prevent exposing the RMA internals to the outside world, we'll map
|
||||
// Node + Label pointers integers wrapped in ValueId and LabelId instances.
|
||||
// These vectors maintain this mapping.
|
||||
std::vector<Node*> nodes_;
|
||||
std::vector<RawMachineLabel*> labels_;
|
||||
|
||||
// Remember the current state for easy error checking. (We prefer to be
|
||||
// strict as this class will be exposed at the API.)
|
||||
enum { kBuilding, kBuilt, kError } state_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(FastAccessorAssembler);
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace internal
|
||||
} // namespace v8
|
||||
|
||||
#endif // V8_COMPILER_FAST_ACCESSOR_ASSEMBLER_H_
|
@ -110,7 +110,6 @@
|
||||
# checked in.
|
||||
# 'test-api-accessors.cc',
|
||||
'test-api-interceptors.cc',
|
||||
'test-api-fast-accessor-builder.cc',
|
||||
'test-array-list.cc',
|
||||
'test-ast.cc',
|
||||
'test-ast-expression-visitor.cc',
|
||||
|
@ -550,12 +550,6 @@ static inline void ExpectUndefined(const char* code) {
|
||||
}
|
||||
|
||||
|
||||
static inline void ExpectNull(const char* code) {
|
||||
v8::Local<v8::Value> result = CompileRun(code);
|
||||
CHECK(result->IsNull());
|
||||
}
|
||||
|
||||
|
||||
static inline void CheckDoubleEquals(double expected, double actual) {
|
||||
const double kEpsilon = 1e-10;
|
||||
CHECK_LE(expected, actual + kEpsilon);
|
||||
|
@ -1,274 +0,0 @@
|
||||
// Copyright 2015 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "include/v8.h"
|
||||
#include "include/v8-experimental.h"
|
||||
|
||||
#include "src/api.h"
|
||||
#include "test/cctest/cctest.h"
|
||||
|
||||
namespace {
|
||||
|
||||
// These tests mean to exercise v8::FastAccessorBuilder. Since initially the
|
||||
// "native" accessor will get called, we need to 'warmup' any accessor first,
|
||||
// to make sure we're actually testing the v8::FastAccessorBuilder result.
|
||||
// To accomplish this, we will
|
||||
// - call each accesssor N times before the actual test.
|
||||
// - wrap that call in a function, so that all such calls will go
|
||||
// through a single call site.
|
||||
// - register a native accessor which is different from the build one
|
||||
// (so that our tests will always fail if we don't end up in the 'fast'
|
||||
// accessor)
|
||||
//
|
||||
// This doesn't work if the src function is inlined - as it is when
|
||||
// --always-opt is enabled - since then every inlined functino is its own
|
||||
// callsite. Hence most test will check for i::FLAG_always_opt.
|
||||
#define WARMUP(src) "for(i = 0; i < 2; i++) { " src " } "
|
||||
|
||||
static void NativePropertyAccessor(
|
||||
const v8::FunctionCallbackInfo<v8::Value>& info) {
|
||||
info.GetReturnValue().Set(v8_num(123));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
// Build a simple "fast accessor" and verify that it is being called.
|
||||
TEST(FastAccessor) {
|
||||
if (i::FLAG_always_opt || i::FLAG_optimize_for_size) return;
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
v8::Local<v8::FunctionTemplate> foo = v8::FunctionTemplate::New(isolate);
|
||||
|
||||
// Native accessor, bar, returns 123.
|
||||
foo->PrototypeTemplate()->SetAccessorProperty(
|
||||
v8_str("bar"),
|
||||
v8::FunctionTemplate::New(isolate, NativePropertyAccessor));
|
||||
|
||||
// Fast accessor, barf, returns 124.
|
||||
auto fab = v8::experimental::FastAccessorBuilder::New(isolate);
|
||||
fab->ReturnValue(fab->IntegerConstant(124));
|
||||
foo->PrototypeTemplate()->SetAccessorProperty(
|
||||
v8_str("barf"), v8::FunctionTemplate::NewWithFastHandler(
|
||||
isolate, NativePropertyAccessor, fab));
|
||||
|
||||
// Install foo on the global object.
|
||||
CHECK(env->Global()
|
||||
->Set(env.local(), v8_str("foo"),
|
||||
foo->GetFunction(env.local()).ToLocalChecked())
|
||||
.FromJust());
|
||||
|
||||
// Wrap f.barf + IC warmup.
|
||||
CompileRun(
|
||||
"function barf() { f = new foo(); return f.barf }; " WARMUP("barf()"));
|
||||
|
||||
ExpectInt32("f = new foo(); f.bar", 123);
|
||||
ExpectInt32("f = new foo(); f.barf", 123); // First call in this call site.
|
||||
ExpectInt32("barf()", 124); // Call via warmed-up callsite.
|
||||
}
|
||||
|
||||
|
||||
void AddInternalFieldAccessor(v8::Isolate* isolate,
|
||||
v8::Local<v8::Template> templ, const char* name,
|
||||
int field_no) {
|
||||
auto builder = v8::experimental::FastAccessorBuilder::New(isolate);
|
||||
builder->ReturnValue(
|
||||
builder->LoadInternalField(builder->GetReceiver(), field_no));
|
||||
templ->SetAccessorProperty(v8_str(name),
|
||||
v8::FunctionTemplate::NewWithFastHandler(
|
||||
isolate, NativePropertyAccessor, builder));
|
||||
}
|
||||
|
||||
|
||||
// "Fast" accessor that accesses an internal field.
|
||||
TEST(FastAccessorWithInternalField) {
|
||||
if (i::FLAG_always_opt || i::FLAG_optimize_for_size) return;
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
v8::Local<v8::ObjectTemplate> foo = v8::ObjectTemplate::New(isolate);
|
||||
foo->SetInternalFieldCount(3);
|
||||
AddInternalFieldAccessor(isolate, foo, "field0", 0);
|
||||
AddInternalFieldAccessor(isolate, foo, "field1", 1);
|
||||
AddInternalFieldAccessor(isolate, foo, "field2", 2);
|
||||
|
||||
// Create an instance w/ 3 internal fields, put in a string, a Smi, nothing.
|
||||
v8::Local<v8::Object> obj = foo->NewInstance(env.local()).ToLocalChecked();
|
||||
obj->SetInternalField(0, v8_str("Hi there!"));
|
||||
obj->SetInternalField(1, v8::Integer::New(isolate, 4321));
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
|
||||
|
||||
// Warmup.
|
||||
CompileRun("function field0() { return obj.field0 }; " WARMUP("field0()"));
|
||||
CompileRun("function field1() { return obj.field1 }; " WARMUP("field1()"));
|
||||
CompileRun("function field2() { return obj.field2 }; " WARMUP("field2()"));
|
||||
|
||||
// Access fields.
|
||||
ExpectString("field0()", "Hi there!");
|
||||
ExpectInt32("field1()", 4321);
|
||||
ExpectUndefined("field2()");
|
||||
}
|
||||
|
||||
|
||||
// "Fast" accessor with control flow via ...OrReturnNull methods.
|
||||
TEST(FastAccessorOrReturnNull) {
|
||||
if (i::FLAG_always_opt || i::FLAG_optimize_for_size) return;
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
v8::Local<v8::ObjectTemplate> foo = v8::ObjectTemplate::New(isolate);
|
||||
foo->SetInternalFieldCount(2);
|
||||
{
|
||||
// accessor "nullcheck": Return null if field 0 is non-null object; else 5.
|
||||
auto builder = v8::experimental::FastAccessorBuilder::New(isolate);
|
||||
auto val = builder->LoadInternalField(builder->GetReceiver(), 0);
|
||||
builder->CheckNotZeroOrReturnNull(val);
|
||||
builder->ReturnValue(builder->IntegerConstant(5));
|
||||
foo->SetAccessorProperty(v8_str("nullcheck"),
|
||||
v8::FunctionTemplate::NewWithFastHandler(
|
||||
isolate, NativePropertyAccessor, builder));
|
||||
}
|
||||
{
|
||||
// accessor "maskcheck": Return null if field 1 has 3rd bit set.
|
||||
auto builder = v8::experimental::FastAccessorBuilder::New(isolate);
|
||||
auto val = builder->LoadInternalField(builder->GetReceiver(), 1);
|
||||
builder->CheckFlagSetOrReturnNull(val, 0x4);
|
||||
builder->ReturnValue(builder->IntegerConstant(42));
|
||||
foo->SetAccessorProperty(v8_str("maskcheck"),
|
||||
v8::FunctionTemplate::NewWithFastHandler(
|
||||
isolate, NativePropertyAccessor, builder));
|
||||
}
|
||||
|
||||
// Create an instance.
|
||||
v8::Local<v8::Object> obj = foo->NewInstance(env.local()).ToLocalChecked();
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
|
||||
|
||||
// CheckNotZeroOrReturnNull:
|
||||
CompileRun(
|
||||
"function nullcheck() { return obj.nullcheck }; " WARMUP("nullcheck()"));
|
||||
obj->SetAlignedPointerInInternalField(0, /* anything != nullptr */ isolate);
|
||||
ExpectInt32("nullcheck()", 5);
|
||||
obj->SetAlignedPointerInInternalField(0, nullptr);
|
||||
ExpectNull("nullcheck()");
|
||||
|
||||
// CheckFlagSetOrReturnNull:
|
||||
CompileRun(
|
||||
"function maskcheck() { return obj.maskcheck }; " WARMUP("maskcheck()"));
|
||||
obj->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0xf0));
|
||||
ExpectInt32("maskcheck()", 42);
|
||||
obj->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0xfe));
|
||||
ExpectNull("maskcheck()");
|
||||
}
|
||||
|
||||
|
||||
// "Fast" accessor with simple control flow via explicit labels.
|
||||
TEST(FastAccessorControlFlowWithLabels) {
|
||||
if (i::FLAG_always_opt || i::FLAG_optimize_for_size) return;
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
v8::Local<v8::ObjectTemplate> foo = v8::ObjectTemplate::New(isolate);
|
||||
foo->SetInternalFieldCount(1);
|
||||
{
|
||||
// accessor isnull: 0 for nullptr, else 1.
|
||||
auto builder = v8::experimental::FastAccessorBuilder::New(isolate);
|
||||
auto label = builder->MakeLabel();
|
||||
auto val = builder->LoadInternalField(builder->GetReceiver(), 0);
|
||||
builder->CheckNotZeroOrJump(val, label);
|
||||
builder->ReturnValue(builder->IntegerConstant(0));
|
||||
builder->SetLabel(label);
|
||||
builder->ReturnValue(builder->IntegerConstant(1));
|
||||
foo->SetAccessorProperty(v8_str("isnull"),
|
||||
v8::FunctionTemplate::NewWithFastHandler(
|
||||
isolate, NativePropertyAccessor, builder));
|
||||
}
|
||||
|
||||
// Create an instance.
|
||||
v8::Local<v8::Object> obj = foo->NewInstance(env.local()).ToLocalChecked();
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
|
||||
|
||||
// CheckNotZeroOrReturnNull:
|
||||
CompileRun("function isnull() { return obj.isnull }; " WARMUP("isnull()"));
|
||||
obj->SetAlignedPointerInInternalField(0, /* anything != nullptr */ isolate);
|
||||
ExpectInt32("isnull()", 1);
|
||||
obj->SetAlignedPointerInInternalField(0, nullptr);
|
||||
ExpectInt32("isnull()", 0);
|
||||
}
|
||||
|
||||
|
||||
// "Fast" accessor, loading things.
|
||||
TEST(FastAccessorLoad) {
|
||||
if (i::FLAG_always_opt || i::FLAG_optimize_for_size) return;
|
||||
|
||||
LocalContext env;
|
||||
v8::Isolate* isolate = env->GetIsolate();
|
||||
v8::HandleScope scope(isolate);
|
||||
|
||||
v8::Local<v8::ObjectTemplate> foo = v8::ObjectTemplate::New(isolate);
|
||||
foo->SetInternalFieldCount(1);
|
||||
|
||||
// Internal field 0 is a pointer to a C++ data structure that we wish to load
|
||||
// field values from.
|
||||
struct {
|
||||
size_t intval;
|
||||
v8::Local<v8::String> v8val;
|
||||
} val = {54321, v8_str("Hello")};
|
||||
|
||||
{
|
||||
// accessor intisnonzero
|
||||
int intval_offset =
|
||||
static_cast<int>(reinterpret_cast<intptr_t>(&val.intval) -
|
||||
reinterpret_cast<intptr_t>(&val));
|
||||
auto builder = v8::experimental::FastAccessorBuilder::New(isolate);
|
||||
auto label = builder->MakeLabel();
|
||||
auto val = builder->LoadValue(
|
||||
builder->LoadInternalField(builder->GetReceiver(), 0), intval_offset);
|
||||
builder->CheckNotZeroOrJump(val, label);
|
||||
builder->ReturnValue(builder->IntegerConstant(0));
|
||||
builder->SetLabel(label);
|
||||
builder->ReturnValue(builder->IntegerConstant(1));
|
||||
foo->SetAccessorProperty(v8_str("nonzero"),
|
||||
v8::FunctionTemplate::NewWithFastHandler(
|
||||
isolate, NativePropertyAccessor, builder));
|
||||
}
|
||||
{
|
||||
// accessor loadval
|
||||
int v8val_offset = static_cast<int>(reinterpret_cast<intptr_t>(&val.v8val) -
|
||||
reinterpret_cast<intptr_t>(&val));
|
||||
auto builder = v8::experimental::FastAccessorBuilder::New(isolate);
|
||||
builder->ReturnValue(builder->LoadObject(
|
||||
builder->LoadInternalField(builder->GetReceiver(), 0), v8val_offset));
|
||||
foo->SetAccessorProperty(v8_str("loadval"),
|
||||
v8::FunctionTemplate::NewWithFastHandler(
|
||||
isolate, NativePropertyAccessor, builder));
|
||||
}
|
||||
|
||||
// Create an instance.
|
||||
v8::Local<v8::Object> obj = foo->NewInstance(env.local()).ToLocalChecked();
|
||||
obj->SetAlignedPointerInInternalField(0, &val);
|
||||
CHECK(env->Global()->Set(env.local(), v8_str("obj"), obj).FromJust());
|
||||
|
||||
// Access val.intval:
|
||||
CompileRun("function nonzero() { return obj.nonzero }; " WARMUP("nonzero()"));
|
||||
ExpectInt32("nonzero()", 1);
|
||||
val.intval = 0;
|
||||
ExpectInt32("nonzero()", 0);
|
||||
val.intval = 27;
|
||||
ExpectInt32("nonzero()", 1);
|
||||
|
||||
// Access val.v8val:
|
||||
CompileRun("function loadval() { return obj.loadval }; " WARMUP("loadval()"));
|
||||
ExpectString("loadval()", "Hello");
|
||||
}
|
@ -374,7 +374,6 @@
|
||||
],
|
||||
'sources': [ ### gcmole(all) ###
|
||||
'../../include/v8-debug.h',
|
||||
'../../include/v8-experimental.h',
|
||||
'../../include/v8-platform.h',
|
||||
'../../include/v8-profiler.h',
|
||||
'../../include/v8-testing.h',
|
||||
@ -390,8 +389,6 @@
|
||||
'../../src/allocation.h',
|
||||
'../../src/allocation-site-scopes.cc',
|
||||
'../../src/allocation-site-scopes.h',
|
||||
'../../src/api-experimental.cc',
|
||||
'../../src/api-experimental.h',
|
||||
'../../src/api.cc',
|
||||
'../../src/api.h',
|
||||
'../../src/api-natives.cc',
|
||||
@ -505,8 +502,6 @@
|
||||
'../../src/compiler/escape-analysis.h',
|
||||
"../../src/compiler/escape-analysis-reducer.cc",
|
||||
"../../src/compiler/escape-analysis-reducer.h",
|
||||
'../../src/compiler/fast-accessor-assembler.cc',
|
||||
'../../src/compiler/fast-accessor-assembler.h',
|
||||
'../../src/compiler/frame.cc',
|
||||
'../../src/compiler/frame.h',
|
||||
'../../src/compiler/frame-elider.cc',
|
||||
|
Loading…
Reference in New Issue
Block a user