| Index: src/runtime.cc
|
| ===================================================================
|
| --- src/runtime.cc (revision 8462)
|
| +++ src/runtime.cc (working copy)
|
| @@ -45,6 +45,7 @@
|
| #include "json-parser.h"
|
| #include "liveedit.h"
|
| #include "liveobjectlist-inl.h"
|
| +#include "misc-intrinsics.h"
|
| #include "parser.h"
|
| #include "platform.h"
|
| #include "runtime-profiler.h"
|
| @@ -1236,9 +1237,8 @@
|
| RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
|
| Handle<Object> initial_value(args[3], isolate);
|
|
|
| - // Declarations are always done in the function context.
|
| - context = Handle<Context>(context->fcontext());
|
| - ASSERT(context->IsFunctionContext() || context->IsGlobalContext());
|
| + // Declarations are always done in a function or global context.
|
| + context = Handle<Context>(context->declaration_context());
|
|
|
| int index;
|
| PropertyAttributes attributes;
|
| @@ -1525,8 +1525,8 @@
|
| CONVERT_ARG_CHECKED(Context, context, 1);
|
| Handle<String> name(String::cast(args[2]));
|
|
|
| - // Initializations are always done in the function context.
|
| - context = Handle<Context>(context->fcontext());
|
| + // Initializations are always done in a function or global context.
|
| + context = Handle<Context>(context->declaration_context());
|
|
|
| int index;
|
| PropertyAttributes attributes;
|
| @@ -1547,14 +1547,12 @@
|
| // In that case, the initialization behaves like a normal assignment
|
| // to property 'x'.
|
| if (index >= 0) {
|
| - // Property was found in a context.
|
| if (holder->IsContext()) {
|
| - // The holder cannot be the function context. If it is, there
|
| - // should have been a const redeclaration error when declaring
|
| - // the const property.
|
| - ASSERT(!holder.is_identical_to(context));
|
| - if ((attributes & READ_ONLY) == 0) {
|
| - Handle<Context>::cast(holder)->set(index, *value);
|
| + // Property was found in a context. Perform the assignment if we
|
| + // found some non-constant or an uninitialized constant.
|
| + Handle<Context> context = Handle<Context>::cast(holder);
|
| + if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
|
| + context->set(index, *value);
|
| }
|
| } else {
|
| // The holder is an arguments object.
|
| @@ -6645,50 +6643,69 @@
|
| // If the integers are equal so are the string representations.
|
| if (x_value == y_value) return Smi::FromInt(EQUAL);
|
|
|
| - // If one of the integers are zero the normal integer order is the
|
| + // If one of the integers is zero the normal integer order is the
|
| // same as the lexicographic order of the string representations.
|
| - if (x_value == 0 || y_value == 0) return Smi::FromInt(x_value - y_value);
|
| + if (x_value == 0 || y_value == 0)
|
| + return Smi::FromInt(x_value < y_value ? LESS : GREATER);
|
|
|
| // If only one of the integers is negative the negative number is
|
| // smallest because the char code of '-' is less than the char code
|
| // of any digit. Otherwise, we make both values positive.
|
| +
|
| + // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
|
| + // architectures using 32-bit Smis.
|
| + uint32_t x_scaled = x_value;
|
| + uint32_t y_scaled = y_value;
|
| if (x_value < 0 || y_value < 0) {
|
| if (y_value >= 0) return Smi::FromInt(LESS);
|
| if (x_value >= 0) return Smi::FromInt(GREATER);
|
| - x_value = -x_value;
|
| - y_value = -y_value;
|
| + x_scaled = -x_value;
|
| + y_scaled = -y_value;
|
| }
|
|
|
| - // Arrays for the individual characters of the two Smis. Smis are
|
| - // 31 bit integers and 10 decimal digits are therefore enough.
|
| - // TODO(isolates): maybe we should simply allocate 20 bytes on the stack.
|
| - int* x_elms = isolate->runtime_state()->smi_lexicographic_compare_x_elms();
|
| - int* y_elms = isolate->runtime_state()->smi_lexicographic_compare_y_elms();
|
| + static const uint32_t kPowersOf10[] = {
|
| + 1, 10, 100, 1000, 10*1000, 100*1000,
|
| + 1000*1000, 10*1000*1000, 100*1000*1000,
|
| + 1000*1000*1000
|
| + };
|
|
|
| + // If the integers have the same number of decimal digits they can be
|
| + // compared directly as the numeric order is the same as the
|
| + // lexicographic order. If one integer has fewer digits, it is scaled
|
| + // by some power of 10 to have the same number of digits as the longer
|
| + // integer. If the scaled integers are equal it means the shorter
|
| + // integer comes first in the lexicographic order.
|
|
|
| - // Convert the integers to arrays of their decimal digits.
|
| - int x_index = 0;
|
| - int y_index = 0;
|
| - while (x_value > 0) {
|
| - x_elms[x_index++] = x_value % 10;
|
| - x_value /= 10;
|
| - }
|
| - while (y_value > 0) {
|
| - y_elms[y_index++] = y_value % 10;
|
| - y_value /= 10;
|
| - }
|
| + // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
|
| + int x_log2 = IntegerLog2(x_scaled);
|
| + int x_log10 = ((x_log2 + 1) * 1233) >> 12;
|
| + x_log10 -= x_scaled < kPowersOf10[x_log10];
|
|
|
| - // Loop through the arrays of decimal digits finding the first place
|
| - // where they differ.
|
| - while (--x_index >= 0 && --y_index >= 0) {
|
| - int diff = x_elms[x_index] - y_elms[y_index];
|
| - if (diff != 0) return Smi::FromInt(diff);
|
| + int y_log2 = IntegerLog2(y_scaled);
|
| + int y_log10 = ((y_log2 + 1) * 1233) >> 12;
|
| + y_log10 -= y_scaled < kPowersOf10[y_log10];
|
| +
|
| + int tie = EQUAL;
|
| +
|
| + if (x_log10 < y_log10) {
|
| + // X has fewer digits. We would like to simply scale up X but that
|
| + // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
|
| + // be scaled up to 9_000_000_000. So we scale up by the next
|
| + // smallest power and scale down Y to drop one digit. It is OK to
|
| + // drop one digit from the longer integer since the final digit is
|
| + // past the length of the shorter integer.
|
| + x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
|
| + y_scaled /= 10;
|
| + tie = LESS;
|
| + } else if (y_log10 < x_log10) {
|
| + y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
|
| + x_scaled /= 10;
|
| + tie = GREATER;
|
| }
|
|
|
| - // If one array is a suffix of the other array, the longest array is
|
| - // the representation of the largest of the Smis in the
|
| - // lexicographic ordering.
|
| - return Smi::FromInt(x_index - y_index);
|
| + if (x_scaled < y_scaled) return Smi::FromInt(LESS);
|
| + if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
|
| + return Smi::FromInt(tie);
|
| }
|
|
|
|
|
| @@ -8052,7 +8069,7 @@
|
|
|
| RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
|
| NoHandleAllocation ha;
|
| - ASSERT(args.length() == 1);
|
| + ASSERT(args.length() == 2);
|
| JSObject* extension_object;
|
| if (args[0]->IsJSObject()) {
|
| extension_object = JSObject::cast(args[0]);
|
| @@ -8073,9 +8090,20 @@
|
| }
|
| }
|
|
|
| + JSFunction* function;
|
| + if (args[1]->IsSmi()) {
|
| + // A smi sentinel indicates a context nested inside global code rather
|
| + // than some function. There is a canonical empty function that can be
|
| + // gotten from the global context.
|
| + function = isolate->context()->global_context()->closure();
|
| + } else {
|
| + function = JSFunction::cast(args[1]);
|
| + }
|
| +
|
| Context* context;
|
| MaybeObject* maybe_context =
|
| - isolate->heap()->AllocateWithContext(isolate->context(),
|
| + isolate->heap()->AllocateWithContext(function,
|
| + isolate->context(),
|
| extension_object);
|
| if (!maybe_context->To(&context)) return maybe_context;
|
| isolate->set_context(context);
|
| @@ -8085,12 +8113,22 @@
|
|
|
| RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
|
| NoHandleAllocation ha;
|
| - ASSERT(args.length() == 2);
|
| + ASSERT(args.length() == 3);
|
| String* name = String::cast(args[0]);
|
| Object* thrown_object = args[1];
|
| + JSFunction* function;
|
| + if (args[2]->IsSmi()) {
|
| + // A smi sentinel indicates a context nested inside global code rather
|
| + // than some function. There is a canonical empty function that can be
|
| + // gotten from the global context.
|
| + function = isolate->context()->global_context()->closure();
|
| + } else {
|
| + function = JSFunction::cast(args[2]);
|
| + }
|
| Context* context;
|
| MaybeObject* maybe_context =
|
| - isolate->heap()->AllocateCatchContext(isolate->context(),
|
| + isolate->heap()->AllocateCatchContext(function,
|
| + isolate->context(),
|
| name,
|
| thrown_object);
|
| if (!maybe_context->To(&context)) return maybe_context;
|
| @@ -9986,9 +10024,6 @@
|
| Handle<SerializedScopeInfo> scope_info(function->shared()->scope_info());
|
| ScopeInfo<> info(*scope_info);
|
|
|
| - // Get the nearest enclosing function context.
|
| - Handle<Context> context(Context::cast(it.frame()->context())->fcontext());
|
| -
|
| // Get the locals names and values into a temporary array.
|
| //
|
| // TODO(1240907): Hide compiler-introduced stack variables
|
| @@ -9997,11 +10032,6 @@
|
| Handle<FixedArray> locals =
|
| isolate->factory()->NewFixedArray(info.NumberOfLocals() * 2);
|
|
|
| - // Fill in the names of the locals.
|
| - for (int i = 0; i < info.NumberOfLocals(); i++) {
|
| - locals->set(i * 2, *info.LocalName(i));
|
| - }
|
| -
|
| // Fill in the values of the locals.
|
| if (is_optimized_frame) {
|
| // If we are inspecting an optimized frame use undefined as the
|
| @@ -10010,15 +10040,22 @@
|
| // TODO(1140): We should be able to get the correct values
|
| // for locals in optimized frames.
|
| for (int i = 0; i < info.NumberOfLocals(); i++) {
|
| + locals->set(i * 2, *info.LocalName(i));
|
| locals->set(i * 2 + 1, isolate->heap()->undefined_value());
|
| }
|
| } else {
|
| - for (int i = 0; i < info.number_of_stack_slots(); i++) {
|
| - // Get the value from the stack.
|
| + int i = 0;
|
| + for (; i < info.number_of_stack_slots(); ++i) {
|
| + // Use the value from the stack.
|
| + locals->set(i * 2, *info.LocalName(i));
|
| locals->set(i * 2 + 1, it.frame()->GetExpression(i));
|
| }
|
| - for (int i = info.number_of_stack_slots(); i < info.NumberOfLocals(); i++) {
|
| + // Get the context containing declarations.
|
| + Handle<Context> context(
|
| + Context::cast(it.frame()->context())->declaration_context());
|
| + for (; i < info.NumberOfLocals(); ++i) {
|
| Handle<String> name = info.LocalName(i);
|
| + locals->set(i * 2, *name);
|
| locals->set(i * 2 + 1,
|
| context->get(scope_info->ContextSlotIndex(*name, NULL)));
|
| }
|
| @@ -10239,7 +10276,7 @@
|
|
|
| // Third fill all context locals.
|
| Handle<Context> frame_context(Context::cast(frame->context()));
|
| - Handle<Context> function_context(frame_context->fcontext());
|
| + Handle<Context> function_context(frame_context->declaration_context());
|
| if (!CopyContextLocalsToScopeObject(isolate,
|
| serialized_scope_info, scope_info,
|
| function_context, local_scope)) {
|
| @@ -10971,6 +11008,7 @@
|
| // Creates a copy of the with context chain. The copy of the context chain is
|
| // is linked to the function context supplied.
|
| static Handle<Context> CopyWithContextChain(Isolate* isolate,
|
| + Handle<JSFunction> function,
|
| Handle<Context> current,
|
| Handle<Context> base) {
|
| // At the end of the chain. Return the base context to link to.
|
| @@ -10981,17 +11019,21 @@
|
| // Recursively copy the with and catch contexts.
|
| HandleScope scope(isolate);
|
| Handle<Context> previous(current->previous());
|
| - Handle<Context> new_previous = CopyWithContextChain(isolate, previous, base);
|
| + Handle<Context> new_previous =
|
| + CopyWithContextChain(isolate, function, previous, base);
|
| Handle<Context> new_current;
|
| if (current->IsCatchContext()) {
|
| Handle<String> name(String::cast(current->extension()));
|
| Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
|
| new_current =
|
| - isolate->factory()->NewCatchContext(new_previous, name, thrown_object);
|
| + isolate->factory()->NewCatchContext(function,
|
| + new_previous,
|
| + name,
|
| + thrown_object);
|
| } else {
|
| Handle<JSObject> extension(JSObject::cast(current->extension()));
|
| new_current =
|
| - isolate->factory()->NewWithContext(new_previous, extension);
|
| + isolate->factory()->NewWithContext(function, new_previous, extension);
|
| }
|
| return scope.CloseAndEscape(new_current);
|
| }
|
| @@ -11121,12 +11163,13 @@
|
| context->set_extension(*local_scope);
|
| // Copy any with contexts present and chain them in front of this context.
|
| Handle<Context> frame_context(Context::cast(frame->context()));
|
| - Handle<Context> function_context(frame_context->fcontext());
|
| - context = CopyWithContextChain(isolate, frame_context, context);
|
| + Handle<Context> function_context(frame_context->declaration_context());
|
| + context = CopyWithContextChain(isolate, go_between, frame_context, context);
|
|
|
| if (additional_context->IsJSObject()) {
|
| Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
|
| - context = isolate->factory()->NewWithContext(context, extension);
|
| + context =
|
| + isolate->factory()->NewWithContext(go_between, context, extension);
|
| }
|
|
|
| // Wrap the evaluation statement in a new function compiled in the newly
|
|
|