Commit 0a50af86 authored by vogelheim's avatar vogelheim Committed by Commit bot

Revert of Implement Fast Accessor Builder (patchset #14 id:260001 of...

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}
parent ce47fc8b
......@@ -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",
......
// 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_
......@@ -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);
......
......@@ -25,7 +25,4 @@ specific_include_rules = {
"d8\.cc": [
"+include/libplatform/libplatform.h",
],
"api-experimental\.cc": [
"+src/compiler/fast-accessor-assembler.h",
],
}
// 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
// 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_
......@@ -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);
}
......
// 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, &not_null);
assembler_->Bind(&is_null);
assembler_->Return(assembler_->NullConstant());
assembler_->Bind(&not_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
// 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);
......
// 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',
......
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