blob: 80ea7f4b6f0f27dbad94b90799747017e69466b6 [file] [log] [blame]
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00001// Copyright 2012 the V8 project authors. All rights reserved.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
28#include <stdlib.h>
29
30#include "v8.h"
31
32#include "accessors.h"
33#include "api.h"
34#include "arguments.h"
fschneider@chromium.org1805e212011-09-05 10:49:12 +000035#include "bootstrapper.h"
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000036#include "codegen.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000037#include "compilation-cache.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000038#include "compiler.h"
39#include "cpu.h"
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000040#include "dateparser-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000041#include "debug.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000042#include "deoptimizer.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000043#include "execution.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000044#include "global-handles.h"
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000045#include "isolate-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000046#include "jsregexp.h"
danno@chromium.org40cb8782011-05-25 07:58:50 +000047#include "json-parser.h"
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000048#include "liveedit.h"
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000049#include "liveobjectlist-inl.h"
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000050#include "misc-intrinsics.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000051#include "parser.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000052#include "platform.h"
kasperl@chromium.orga5551262010-12-07 12:49:48 +000053#include "runtime-profiler.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000054#include "runtime.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000055#include "scopeinfo.h"
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000056#include "smart-array-pointer.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000057#include "string-search.h"
ager@chromium.org18ad94b2009-09-02 08:22:29 +000058#include "stub-cache.h"
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +000059#include "v8threads.h"
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +000060#include "vm-state-inl.h"
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000061
kasperl@chromium.org71affb52009-05-26 05:44:31 +000062namespace v8 {
63namespace internal {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000064
65
ager@chromium.org3e875802009-06-29 08:26:34 +000066#define RUNTIME_ASSERT(value) \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000067 if (!(value)) return isolate->ThrowIllegalOperation();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000068
69// Cast the given object to a value of the specified type and store
70// it in a variable with the given name. If the object is not of the
71// expected type call IllegalOperation and return.
72#define CONVERT_CHECKED(Type, name, obj) \
73 RUNTIME_ASSERT(obj->Is##Type()); \
74 Type* name = Type::cast(obj);
75
76#define CONVERT_ARG_CHECKED(Type, name, index) \
77 RUNTIME_ASSERT(args[index]->Is##Type()); \
78 Handle<Type> name = args.at<Type>(index);
79
kasper.lundbd3ec4e2008-07-09 11:06:54 +000080// Cast the given object to a boolean and store it in a variable with
81// the given name. If the object is not a boolean call IllegalOperation
82// and return.
83#define CONVERT_BOOLEAN_CHECKED(name, obj) \
84 RUNTIME_ASSERT(obj->IsBoolean()); \
85 bool name = (obj)->IsTrue();
86
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000087// Cast the given argument to a Smi and store its value in an int variable
88// with the given name. If the argument is not a Smi call IllegalOperation
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000089// and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000090#define CONVERT_SMI_ARG_CHECKED(name, index) \
91 RUNTIME_ASSERT(args[index]->IsSmi()); \
92 int name = args.smi_at(index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000093
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000094// Cast the given argument to a double and store it in a variable with
95// the given name. If the argument is not a number (as opposed to
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000096// the number not-a-number) call IllegalOperation and return.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000097#define CONVERT_DOUBLE_ARG_CHECKED(name, index) \
98 RUNTIME_ASSERT(args[index]->IsNumber()); \
99 double name = args.number_at(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000100
101// Call the specified converter on the object *comand store the result in
102// a variable of the specified type with the given name. If the
103// object is not a Number call IllegalOperation and return.
104#define CONVERT_NUMBER_CHECKED(type, name, Type, obj) \
105 RUNTIME_ASSERT(obj->IsNumber()); \
106 type name = NumberTo##Type(obj);
107
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000108
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +0000109// Assert that the given argument has a valid value for a StrictModeFlag
110// and store it in a StrictModeFlag variable with the given name.
111#define CONVERT_STRICT_MODE_ARG(name, index) \
112 ASSERT(args[index]->IsSmi()); \
113 ASSERT(args.smi_at(index) == kStrictMode || \
114 args.smi_at(index) == kNonStrictMode); \
115 StrictModeFlag name = \
116 static_cast<StrictModeFlag>(args.smi_at(index));
117
118
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +0000119// Assert that the given argument has a valid value for a LanguageMode
120// and store it in a LanguageMode variable with the given name.
121#define CONVERT_LANGUAGE_MODE_ARG(name, index) \
122 ASSERT(args[index]->IsSmi()); \
123 ASSERT(args.smi_at(index) == CLASSIC_MODE || \
124 args.smi_at(index) == STRICT_MODE || \
125 args.smi_at(index) == EXTENDED_MODE); \
126 LanguageMode name = \
127 static_cast<LanguageMode>(args.smi_at(index));
128
129
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000130MUST_USE_RESULT static MaybeObject* DeepCopyBoilerplate(Isolate* isolate,
131 JSObject* boilerplate) {
132 StackLimitCheck check(isolate);
133 if (check.HasOverflowed()) return isolate->StackOverflow();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000134
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000135 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +0000136 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000137 { MaybeObject* maybe_result = heap->CopyJSObject(boilerplate);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000138 if (!maybe_result->ToObject(&result)) return maybe_result;
139 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000140 JSObject* copy = JSObject::cast(result);
141
142 // Deep copy local properties.
143 if (copy->HasFastProperties()) {
144 FixedArray* properties = copy->properties();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000145 for (int i = 0; i < properties->length(); i++) {
146 Object* value = properties->get(i);
147 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000148 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000149 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000150 if (!maybe_result->ToObject(&result)) return maybe_result;
151 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000152 properties->set(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000153 }
154 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +0000155 int nof = copy->map()->inobject_properties();
156 for (int i = 0; i < nof; i++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000157 Object* value = copy->InObjectPropertyAt(i);
158 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000159 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000160 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000161 if (!maybe_result->ToObject(&result)) return maybe_result;
162 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000163 copy->InObjectPropertyAtPut(i, result);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000164 }
165 }
166 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +0000167 { MaybeObject* maybe_result =
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties());
lrn@chromium.org303ada72010-10-27 09:33:13 +0000169 if (!maybe_result->ToObject(&result)) return maybe_result;
170 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000171 FixedArray* names = FixedArray::cast(result);
172 copy->GetLocalPropertyNames(names, 0);
173 for (int i = 0; i < names->length(); i++) {
174 ASSERT(names->get(i)->IsString());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000175 String* key_string = String::cast(names->get(i));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000176 PropertyAttributes attributes =
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000177 copy->GetLocalPropertyAttribute(key_string);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000178 // Only deep copy fields from the object literal expression.
179 // In particular, don't try to copy the length attribute of
180 // an array.
181 if (attributes != NONE) continue;
lrn@chromium.org303ada72010-10-27 09:33:13 +0000182 Object* value =
183 copy->GetProperty(key_string, &attributes)->ToObjectUnchecked();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000184 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000185 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000186 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate, js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000187 if (!maybe_result->ToObject(&result)) return maybe_result;
188 }
189 { MaybeObject* maybe_result =
ager@chromium.org9ee27ae2011-03-02 13:43:26 +0000190 // Creating object copy for literals. No strict mode needed.
191 copy->SetProperty(key_string, result, NONE, kNonStrictMode);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000192 if (!maybe_result->ToObject(&result)) return maybe_result;
193 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000194 }
195 }
196 }
197
198 // Deep copy local elements.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000199 // Pixel elements cannot be created using an object literal.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +0000200 ASSERT(!copy->HasExternalArrayElements());
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000201 switch (copy->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000202 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000203 case FAST_ELEMENTS: {
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000204 FixedArray* elements = FixedArray::cast(copy->elements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000205 if (elements->map() == heap->fixed_cow_array_map()) {
206 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000207#ifdef DEBUG
208 for (int i = 0; i < elements->length(); i++) {
209 ASSERT(!elements->get(i)->IsJSObject());
210 }
211#endif
212 } else {
213 for (int i = 0; i < elements->length(); i++) {
214 Object* value = elements->get(i);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000215 ASSERT(value->IsSmi() ||
216 value->IsTheHole() ||
217 (copy->GetElementsKind() == FAST_ELEMENTS));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000218 if (value->IsJSObject()) {
219 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000220 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
221 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000222 if (!maybe_result->ToObject(&result)) return maybe_result;
223 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000224 elements->set(i, result);
225 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000226 }
227 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000228 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000229 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000230 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000231 SeededNumberDictionary* element_dictionary = copy->element_dictionary();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000232 int capacity = element_dictionary->Capacity();
233 for (int i = 0; i < capacity; i++) {
234 Object* k = element_dictionary->KeyAt(i);
235 if (element_dictionary->IsKey(k)) {
236 Object* value = element_dictionary->ValueAt(i);
237 if (value->IsJSObject()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000238 JSObject* js_object = JSObject::cast(value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000239 { MaybeObject* maybe_result = DeepCopyBoilerplate(isolate,
240 js_object);
lrn@chromium.org303ada72010-10-27 09:33:13 +0000241 if (!maybe_result->ToObject(&result)) return maybe_result;
242 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000243 element_dictionary->ValueAtPut(i, result);
244 }
245 }
246 }
247 break;
248 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000249 case NON_STRICT_ARGUMENTS_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000250 UNIMPLEMENTED();
251 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +0000252 case EXTERNAL_PIXEL_ELEMENTS:
253 case EXTERNAL_BYTE_ELEMENTS:
254 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
255 case EXTERNAL_SHORT_ELEMENTS:
256 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
257 case EXTERNAL_INT_ELEMENTS:
258 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
259 case EXTERNAL_FLOAT_ELEMENTS:
260 case EXTERNAL_DOUBLE_ELEMENTS:
261 case FAST_DOUBLE_ELEMENTS:
ricow@chromium.org2c99e282011-07-28 09:15:17 +0000262 // No contained objects, nothing to do.
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +0000263 break;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000264 }
265 return copy;
266}
267
268
ager@chromium.org236ad962008-09-25 09:45:57 +0000269static Handle<Map> ComputeObjectLiteralMap(
270 Handle<Context> context,
271 Handle<FixedArray> constant_properties,
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000272 bool* is_result_from_cache) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000273 Isolate* isolate = context->GetIsolate();
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000274 int properties_length = constant_properties->length();
275 int number_of_properties = properties_length / 2;
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000276 // Check that there are only symbols and array indices among keys.
277 int number_of_symbol_keys = 0;
278 for (int p = 0; p != properties_length; p += 2) {
279 Object* key = constant_properties->get(p);
280 uint32_t element_index = 0;
281 if (key->IsSymbol()) {
282 number_of_symbol_keys++;
283 } else if (key->ToArrayIndex(&element_index)) {
284 // An index key does not require space in the property backing store.
285 number_of_properties--;
286 } else {
287 // Bail out as a non-symbol non-index key makes caching impossible.
288 // ASSERT to make sure that the if condition after the loop is false.
289 ASSERT(number_of_symbol_keys != number_of_properties);
290 break;
ager@chromium.org236ad962008-09-25 09:45:57 +0000291 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000292 }
293 // If we only have symbols and array indices among keys then we can
294 // use the map cache in the global context.
295 const int kMaxKeys = 10;
296 if ((number_of_symbol_keys == number_of_properties) &&
297 (number_of_symbol_keys < kMaxKeys)) {
298 // Create the fixed array with the key.
299 Handle<FixedArray> keys =
300 isolate->factory()->NewFixedArray(number_of_symbol_keys);
301 if (number_of_symbol_keys > 0) {
302 int index = 0;
303 for (int p = 0; p < properties_length; p += 2) {
304 Object* key = constant_properties->get(p);
305 if (key->IsSymbol()) {
306 keys->set(index++, key);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000307 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000308 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000309 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000310 }
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +0000311 *is_result_from_cache = true;
312 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000313 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000314 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000315 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000316 Handle<Map>(context->object_function()->initial_map()),
317 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000318}
319
320
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000321static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000322 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323 Handle<FixedArray> literals,
324 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000325
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000326
327static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000328 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000329 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000330 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000331 bool should_have_fast_elements,
332 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000333 // Get the global context from the literals array. This is the
334 // context in which the function was created and we use the object
335 // function from this context to create the object literal. We do
336 // not use the object function from the current global context
337 // because this might be the object function from another context
338 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000339 Handle<Context> context =
340 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
341
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000342 // In case we have function literals, we want the object to be in
343 // slow properties mode for now. We don't go in the map cache because
344 // maps with constant functions can't be shared if the functions are
345 // not the same (which is the common case).
346 bool is_result_from_cache = false;
347 Handle<Map> map = has_function_literal
348 ? Handle<Map>(context->object_function()->initial_map())
349 : ComputeObjectLiteralMap(context,
350 constant_properties,
351 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000352
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000353 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000354
355 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000356 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000357
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000358 // Add the constant properties to the boilerplate.
359 int length = constant_properties->length();
360 bool should_transform =
361 !is_result_from_cache && boilerplate->HasFastProperties();
362 if (should_transform || has_function_literal) {
363 // Normalize the properties of object to avoid n^2 behavior
364 // when extending the object multiple properties. Indicate the number of
365 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000366 JSObject::NormalizeProperties(
367 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000368 }
369
370 for (int index = 0; index < length; index +=2) {
371 Handle<Object> key(constant_properties->get(index+0), isolate);
372 Handle<Object> value(constant_properties->get(index+1), isolate);
373 if (value->IsFixedArray()) {
374 // The value contains the constant_properties of a
375 // simple object or array literal.
376 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
377 value = CreateLiteralBoilerplate(isolate, literals, array);
378 if (value.is_null()) return value;
379 }
380 Handle<Object> result;
381 uint32_t element_index = 0;
382 if (key->IsSymbol()) {
383 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
384 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000385 result = JSObject::SetOwnElement(
386 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000387 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000388 Handle<String> name(String::cast(*key));
389 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000390 result = JSObject::SetLocalPropertyIgnoreAttributes(
391 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000392 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000393 } else if (key->ToArrayIndex(&element_index)) {
394 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000395 result = JSObject::SetOwnElement(
396 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000397 } else {
398 // Non-uint32 number.
399 ASSERT(key->IsNumber());
400 double num = key->Number();
401 char arr[100];
402 Vector<char> buffer(arr, ARRAY_SIZE(arr));
403 const char* str = DoubleToCString(num, buffer);
404 Handle<String> name =
405 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000406 result = JSObject::SetLocalPropertyIgnoreAttributes(
407 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000408 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000409 // If setting the property on the boilerplate throws an
410 // exception, the exception is converted to an empty handle in
411 // the handle based operations. In that case, we need to
412 // convert back to an exception.
413 if (result.is_null()) return result;
414 }
415
416 // Transform to fast properties if necessary. For object literals with
417 // containing function literals we defer this operation until after all
418 // computed properties have been assigned so that we can generate
419 // constant function properties.
420 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000421 JSObject::TransformToFastProperties(
422 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000423 }
424
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000425 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000426}
427
428
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000429MaybeObject* TransitionElements(Handle<Object> object,
430 ElementsKind to_kind,
431 Isolate* isolate) {
432 HandleScope scope(isolate);
433 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
434 ElementsKind from_kind =
435 Handle<JSObject>::cast(object)->map()->elements_kind();
436 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
437 Handle<Object> result = JSObject::TransitionElementsKind(
438 Handle<JSObject>::cast(object), to_kind);
439 if (result.is_null()) return isolate->ThrowIllegalOperation();
440 return *result;
441 }
442 return isolate->ThrowIllegalOperation();
443}
444
445
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000446static const int kSmiOnlyLiteralMinimumLength = 1024;
447
448
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000449Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000450 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000451 Handle<FixedArray> literals,
452 Handle<FixedArray> elements) {
453 // Create the JSArray.
454 Handle<JSFunction> constructor(
455 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000456 Handle<JSArray> object =
457 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000458
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000459 ElementsKind constant_elements_kind =
460 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
461 Handle<FixedArrayBase> constant_elements_values(
462 FixedArrayBase::cast(elements->get(1)));
463
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000464 Context* global_context = isolate->context()->global_context();
465 if (constant_elements_kind == FAST_SMI_ONLY_ELEMENTS) {
466 object->set_map(Map::cast(global_context->smi_js_array_map()));
467 } else if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
468 object->set_map(Map::cast(global_context->double_js_array_map()));
469 } else {
470 object->set_map(Map::cast(global_context->object_js_array_map()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000471 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000472
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000473 Handle<FixedArrayBase> copied_elements_values;
474 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
475 ASSERT(FLAG_smi_only_arrays);
476 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
477 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000478 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000479 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
480 constant_elements_kind == FAST_ELEMENTS);
481 const bool is_cow =
482 (constant_elements_values->map() ==
483 isolate->heap()->fixed_cow_array_map());
484 if (is_cow) {
485 copied_elements_values = constant_elements_values;
486#if DEBUG
487 Handle<FixedArray> fixed_array_values =
488 Handle<FixedArray>::cast(copied_elements_values);
489 for (int i = 0; i < fixed_array_values->length(); i++) {
490 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
491 }
492#endif
493 } else {
494 Handle<FixedArray> fixed_array_values =
495 Handle<FixedArray>::cast(constant_elements_values);
496 Handle<FixedArray> fixed_array_values_copy =
497 isolate->factory()->CopyFixedArray(fixed_array_values);
498 copied_elements_values = fixed_array_values_copy;
499 for (int i = 0; i < fixed_array_values->length(); i++) {
500 Object* current = fixed_array_values->get(i);
501 if (current->IsFixedArray()) {
502 // The value contains the constant_properties of a
503 // simple object or array literal.
504 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
505 Handle<Object> result =
506 CreateLiteralBoilerplate(isolate, literals, fa);
507 if (result.is_null()) return result;
508 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000509 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000510 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000511 }
512 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000513 object->set_elements(*copied_elements_values);
514 object->set_length(Smi::FromInt(copied_elements_values->length()));
danno@chromium.orgfa458e42012-02-01 10:48:36 +0000515
516 // Ensure that the boilerplate object has FAST_ELEMENTS, unless the flag is
517 // on or the object is larger than the threshold.
518 if (!FLAG_smi_only_arrays &&
519 constant_elements_values->length() < kSmiOnlyLiteralMinimumLength) {
520 if (object->GetElementsKind() != FAST_ELEMENTS) {
521 CHECK(!TransitionElements(object, FAST_ELEMENTS, isolate)->IsFailure());
522 }
523 }
524
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000525 return object;
526}
527
528
529static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000531 Handle<FixedArray> literals,
532 Handle<FixedArray> array) {
533 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000534 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000536 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000537 return CreateObjectLiteralBoilerplate(isolate,
538 literals,
539 elements,
540 true,
541 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000542 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000543 return CreateObjectLiteralBoilerplate(isolate,
544 literals,
545 elements,
546 false,
547 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000548 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000549 return Runtime::CreateArrayLiteralBoilerplate(
550 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000551 default:
552 UNREACHABLE();
553 return Handle<Object>::null();
554 }
555}
556
557
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000558RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000559 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000560 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000561 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000562 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000564 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000565 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
566 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000567
568 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000569 Handle<Object> boilerplate(literals->get(literals_index), isolate);
570 if (*boilerplate == isolate->heap()->undefined_value()) {
571 boilerplate = CreateObjectLiteralBoilerplate(isolate,
572 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000573 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000574 should_have_fast_elements,
575 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 if (boilerplate.is_null()) return Failure::Exception();
577 // Update the functions literal and return the boilerplate.
578 literals->set(literals_index, *boilerplate);
579 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000580 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000581}
582
583
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000584RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000585 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000586 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000587 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000588 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000590 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000591 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
592 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000593
594 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000595 Handle<Object> boilerplate(literals->get(literals_index), isolate);
596 if (*boilerplate == isolate->heap()->undefined_value()) {
597 boilerplate = CreateObjectLiteralBoilerplate(isolate,
598 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000599 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000600 should_have_fast_elements,
601 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602 if (boilerplate.is_null()) return Failure::Exception();
603 // Update the functions literal and return the boilerplate.
604 literals->set(literals_index, *boilerplate);
605 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000606 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000607}
608
609
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000610RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000611 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000612 ASSERT(args.length() == 3);
613 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000614 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000615 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
616
617 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 Handle<Object> boilerplate(literals->get(literals_index), isolate);
619 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000620 boilerplate =
621 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622 if (boilerplate.is_null()) return Failure::Exception();
623 // Update the functions literal and return the boilerplate.
624 literals->set(literals_index, *boilerplate);
625 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000626 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000627}
628
629
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000630RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000631 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000632 ASSERT(args.length() == 3);
633 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000634 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000635 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
636
637 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 Handle<Object> boilerplate(literals->get(literals_index), isolate);
639 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000640 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000641 boilerplate =
642 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000643 if (boilerplate.is_null()) return Failure::Exception();
644 // Update the functions literal and return the boilerplate.
645 literals->set(literals_index, *boilerplate);
646 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000647 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000648 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000649 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000650 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000651 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000652}
653
654
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000655RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
656 ASSERT(args.length() == 2);
657 Object* handler = args[0];
658 Object* prototype = args[1];
659 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000660 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000661 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
662}
663
664
lrn@chromium.org34e60782011-09-15 07:25:40 +0000665RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
666 ASSERT(args.length() == 4);
667 Object* handler = args[0];
668 Object* call_trap = args[1];
669 Object* construct_trap = args[2];
670 Object* prototype = args[3];
671 Object* used_prototype =
672 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
673 return isolate->heap()->AllocateJSFunctionProxy(
674 handler, call_trap, construct_trap, used_prototype);
675}
676
677
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000678RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
679 ASSERT(args.length() == 1);
680 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000681 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000682}
683
684
lrn@chromium.org34e60782011-09-15 07:25:40 +0000685RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
686 ASSERT(args.length() == 1);
687 Object* obj = args[0];
688 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
689}
690
691
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
693 ASSERT(args.length() == 1);
694 CONVERT_CHECKED(JSProxy, proxy, args[0]);
695 return proxy->handler();
696}
697
698
lrn@chromium.org34e60782011-09-15 07:25:40 +0000699RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
700 ASSERT(args.length() == 1);
701 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
702 return proxy->call_trap();
703}
704
705
706RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
707 ASSERT(args.length() == 1);
708 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
709 return proxy->construct_trap();
710}
711
712
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000713RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
714 ASSERT(args.length() == 1);
715 CONVERT_CHECKED(JSProxy, proxy, args[0]);
716 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000717 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000718}
719
720
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000721RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
722 HandleScope scope(isolate);
723 ASSERT(args.length() == 1);
724 CONVERT_ARG_CHECKED(JSSet, holder, 0);
725 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
726 holder->set_table(*table);
727 return *holder;
728}
729
730
731RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
732 HandleScope scope(isolate);
733 ASSERT(args.length() == 2);
734 CONVERT_ARG_CHECKED(JSSet, holder, 0);
735 Handle<Object> key(args[1]);
736 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
737 table = ObjectHashSetAdd(table, key);
738 holder->set_table(*table);
739 return isolate->heap()->undefined_symbol();
740}
741
742
743RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
744 HandleScope scope(isolate);
745 ASSERT(args.length() == 2);
746 CONVERT_ARG_CHECKED(JSSet, holder, 0);
747 Handle<Object> key(args[1]);
748 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
749 return isolate->heap()->ToBoolean(table->Contains(*key));
750}
751
752
753RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
754 HandleScope scope(isolate);
755 ASSERT(args.length() == 2);
756 CONVERT_ARG_CHECKED(JSSet, holder, 0);
757 Handle<Object> key(args[1]);
758 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
759 table = ObjectHashSetRemove(table, key);
760 holder->set_table(*table);
761 return isolate->heap()->undefined_symbol();
762}
763
764
765RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
766 HandleScope scope(isolate);
767 ASSERT(args.length() == 1);
768 CONVERT_ARG_CHECKED(JSMap, holder, 0);
769 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
770 holder->set_table(*table);
771 return *holder;
772}
773
774
775RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
776 HandleScope scope(isolate);
777 ASSERT(args.length() == 2);
778 CONVERT_ARG_CHECKED(JSMap, holder, 0);
779 Handle<Object> key(args[1]);
780 return ObjectHashTable::cast(holder->table())->Lookup(*key);
781}
782
783
784RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 3);
787 CONVERT_ARG_CHECKED(JSMap, holder, 0);
788 Handle<Object> key(args[1]);
789 Handle<Object> value(args[2]);
790 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
791 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
792 holder->set_table(*new_table);
793 return *value;
794}
795
796
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000797RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
798 HandleScope scope(isolate);
799 ASSERT(args.length() == 1);
800 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
801 ASSERT(weakmap->map()->inobject_properties() == 0);
802 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
803 weakmap->set_table(*table);
804 weakmap->set_next(Smi::FromInt(0));
805 return *weakmap;
806}
807
808
809RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
810 NoHandleAllocation ha;
811 ASSERT(args.length() == 2);
812 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000813 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
814 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000815}
816
817
818RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
819 HandleScope scope(isolate);
820 ASSERT(args.length() == 3);
821 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000822 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000823 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000824 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000825 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
826 weakmap->set_table(*new_table);
827 return *value;
828}
829
830
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000831RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000832 NoHandleAllocation ha;
833 ASSERT(args.length() == 1);
834 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000835 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000836 return JSObject::cast(obj)->class_name();
837}
838
ager@chromium.org7c537e22008-10-16 08:43:32 +0000839
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000840RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
841 NoHandleAllocation ha;
842 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000843 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
844 Object* obj = input_obj;
845 // We don't expect access checks to be needed on JSProxy objects.
846 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000847 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000848 if (obj->IsAccessCheckNeeded() &&
849 !isolate->MayNamedAccess(JSObject::cast(obj),
850 isolate->heap()->Proto_symbol(),
851 v8::ACCESS_GET)) {
852 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
853 return isolate->heap()->undefined_value();
854 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000855 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000856 } while (obj->IsJSObject() &&
857 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000858 return obj;
859}
860
861
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000862RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000863 NoHandleAllocation ha;
864 ASSERT(args.length() == 2);
865 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
866 Object* O = args[0];
867 Object* V = args[1];
868 while (true) {
869 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000870 if (prototype->IsNull()) return isolate->heap()->false_value();
871 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000872 V = prototype;
873 }
874}
875
876
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000877RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000878 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000879 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000880 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000881 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000882}
883
884
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000885// Recursively traverses hidden prototypes if property is not found
886static void GetOwnPropertyImplementation(JSObject* obj,
887 String* name,
888 LookupResult* result) {
889 obj->LocalLookupRealNamedProperty(name, result);
890
891 if (!result->IsProperty()) {
892 Object* proto = obj->GetPrototype();
893 if (proto->IsJSObject() &&
894 JSObject::cast(proto)->map()->is_hidden_prototype())
895 GetOwnPropertyImplementation(JSObject::cast(proto),
896 name, result);
897 }
898}
899
900
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000901static bool CheckAccessException(LookupResult* result,
902 v8::AccessType access_type) {
903 if (result->type() == CALLBACKS) {
904 Object* callback = result->GetCallbackObject();
905 if (callback->IsAccessorInfo()) {
906 AccessorInfo* info = AccessorInfo::cast(callback);
907 bool can_access =
908 (access_type == v8::ACCESS_HAS &&
909 (info->all_can_read() || info->all_can_write())) ||
910 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
911 (access_type == v8::ACCESS_SET && info->all_can_write());
912 return can_access;
913 }
914 }
915
916 return false;
917}
918
919
920static bool CheckAccess(JSObject* obj,
921 String* name,
922 LookupResult* result,
923 v8::AccessType access_type) {
924 ASSERT(result->IsProperty());
925
926 JSObject* holder = result->holder();
927 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000928 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000929 while (true) {
930 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000931 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000932 // Access check callback denied the access, but some properties
933 // can have a special permissions which override callbacks descision
934 // (currently see v8::AccessControl).
935 break;
936 }
937
938 if (current == holder) {
939 return true;
940 }
941
942 current = JSObject::cast(current->GetPrototype());
943 }
944
945 // API callbacks can have per callback access exceptions.
946 switch (result->type()) {
947 case CALLBACKS: {
948 if (CheckAccessException(result, access_type)) {
949 return true;
950 }
951 break;
952 }
953 case INTERCEPTOR: {
954 // If the object has an interceptor, try real named properties.
955 // Overwrite the result to fetch the correct property later.
956 holder->LookupRealNamedProperty(name, result);
957 if (result->IsProperty()) {
958 if (CheckAccessException(result, access_type)) {
959 return true;
960 }
961 }
962 break;
963 }
964 default:
965 break;
966 }
967
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000968 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000969 return false;
970}
971
972
973// TODO(1095): we should traverse hidden prototype hierachy as well.
974static bool CheckElementAccess(JSObject* obj,
975 uint32_t index,
976 v8::AccessType access_type) {
977 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000978 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000979 return false;
980 }
981
982 return true;
983}
984
985
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000986// Enumerator used as indices into the array returned from GetOwnProperty
987enum PropertyDescriptorIndices {
988 IS_ACCESSOR_INDEX,
989 VALUE_INDEX,
990 GETTER_INDEX,
991 SETTER_INDEX,
992 WRITABLE_INDEX,
993 ENUMERABLE_INDEX,
994 CONFIGURABLE_INDEX,
995 DESCRIPTOR_SIZE
996};
997
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000998// Returns an array with the property description:
999// if args[1] is not a property on args[0]
1000// returns undefined
1001// if args[1] is a data property on args[0]
1002// [false, value, Writeable, Enumerable, Configurable]
1003// if args[1] is an accessor on args[0]
1004// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001005RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001006 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 Heap* heap = isolate->heap();
1008 HandleScope scope(isolate);
1009 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
1010 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001011 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001012 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1013 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001014
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001015 // This could be an element.
1016 uint32_t index;
1017 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001018 switch (obj->HasLocalElement(index)) {
1019 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001021
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001022 case JSObject::STRING_CHARACTER_ELEMENT: {
1023 // Special handling of string objects according to ECMAScript 5
1024 // 15.5.5.2. Note that this might be a string object with elements
1025 // other than the actual string value. This is covered by the
1026 // subsequent cases.
1027 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1028 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001029 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001030
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001031 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001032 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001033 elms->set(WRITABLE_INDEX, heap->false_value());
1034 elms->set(ENUMERABLE_INDEX, heap->false_value());
1035 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001036 return *desc;
1037 }
1038
1039 case JSObject::INTERCEPTED_ELEMENT:
1040 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001041 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001042 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001043 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001044 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001045 elms->set(WRITABLE_INDEX, heap->true_value());
1046 elms->set(ENUMERABLE_INDEX, heap->true_value());
1047 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001048 return *desc;
1049 }
1050
1051 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001052 Handle<JSObject> holder = obj;
1053 if (obj->IsJSGlobalProxy()) {
1054 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001055 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001056 ASSERT(proto->IsJSGlobalObject());
1057 holder = Handle<JSObject>(JSObject::cast(proto));
1058 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001059 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001060 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001061 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001062 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001063 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001064 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001065 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001066 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001067 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 PropertyDetails details = dictionary->DetailsAt(entry);
1069 switch (details.type()) {
1070 case CALLBACKS: {
1071 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001072 AccessorPair* accessors =
1073 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001074 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001075 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001076 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001077 }
1078 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001079 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001080 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001081 break;
1082 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001083 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001084 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001085 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001086 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001087 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001088 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001089 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001090 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001091 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001092 default:
1093 UNREACHABLE();
1094 break;
1095 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001096 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1097 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001098 return *desc;
1099 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001100 }
1101 }
1102
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001103 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001104 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001105
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001106 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001107 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001108 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001109
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001110 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001111 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 }
1113
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001114 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1115 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001116
1117 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001118 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001119
1120 if (is_js_accessor) {
1121 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001122 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001123
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001124 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001125 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001126 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001127 }
1128 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001129 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001130 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001131 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001132 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1133 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001134
1135 PropertyAttributes attrs;
1136 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001137 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001138 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1139 if (!maybe_value->ToObject(&value)) return maybe_value;
1140 }
1141 elms->set(VALUE_INDEX, value);
1142 }
1143
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001144 return *desc;
1145}
1146
1147
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001148RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001149 ASSERT(args.length() == 1);
1150 CONVERT_CHECKED(JSObject, obj, args[0]);
1151 return obj->PreventExtensions();
1152}
1153
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001156 ASSERT(args.length() == 1);
1157 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001158 if (obj->IsJSGlobalProxy()) {
1159 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001160 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001161 ASSERT(proto->IsJSGlobalObject());
1162 obj = JSObject::cast(proto);
1163 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001164 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001165}
1166
1167
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001168RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001169 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001170 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001171 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1172 CONVERT_ARG_CHECKED(String, pattern, 1);
1173 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001174 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1175 if (result.is_null()) return Failure::Exception();
1176 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001177}
1178
1179
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001180RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001181 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001182 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001183 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001184 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001185}
1186
1187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001188RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001189 ASSERT(args.length() == 1);
1190 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001191 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001192 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001193}
1194
1195
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001196RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001197 ASSERT(args.length() == 2);
1198 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001200 int index = field->value();
1201 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1202 InstanceType type = templ->map()->instance_type();
1203 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1204 type == OBJECT_TEMPLATE_INFO_TYPE);
1205 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001206 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001207 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1208 } else {
1209 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1210 }
1211 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001212}
1213
1214
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001215RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001216 ASSERT(args.length() == 1);
1217 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001218 Map* old_map = object->map();
1219 bool needs_access_checks = old_map->is_access_check_needed();
1220 if (needs_access_checks) {
1221 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001222 Object* new_map;
1223 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1224 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1225 }
ager@chromium.org32912102009-01-16 10:38:43 +00001226
1227 Map::cast(new_map)->set_is_access_check_needed(false);
1228 object->set_map(Map::cast(new_map));
1229 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001230 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001231}
1232
1233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001234RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001235 ASSERT(args.length() == 1);
1236 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001237 Map* old_map = object->map();
1238 if (!old_map->is_access_check_needed()) {
1239 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001240 Object* new_map;
1241 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1242 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1243 }
ager@chromium.org32912102009-01-16 10:38:43 +00001244
1245 Map::cast(new_map)->set_is_access_check_needed(true);
1246 object->set_map(Map::cast(new_map));
1247 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001248 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001249}
1250
1251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001252static Failure* ThrowRedeclarationError(Isolate* isolate,
1253 const char* type,
1254 Handle<String> name) {
1255 HandleScope scope(isolate);
1256 Handle<Object> type_handle =
1257 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001258 Handle<Object> args[2] = { type_handle, name };
1259 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001260 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1261 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262}
1263
1264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001265RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001266 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 HandleScope scope(isolate);
1268 Handle<GlobalObject> global = Handle<GlobalObject>(
1269 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001270
ager@chromium.org3811b432009-10-28 14:53:37 +00001271 Handle<Context> context = args.at<Context>(0);
1272 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001275 // Traverse the name/value pairs and set the properties.
1276 int length = pairs->length();
1277 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001278 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001279 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001280 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001281
1282 // We have to declare a global const property. To capture we only
1283 // assign to it when evaluating the assignment for "const x =
1284 // <expr>" the initial value is the hole.
1285 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001286 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001287 if (value->IsUndefined() || is_const_property) {
1288 // Lookup the property in the global object, and don't set the
1289 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001290 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 global->Lookup(*name, &lookup);
1292 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001293 // We found an existing property. Unless it was an interceptor
1294 // that claims the property is absent, skip this declaration.
1295 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001296 continue;
1297 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001298 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1299 if (attributes != ABSENT) {
1300 continue;
1301 }
1302 // Fall-through and introduce the absent property by using
1303 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001304 }
1305 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001306 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001307 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001308 Handle<SharedFunctionInfo> shared =
1309 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001310 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001311 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1312 context,
1313 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001314 value = function;
1315 }
1316
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001317 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001318 global->LocalLookup(*name, &lookup);
1319
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001320 // Compute the property attributes. According to ECMA-262, section
1321 // 13, page 71, the property must be read-only and
1322 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1323 // property as read-only, so we don't either.
1324 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001325 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001326 attr |= DONT_DELETE;
1327 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001328 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001329 if (is_const_property || (is_native && is_function_declaration)) {
1330 attr |= READ_ONLY;
1331 }
1332
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001333 // Safari does not allow the invocation of callback setters for
1334 // function declarations. To mimic this behavior, we do not allow
1335 // the invocation of setters for function values. This makes a
1336 // difference for global functions with the same names as event
1337 // handlers such as "function onload() {}". Firefox does call the
1338 // onload setter in those case and Safari does not. We follow
1339 // Safari for compatibility.
1340 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001341 // Do not change DONT_DELETE to false from true.
1342 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001343 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001344 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001345 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1346
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001347 RETURN_IF_EMPTY_HANDLE(
1348 isolate,
1349 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1350 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001351 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001352 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1353 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1354 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001355 RETURN_IF_EMPTY_HANDLE(
1356 isolate,
1357 JSReceiver::SetProperty(global, name, value,
1358 static_cast<PropertyAttributes>(attr),
1359 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001360 }
1361 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001362
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001363 ASSERT(!isolate->has_pending_exception());
1364 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001365}
1366
1367
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001368RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001369 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001370 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001371
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001372 // Declarations are always made in a function or global context. In the
1373 // case of eval code, the context passed is the context of the caller,
1374 // which may be some nested context and not the declaration context.
1375 RUNTIME_ASSERT(args[0]->IsContext());
1376 Handle<Context> context(Context::cast(args[0])->declaration_context());
1377
ager@chromium.org7c537e22008-10-16 08:43:32 +00001378 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001379 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001380 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001381 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001382
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001383 int index;
1384 PropertyAttributes attributes;
1385 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001386 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001387 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001388 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001389
1390 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001391 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001392 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1393 // Functions are not read-only.
1394 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1395 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001396 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001397 }
1398
1399 // Initialize it if necessary.
1400 if (*initial_value != NULL) {
1401 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001402 ASSERT(holder.is_identical_to(context));
1403 if (((attributes & READ_ONLY) == 0) ||
1404 context->get(index)->IsTheHole()) {
1405 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001406 }
1407 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001408 // Slow case: The property is in the context extension object of a
1409 // function context or the global object of a global context.
1410 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001411 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001412 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001413 JSReceiver::SetProperty(object, name, initial_value, mode,
1414 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001415 }
1416 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001417
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001418 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001419 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001420 // "declared" in the function context's extension context or as a
1421 // property of the the global object.
1422 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001423 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001425 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001426 // Context extension objects are allocated lazily.
1427 ASSERT(context->IsFunctionContext());
1428 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001429 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001430 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001431 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001432 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001433
ager@chromium.org7c537e22008-10-16 08:43:32 +00001434 // Declare the property by setting it to the initial value if provided,
1435 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1436 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001437 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001439 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001440 // Declaring a const context slot is a conflicting declaration if
1441 // there is a callback with that name in a prototype. It is
1442 // allowed to introduce const variables in
1443 // JSContextExtensionObjects. They are treated specially in
1444 // SetProperty and no setters are invoked for those since they are
1445 // not real JSObjects.
1446 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001447 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001448 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001449 object->Lookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001450 if (lookup.IsFound() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001451 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001452 }
1453 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001454 RETURN_IF_EMPTY_HANDLE(
1455 isolate,
1456 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001457 }
1458
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001459 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460}
1461
1462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001463RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001464 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001465 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001466 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001467 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001468
1469 // Determine if we need to assign to the variable if it already
1470 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001471 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1472 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001473
1474 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001475 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001476 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001477 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1478 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1479 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001480
1481 // According to ECMA-262, section 12.2, page 62, the property must
1482 // not be deletable.
1483 PropertyAttributes attributes = DONT_DELETE;
1484
1485 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001486 // there, there is a property with this name in the prototype chain.
1487 // We follow Safari and Firefox behavior and only set the property
1488 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001489 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001490 // Note that objects can have hidden prototypes, so we need to traverse
1491 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001492 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001493 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001494 while (object->IsJSObject() &&
1495 JSObject::cast(object)->map()->is_hidden_prototype()) {
1496 JSObject* raw_holder = JSObject::cast(object);
1497 raw_holder->LocalLookup(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001498 if (lookup.IsFound() && lookup.type() == INTERCEPTOR) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001499 HandleScope handle_scope(isolate);
1500 Handle<JSObject> holder(raw_holder);
1501 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1502 // Update the raw pointer in case it's changed due to GC.
1503 raw_holder = *holder;
1504 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1505 // Found an interceptor that's not read only.
1506 if (assign) {
1507 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001508 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001509 } else {
1510 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001511 }
1512 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001513 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001514 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001515 }
1516
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001517 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001518 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001519 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001520 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001521 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523}
1524
1525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001526RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001527 // All constants are declared with an initial value. The name
1528 // of the constant is the first argument and the initial value
1529 // is the second.
1530 RUNTIME_ASSERT(args.length() == 2);
1531 CONVERT_ARG_CHECKED(String, name, 0);
1532 Handle<Object> value = args.at<Object>(1);
1533
1534 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001535 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001536
1537 // According to ECMA-262, section 12.2, page 62, the property must
1538 // not be deletable. Since it's a const, it must be READ_ONLY too.
1539 PropertyAttributes attributes =
1540 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1541
1542 // Lookup the property locally in the global object. If it isn't
1543 // there, we add the property and take special precautions to always
1544 // add it as a local property even in case of callbacks in the
1545 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001546 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001547 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001548 global->LocalLookup(*name, &lookup);
1549 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001550 return global->SetLocalPropertyIgnoreAttributes(*name,
1551 *value,
1552 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001553 }
1554
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001555 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001557 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001558 HandleScope handle_scope(isolate);
1559 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001561 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001562 // property through an interceptor and only do it if it's
1563 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001564 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001565 RETURN_IF_EMPTY_HANDLE(
1566 isolate,
1567 JSReceiver::SetProperty(global, name, value, attributes,
1568 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001569 return *value;
1570 }
1571
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001572 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001573 // constant. For now, we determine this by checking if the
1574 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001575 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001576 PropertyType type = lookup.type();
1577 if (type == FIELD) {
1578 FixedArray* properties = global->properties();
1579 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001580 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001581 properties->set(index, *value);
1582 }
1583 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001584 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1585 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001586 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001587 }
1588 } else {
1589 // Ignore re-initialization of constants that have already been
1590 // assigned a function value.
1591 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1592 }
1593
1594 // Use the set value as the result of the operation.
1595 return *value;
1596}
1597
1598
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001599RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001600 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001601 ASSERT(args.length() == 3);
1602
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001603 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001604 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001606 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607 RUNTIME_ASSERT(args[1]->IsContext());
1608 Handle<Context> context(Context::cast(args[1])->declaration_context());
1609
1610 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001611
1612 int index;
1613 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001614 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001615 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001616 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001617 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001618
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001619 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001620 ASSERT(holder->IsContext());
1621 // Property was found in a context. Perform the assignment if we
1622 // found some non-constant or an uninitialized constant.
1623 Handle<Context> context = Handle<Context>::cast(holder);
1624 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1625 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001626 }
1627 return *value;
1628 }
1629
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001630 // The property could not be found, we introduce it as a property of the
1631 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001632 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001633 Handle<JSObject> global = Handle<JSObject>(
1634 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001635 // Strict mode not needed (const disallowed in strict mode).
1636 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001637 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001638 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001639 return *value;
1640 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001641
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001642 // The property was present in some function's context extension object,
1643 // as a property on the subject of a with, or as a property of the global
1644 // object.
1645 //
1646 // In most situations, eval-introduced consts should still be present in
1647 // the context extension object. However, because declaration and
1648 // initialization are separate, the property might have been deleted
1649 // before we reach the initialization point.
1650 //
1651 // Example:
1652 //
1653 // function f() { eval("delete x; const x;"); }
1654 //
1655 // In that case, the initialization behaves like a normal assignment.
1656 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001657
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001658 if (*object == context->extension()) {
1659 // This is the property that was introduced by the const declaration.
1660 // Set it if it hasn't been set before. NOTE: We cannot use
1661 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001662 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001663 object->LocalLookupRealNamedProperty(*name, &lookup);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001664 ASSERT(lookup.IsFound()); // the property was declared
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001665 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1666
1667 PropertyType type = lookup.type();
1668 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001669 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001670 int index = lookup.GetFieldIndex();
1671 if (properties->get(index)->IsTheHole()) {
1672 properties->set(index, *value);
1673 }
1674 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001675 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1676 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001677 }
1678 } else {
1679 // We should not reach here. Any real, named property should be
1680 // either a field or a dictionary slot.
1681 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 }
1683 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001684 // The property was found on some other object. Set it if it is not a
1685 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001686 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001687 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001688 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001689 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001690 JSReceiver::SetProperty(object, name, value, attributes,
1691 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001692 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001693 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001694
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001695 return *value;
1696}
1697
1698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001699RUNTIME_FUNCTION(MaybeObject*,
1700 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001701 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001702 ASSERT(args.length() == 2);
1703 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001704 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001705 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001706 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001707 }
1708 return *object;
1709}
1710
1711
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001712RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001713 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001714 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001715 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1716 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001717 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001718 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001719 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001720 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001721 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001722 RUNTIME_ASSERT(index >= 0);
1723 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001724 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001725 Handle<Object> result = RegExpImpl::Exec(regexp,
1726 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001727 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001728 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001729 if (result.is_null()) return Failure::Exception();
1730 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001731}
1732
1733
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001734RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001735 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001736 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001737 if (elements_count < 0 ||
1738 elements_count > FixedArray::kMaxLength ||
1739 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001740 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001741 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001742 Object* new_object;
1743 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001744 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001745 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1746 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001748 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1749 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001750 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1751 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001752 {
1753 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001754 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001755 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001756 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001757 }
1758 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001759 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001760 array->set_elements(elements);
1761 array->set_length(Smi::FromInt(elements_count));
1762 // Write in-object properties after the length of the array.
1763 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1764 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1765 return array;
1766}
1767
1768
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001769RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770 AssertNoAllocation no_alloc;
1771 ASSERT(args.length() == 5);
1772 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1773 CONVERT_CHECKED(String, source, args[1]);
1774
1775 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001776 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001777
1778 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001779 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001780
1781 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001782 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001783
1784 Map* map = regexp->map();
1785 Object* constructor = map->constructor();
1786 if (constructor->IsJSFunction() &&
1787 JSFunction::cast(constructor)->initial_map() == map) {
1788 // If we still have the original map, set in-object properties directly.
1789 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001790 // Both true and false are immovable immortal objects so no need for write
1791 // barrier.
1792 regexp->InObjectPropertyAtPut(
1793 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1794 regexp->InObjectPropertyAtPut(
1795 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1796 regexp->InObjectPropertyAtPut(
1797 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001798 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1799 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001800 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001801 return regexp;
1802 }
1803
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001804 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001805 PropertyAttributes final =
1806 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1807 PropertyAttributes writable =
1808 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001809 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001810 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001812 source,
1813 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001815 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001816 global,
1817 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001818 ASSERT(!result->IsFailure());
1819 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001820 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001821 ignoreCase,
1822 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001823 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001824 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001825 multiline,
1826 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001827 ASSERT(!result->IsFailure());
1828 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001829 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001830 Smi::FromInt(0),
1831 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001832 ASSERT(!result->IsFailure());
1833 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001834 return regexp;
1835}
1836
1837
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001838RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001839 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001840 ASSERT(args.length() == 1);
1841 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1842 // This is necessary to enable fast checks for absence of elements
1843 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001844 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001845 return Smi::FromInt(0);
1846}
1847
1848
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001849static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1850 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001851 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001852 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001853 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1854 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1855 Handle<JSFunction> optimized =
1856 isolate->factory()->NewFunction(key,
1857 JS_OBJECT_TYPE,
1858 JSObject::kHeaderSize,
1859 code,
1860 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001861 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001862 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001863 return optimized;
1864}
1865
1866
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001867RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001868 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001869 ASSERT(args.length() == 1);
1870 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1871
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001872 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1873 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1874 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1875 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1876 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1877 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1878 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001879
1880 return *holder;
1881}
1882
1883
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001884RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001885 ASSERT(args.length() == 1);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00001886 CONVERT_CHECKED(JSReceiver, callable, args[0]);
1887
1888 if (!callable->IsJSFunction()) {
1889 HandleScope scope(isolate);
1890 bool threw = false;
1891 Handle<Object> delegate =
1892 Execution::TryGetFunctionDelegate(Handle<JSReceiver>(callable), &threw);
1893 if (threw) return Failure::Exception();
1894 callable = JSFunction::cast(*delegate);
1895 }
1896 JSFunction* function = JSFunction::cast(callable);
1897
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001898 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001899 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001900 return isolate->heap()->undefined_value();
1901 }
1902 // Returns undefined for strict or native functions, or
1903 // the associated global receiver for "normal" functions.
1904
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001905 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001906 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001907 return global_context->global()->global_receiver();
1908}
1909
1910
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001911RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001912 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001913 ASSERT(args.length() == 4);
1914 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001915 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001916 Handle<String> pattern = args.at<String>(2);
1917 Handle<String> flags = args.at<String>(3);
1918
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001919 // Get the RegExp function from the context in the literals array.
1920 // This is the RegExp function from the context in which the
1921 // function was created. We do not use the RegExp function from the
1922 // current global context because this might be the RegExp function
1923 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001924 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001925 Handle<JSFunction>(
1926 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001927 // Compute the regular expression literal.
1928 bool has_pending_exception;
1929 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001930 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1931 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001932 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001933 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001934 return Failure::Exception();
1935 }
1936 literals->set(index, *regexp);
1937 return *regexp;
1938}
1939
1940
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001941RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001942 NoHandleAllocation ha;
1943 ASSERT(args.length() == 1);
1944
1945 CONVERT_CHECKED(JSFunction, f, args[0]);
1946 return f->shared()->name();
1947}
1948
1949
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001950RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001951 NoHandleAllocation ha;
1952 ASSERT(args.length() == 2);
1953
1954 CONVERT_CHECKED(JSFunction, f, args[0]);
1955 CONVERT_CHECKED(String, name, args[1]);
1956 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001957 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001958}
1959
1960
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001961RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1962 NoHandleAllocation ha;
1963 ASSERT(args.length() == 1);
1964 CONVERT_CHECKED(JSFunction, f, args[0]);
1965 return isolate->heap()->ToBoolean(
1966 f->shared()->name_should_print_as_anonymous());
1967}
1968
1969
1970RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1971 NoHandleAllocation ha;
1972 ASSERT(args.length() == 1);
1973 CONVERT_CHECKED(JSFunction, f, args[0]);
1974 f->shared()->set_name_should_print_as_anonymous(true);
1975 return isolate->heap()->undefined_value();
1976}
1977
1978
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001979RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001980 NoHandleAllocation ha;
1981 ASSERT(args.length() == 1);
1982
1983 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001984 Object* obj = f->RemovePrototype();
1985 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001986
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001987 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001988}
1989
1990
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001991RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001992 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001993 ASSERT(args.length() == 1);
1994
1995 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001996 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1997 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001998
1999 return *GetScriptWrapper(Handle<Script>::cast(script));
2000}
2001
2002
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002003RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002004 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002005 ASSERT(args.length() == 1);
2006
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00002007 CONVERT_ARG_CHECKED(JSFunction, f, 0);
2008 Handle<SharedFunctionInfo> shared(f->shared());
2009 return *shared->GetSourceCode();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002010}
2011
2012
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002013RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002014 NoHandleAllocation ha;
2015 ASSERT(args.length() == 1);
2016
2017 CONVERT_CHECKED(JSFunction, fun, args[0]);
2018 int pos = fun->shared()->start_position();
2019 return Smi::FromInt(pos);
2020}
2021
2022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002023RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002024 ASSERT(args.length() == 2);
2025
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002026 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002027 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2028
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002029 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2030
2031 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002032 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002033}
2034
2035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002036RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002037 NoHandleAllocation ha;
2038 ASSERT(args.length() == 2);
2039
2040 CONVERT_CHECKED(JSFunction, fun, args[0]);
2041 CONVERT_CHECKED(String, name, args[1]);
2042 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002043 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002044}
2045
2046
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002047RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002048 NoHandleAllocation ha;
2049 ASSERT(args.length() == 2);
2050
2051 CONVERT_CHECKED(JSFunction, fun, args[0]);
2052 CONVERT_CHECKED(Smi, length, args[1]);
2053 fun->shared()->set_length(length->value());
2054 return length;
2055}
2056
2057
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002058RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002059 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002060 ASSERT(args.length() == 2);
2061
2062 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002063 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002064 Object* obj;
2065 { MaybeObject* maybe_obj =
2066 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2067 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2068 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002069 return args[0]; // return TOS
2070}
2071
2072
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002073RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2074 NoHandleAllocation ha;
2075 RUNTIME_ASSERT(args.length() == 1);
2076 CONVERT_CHECKED(JSFunction, function, args[0]);
2077
2078 MaybeObject* maybe_name =
2079 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2080 String* name;
2081 if (!maybe_name->To(&name)) return maybe_name;
2082
2083 if (function->HasFastProperties()) {
2084 // Construct a new field descriptor with updated attributes.
2085 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2086 int index = instance_desc->Search(name);
2087 ASSERT(index != DescriptorArray::kNotFound);
2088 PropertyDetails details(instance_desc->GetDetails(index));
2089 CallbacksDescriptor new_desc(name,
2090 instance_desc->GetValue(index),
2091 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2092 details.index());
2093 // Construct a new field descriptors array containing the new descriptor.
2094 Object* descriptors_unchecked;
2095 { MaybeObject* maybe_descriptors_unchecked =
2096 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2097 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2098 return maybe_descriptors_unchecked;
2099 }
2100 }
2101 DescriptorArray* new_descriptors =
2102 DescriptorArray::cast(descriptors_unchecked);
2103 // Create a new map featuring the new field descriptors array.
2104 Object* map_unchecked;
2105 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2106 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2107 return maybe_map_unchecked;
2108 }
2109 }
2110 Map* new_map = Map::cast(map_unchecked);
2111 new_map->set_instance_descriptors(new_descriptors);
2112 function->set_map(new_map);
2113 } else { // Dictionary properties.
2114 // Directly manipulate the property details.
2115 int entry = function->property_dictionary()->FindEntry(name);
2116 ASSERT(entry != StringDictionary::kNotFound);
2117 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2118 PropertyDetails new_details(
2119 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2120 details.type(),
2121 details.index());
2122 function->property_dictionary()->DetailsAtPut(entry, new_details);
2123 }
2124 return function;
2125}
2126
2127
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002128RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002129 NoHandleAllocation ha;
2130 ASSERT(args.length() == 1);
2131
2132 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002133 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002134}
2135
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002136
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002137RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002138 NoHandleAllocation ha;
2139 ASSERT(args.length() == 1);
2140
2141 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002142 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002143}
2144
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002146RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002147 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002148 ASSERT(args.length() == 2);
2149
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002150 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002151 Handle<Object> code = args.at<Object>(1);
2152
2153 Handle<Context> context(target->context());
2154
2155 if (!code->IsNull()) {
2156 RUNTIME_ASSERT(code->IsJSFunction());
2157 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002158 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002159
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002160 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002161 return Failure::Exception();
2162 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002163 // Since we don't store the source for this we should never
2164 // optimize this.
2165 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002166 // Set the code, scope info, formal parameter count,
2167 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002168 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002169 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002170 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002171 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002173 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002174 // Set the source code of the target function to undefined.
2175 // SetCode is only used for built-in constructors like String,
2176 // Array, and Object, and some web code
2177 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002178 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002179 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002180 // Clear the optimization hints related to the compiled code as these are no
2181 // longer valid when the code is overwritten.
2182 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002183 context = Handle<Context>(fun->context());
2184
2185 // Make sure we get a fresh copy of the literal vector to avoid
2186 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002187 int number_of_literals = fun->NumberOfLiterals();
2188 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002189 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002190 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002191 // Insert the object, regexp and array functions in the literals
2192 // array prefix. These are the functions that will be used when
2193 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002194 literals->set(JSFunction::kLiteralGlobalContextIndex,
2195 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002196 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002197 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002199
2200 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2201 isolate->logger()->LogExistingFunction(
2202 shared, Handle<Code>(shared->code()));
2203 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002204 }
2205
2206 target->set_context(*context);
2207 return *target;
2208}
2209
2210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002211RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002212 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002213 ASSERT(args.length() == 2);
2214 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002215 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002216 RUNTIME_ASSERT(num >= 0);
2217 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002218 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002219}
2220
2221
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002222MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2223 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002224 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002225 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002226 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002227 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002228 }
2229 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002230 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002231}
2232
2233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002234RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002235 NoHandleAllocation ha;
2236 ASSERT(args.length() == 2);
2237
2238 CONVERT_CHECKED(String, subject, args[0]);
2239 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002241
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002242 uint32_t i = 0;
2243 if (index->IsSmi()) {
2244 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002245 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002246 i = value;
2247 } else {
2248 ASSERT(index->IsHeapNumber());
2249 double value = HeapNumber::cast(index)->value();
2250 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002251 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002252
2253 // Flatten the string. If someone wants to get a char at an index
2254 // in a cons string, it is likely that more indices will be
2255 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002256 Object* flat;
2257 { MaybeObject* maybe_flat = subject->TryFlatten();
2258 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2259 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002260 subject = String::cast(flat);
2261
2262 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002263 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002264 }
2265
2266 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002267}
2268
2269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002270RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002271 NoHandleAllocation ha;
2272 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002273 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002274}
2275
lrn@chromium.org25156de2010-04-06 13:10:27 +00002276
2277class FixedArrayBuilder {
2278 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002279 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2280 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002281 length_(0),
2282 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002283 // Require a non-zero initial size. Ensures that doubling the size to
2284 // extend the array will work.
2285 ASSERT(initial_capacity > 0);
2286 }
2287
2288 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2289 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002290 length_(0),
2291 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002292 // Require a non-zero initial size. Ensures that doubling the size to
2293 // extend the array will work.
2294 ASSERT(backing_store->length() > 0);
2295 }
2296
2297 bool HasCapacity(int elements) {
2298 int length = array_->length();
2299 int required_length = length_ + elements;
2300 return (length >= required_length);
2301 }
2302
2303 void EnsureCapacity(int elements) {
2304 int length = array_->length();
2305 int required_length = length_ + elements;
2306 if (length < required_length) {
2307 int new_length = length;
2308 do {
2309 new_length *= 2;
2310 } while (new_length < required_length);
2311 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002312 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002313 array_->CopyTo(0, *extended_array, 0, length_);
2314 array_ = extended_array;
2315 }
2316 }
2317
2318 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002319 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002320 ASSERT(length_ < capacity());
2321 array_->set(length_, value);
2322 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002323 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002324 }
2325
2326 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002327 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002328 ASSERT(length_ < capacity());
2329 array_->set(length_, value);
2330 length_++;
2331 }
2332
2333 Handle<FixedArray> array() {
2334 return array_;
2335 }
2336
2337 int length() {
2338 return length_;
2339 }
2340
2341 int capacity() {
2342 return array_->length();
2343 }
2344
2345 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002346 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002347 result_array->set_length(Smi::FromInt(length_));
2348 return result_array;
2349 }
2350
2351 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002352 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002353 target_array->set_length(Smi::FromInt(length_));
2354 return target_array;
2355 }
2356
2357 private:
2358 Handle<FixedArray> array_;
2359 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002360 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002361};
2362
2363
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002364// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002365const int kStringBuilderConcatHelperLengthBits = 11;
2366const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002367
2368template <typename schar>
2369static inline void StringBuilderConcatHelper(String*,
2370 schar*,
2371 FixedArray*,
2372 int);
2373
lrn@chromium.org25156de2010-04-06 13:10:27 +00002374typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2375 StringBuilderSubstringLength;
2376typedef BitField<int,
2377 kStringBuilderConcatHelperLengthBits,
2378 kStringBuilderConcatHelperPositionBits>
2379 StringBuilderSubstringPosition;
2380
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002381
2382class ReplacementStringBuilder {
2383 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002384 ReplacementStringBuilder(Heap* heap,
2385 Handle<String> subject,
2386 int estimated_part_count)
2387 : heap_(heap),
2388 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002390 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002391 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002392 // Require a non-zero initial size. Ensures that doubling the size to
2393 // extend the array will work.
2394 ASSERT(estimated_part_count > 0);
2395 }
2396
lrn@chromium.org25156de2010-04-06 13:10:27 +00002397 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2398 int from,
2399 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400 ASSERT(from >= 0);
2401 int length = to - from;
2402 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002403 if (StringBuilderSubstringLength::is_valid(length) &&
2404 StringBuilderSubstringPosition::is_valid(from)) {
2405 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2406 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002407 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002409 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002410 builder->Add(Smi::FromInt(-length));
2411 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002412 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002413 }
2414
2415
2416 void EnsureCapacity(int elements) {
2417 array_builder_.EnsureCapacity(elements);
2418 }
2419
2420
2421 void AddSubjectSlice(int from, int to) {
2422 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002423 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002424 }
2425
2426
2427 void AddString(Handle<String> string) {
2428 int length = string->length();
2429 ASSERT(length > 0);
2430 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002431 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 is_ascii_ = false;
2433 }
2434 IncrementCharacterCount(length);
2435 }
2436
2437
2438 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002439 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002440 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002441 }
2442
2443 Handle<String> joined_string;
2444 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002445 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002447 char* char_buffer = seq->GetChars();
2448 StringBuilderConcatHelper(*subject_,
2449 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002450 *array_builder_.array(),
2451 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002452 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002453 } else {
2454 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002455 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002456 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002457 uc16* char_buffer = seq->GetChars();
2458 StringBuilderConcatHelper(*subject_,
2459 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002460 *array_builder_.array(),
2461 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002462 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 }
2464 return joined_string;
2465 }
2466
2467
2468 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002469 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 V8::FatalProcessOutOfMemory("String.replace result too large.");
2471 }
2472 character_count_ += by;
2473 }
2474
lrn@chromium.org25156de2010-04-06 13:10:27 +00002475 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002476 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002477 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002478
lrn@chromium.org25156de2010-04-06 13:10:27 +00002479 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002480 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2481 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002482 }
2483
2484
ager@chromium.org04921a82011-06-27 13:21:41 +00002485 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2486 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002487 }
2488
2489
2490 void AddElement(Object* element) {
2491 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002492 ASSERT(array_builder_.capacity() > array_builder_.length());
2493 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002494 }
2495
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002496 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002497 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002498 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002499 int character_count_;
2500 bool is_ascii_;
2501};
2502
2503
2504class CompiledReplacement {
2505 public:
2506 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002507 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002508
2509 void Compile(Handle<String> replacement,
2510 int capture_count,
2511 int subject_length);
2512
2513 void Apply(ReplacementStringBuilder* builder,
2514 int match_from,
2515 int match_to,
2516 Handle<JSArray> last_match_info);
2517
2518 // Number of distinct parts of the replacement pattern.
2519 int parts() {
2520 return parts_.length();
2521 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002522
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002523 bool simple_hint() {
2524 return simple_hint_;
2525 }
2526
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002527 private:
2528 enum PartType {
2529 SUBJECT_PREFIX = 1,
2530 SUBJECT_SUFFIX,
2531 SUBJECT_CAPTURE,
2532 REPLACEMENT_SUBSTRING,
2533 REPLACEMENT_STRING,
2534
2535 NUMBER_OF_PART_TYPES
2536 };
2537
2538 struct ReplacementPart {
2539 static inline ReplacementPart SubjectMatch() {
2540 return ReplacementPart(SUBJECT_CAPTURE, 0);
2541 }
2542 static inline ReplacementPart SubjectCapture(int capture_index) {
2543 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2544 }
2545 static inline ReplacementPart SubjectPrefix() {
2546 return ReplacementPart(SUBJECT_PREFIX, 0);
2547 }
2548 static inline ReplacementPart SubjectSuffix(int subject_length) {
2549 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2550 }
2551 static inline ReplacementPart ReplacementString() {
2552 return ReplacementPart(REPLACEMENT_STRING, 0);
2553 }
2554 static inline ReplacementPart ReplacementSubString(int from, int to) {
2555 ASSERT(from >= 0);
2556 ASSERT(to > from);
2557 return ReplacementPart(-from, to);
2558 }
2559
2560 // If tag <= 0 then it is the negation of a start index of a substring of
2561 // the replacement pattern, otherwise it's a value from PartType.
2562 ReplacementPart(int tag, int data)
2563 : tag(tag), data(data) {
2564 // Must be non-positive or a PartType value.
2565 ASSERT(tag < NUMBER_OF_PART_TYPES);
2566 }
2567 // Either a value of PartType or a non-positive number that is
2568 // the negation of an index into the replacement string.
2569 int tag;
2570 // The data value's interpretation depends on the value of tag:
2571 // tag == SUBJECT_PREFIX ||
2572 // tag == SUBJECT_SUFFIX: data is unused.
2573 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2574 // tag == REPLACEMENT_SUBSTRING ||
2575 // tag == REPLACEMENT_STRING: data is index into array of substrings
2576 // of the replacement string.
2577 // tag <= 0: Temporary representation of the substring of the replacement
2578 // string ranging over -tag .. data.
2579 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2580 // substring objects.
2581 int data;
2582 };
2583
2584 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002585 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002586 Vector<Char> characters,
2587 int capture_count,
2588 int subject_length) {
2589 int length = characters.length();
2590 int last = 0;
2591 for (int i = 0; i < length; i++) {
2592 Char c = characters[i];
2593 if (c == '$') {
2594 int next_index = i + 1;
2595 if (next_index == length) { // No next character!
2596 break;
2597 }
2598 Char c2 = characters[next_index];
2599 switch (c2) {
2600 case '$':
2601 if (i > last) {
2602 // There is a substring before. Include the first "$".
2603 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2604 last = next_index + 1; // Continue after the second "$".
2605 } else {
2606 // Let the next substring start with the second "$".
2607 last = next_index;
2608 }
2609 i = next_index;
2610 break;
2611 case '`':
2612 if (i > last) {
2613 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2614 }
2615 parts->Add(ReplacementPart::SubjectPrefix());
2616 i = next_index;
2617 last = i + 1;
2618 break;
2619 case '\'':
2620 if (i > last) {
2621 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2622 }
2623 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2624 i = next_index;
2625 last = i + 1;
2626 break;
2627 case '&':
2628 if (i > last) {
2629 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2630 }
2631 parts->Add(ReplacementPart::SubjectMatch());
2632 i = next_index;
2633 last = i + 1;
2634 break;
2635 case '0':
2636 case '1':
2637 case '2':
2638 case '3':
2639 case '4':
2640 case '5':
2641 case '6':
2642 case '7':
2643 case '8':
2644 case '9': {
2645 int capture_ref = c2 - '0';
2646 if (capture_ref > capture_count) {
2647 i = next_index;
2648 continue;
2649 }
2650 int second_digit_index = next_index + 1;
2651 if (second_digit_index < length) {
2652 // Peek ahead to see if we have two digits.
2653 Char c3 = characters[second_digit_index];
2654 if ('0' <= c3 && c3 <= '9') { // Double digits.
2655 int double_digit_ref = capture_ref * 10 + c3 - '0';
2656 if (double_digit_ref <= capture_count) {
2657 next_index = second_digit_index;
2658 capture_ref = double_digit_ref;
2659 }
2660 }
2661 }
2662 if (capture_ref > 0) {
2663 if (i > last) {
2664 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2665 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002666 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002667 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2668 last = next_index + 1;
2669 }
2670 i = next_index;
2671 break;
2672 }
2673 default:
2674 i = next_index;
2675 break;
2676 }
2677 }
2678 }
2679 if (length > last) {
2680 if (last == 0) {
2681 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002682 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002683 } else {
2684 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2685 }
2686 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002687 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002688 }
2689
2690 ZoneList<ReplacementPart> parts_;
2691 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002692 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002693};
2694
2695
2696void CompiledReplacement::Compile(Handle<String> replacement,
2697 int capture_count,
2698 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002699 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002700 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002701 String::FlatContent content = replacement->GetFlatContent();
2702 ASSERT(content.IsFlat());
2703 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002704 simple_hint_ = ParseReplacementPattern(&parts_,
2705 content.ToAsciiVector(),
2706 capture_count,
2707 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002708 } else {
2709 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002710 simple_hint_ = ParseReplacementPattern(&parts_,
2711 content.ToUC16Vector(),
2712 capture_count,
2713 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002714 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002715 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002716 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002717 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002718 int substring_index = 0;
2719 for (int i = 0, n = parts_.length(); i < n; i++) {
2720 int tag = parts_[i].tag;
2721 if (tag <= 0) { // A replacement string slice.
2722 int from = -tag;
2723 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002724 replacement_substrings_.Add(
2725 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002726 parts_[i].tag = REPLACEMENT_SUBSTRING;
2727 parts_[i].data = substring_index;
2728 substring_index++;
2729 } else if (tag == REPLACEMENT_STRING) {
2730 replacement_substrings_.Add(replacement);
2731 parts_[i].data = substring_index;
2732 substring_index++;
2733 }
2734 }
2735}
2736
2737
2738void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2739 int match_from,
2740 int match_to,
2741 Handle<JSArray> last_match_info) {
2742 for (int i = 0, n = parts_.length(); i < n; i++) {
2743 ReplacementPart part = parts_[i];
2744 switch (part.tag) {
2745 case SUBJECT_PREFIX:
2746 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2747 break;
2748 case SUBJECT_SUFFIX: {
2749 int subject_length = part.data;
2750 if (match_to < subject_length) {
2751 builder->AddSubjectSlice(match_to, subject_length);
2752 }
2753 break;
2754 }
2755 case SUBJECT_CAPTURE: {
2756 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002757 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002758 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2759 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2760 if (from >= 0 && to > from) {
2761 builder->AddSubjectSlice(from, to);
2762 }
2763 break;
2764 }
2765 case REPLACEMENT_SUBSTRING:
2766 case REPLACEMENT_STRING:
2767 builder->AddString(replacement_substrings_[part.data]);
2768 break;
2769 default:
2770 UNREACHABLE();
2771 }
2772 }
2773}
2774
2775
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002776void FindAsciiStringIndices(Vector<const char> subject,
2777 char pattern,
2778 ZoneList<int>* indices,
2779 unsigned int limit) {
2780 ASSERT(limit > 0);
2781 // Collect indices of pattern in subject using memchr.
2782 // Stop after finding at most limit values.
2783 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2784 const char* subject_end = subject_start + subject.length();
2785 const char* pos = subject_start;
2786 while (limit > 0) {
2787 pos = reinterpret_cast<const char*>(
2788 memchr(pos, pattern, subject_end - pos));
2789 if (pos == NULL) return;
2790 indices->Add(static_cast<int>(pos - subject_start));
2791 pos++;
2792 limit--;
2793 }
2794}
2795
2796
2797template <typename SubjectChar, typename PatternChar>
2798void FindStringIndices(Isolate* isolate,
2799 Vector<const SubjectChar> subject,
2800 Vector<const PatternChar> pattern,
2801 ZoneList<int>* indices,
2802 unsigned int limit) {
2803 ASSERT(limit > 0);
2804 // Collect indices of pattern in subject.
2805 // Stop after finding at most limit values.
2806 int pattern_length = pattern.length();
2807 int index = 0;
2808 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2809 while (limit > 0) {
2810 index = search.Search(subject, index);
2811 if (index < 0) return;
2812 indices->Add(index);
2813 index += pattern_length;
2814 limit--;
2815 }
2816}
2817
2818
2819void FindStringIndicesDispatch(Isolate* isolate,
2820 String* subject,
2821 String* pattern,
2822 ZoneList<int>* indices,
2823 unsigned int limit) {
2824 {
2825 AssertNoAllocation no_gc;
2826 String::FlatContent subject_content = subject->GetFlatContent();
2827 String::FlatContent pattern_content = pattern->GetFlatContent();
2828 ASSERT(subject_content.IsFlat());
2829 ASSERT(pattern_content.IsFlat());
2830 if (subject_content.IsAscii()) {
2831 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2832 if (pattern_content.IsAscii()) {
2833 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2834 if (pattern_vector.length() == 1) {
2835 FindAsciiStringIndices(subject_vector,
2836 pattern_vector[0],
2837 indices,
2838 limit);
2839 } else {
2840 FindStringIndices(isolate,
2841 subject_vector,
2842 pattern_vector,
2843 indices,
2844 limit);
2845 }
2846 } else {
2847 FindStringIndices(isolate,
2848 subject_vector,
2849 pattern_content.ToUC16Vector(),
2850 indices,
2851 limit);
2852 }
2853 } else {
2854 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002855 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002856 FindStringIndices(isolate,
2857 subject_vector,
2858 pattern_content.ToAsciiVector(),
2859 indices,
2860 limit);
2861 } else {
2862 FindStringIndices(isolate,
2863 subject_vector,
2864 pattern_content.ToUC16Vector(),
2865 indices,
2866 limit);
2867 }
2868 }
2869 }
2870}
2871
2872
2873template<typename ResultSeqString>
2874MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2875 Isolate* isolate,
2876 Handle<String> subject,
2877 Handle<JSRegExp> pattern_regexp,
2878 Handle<String> replacement) {
2879 ASSERT(subject->IsFlat());
2880 ASSERT(replacement->IsFlat());
2881
2882 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2883 ZoneList<int> indices(8);
2884 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2885 String* pattern =
2886 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2887 int subject_len = subject->length();
2888 int pattern_len = pattern->length();
2889 int replacement_len = replacement->length();
2890
2891 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2892
2893 int matches = indices.length();
2894 if (matches == 0) return *subject;
2895
2896 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2897 int subject_pos = 0;
2898 int result_pos = 0;
2899
2900 Handle<ResultSeqString> result;
2901 if (ResultSeqString::kHasAsciiEncoding) {
2902 result = Handle<ResultSeqString>::cast(
2903 isolate->factory()->NewRawAsciiString(result_len));
2904 } else {
2905 result = Handle<ResultSeqString>::cast(
2906 isolate->factory()->NewRawTwoByteString(result_len));
2907 }
2908
2909 for (int i = 0; i < matches; i++) {
2910 // Copy non-matched subject content.
2911 if (subject_pos < indices.at(i)) {
2912 String::WriteToFlat(*subject,
2913 result->GetChars() + result_pos,
2914 subject_pos,
2915 indices.at(i));
2916 result_pos += indices.at(i) - subject_pos;
2917 }
2918
2919 // Replace match.
2920 if (replacement_len > 0) {
2921 String::WriteToFlat(*replacement,
2922 result->GetChars() + result_pos,
2923 0,
2924 replacement_len);
2925 result_pos += replacement_len;
2926 }
2927
2928 subject_pos = indices.at(i) + pattern_len;
2929 }
2930 // Add remaining subject content at the end.
2931 if (subject_pos < subject_len) {
2932 String::WriteToFlat(*subject,
2933 result->GetChars() + result_pos,
2934 subject_pos,
2935 subject_len);
2936 }
2937 return *result;
2938}
2939
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002940
lrn@chromium.org303ada72010-10-27 09:33:13 +00002941MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002942 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002943 String* subject,
2944 JSRegExp* regexp,
2945 String* replacement,
2946 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002947 ASSERT(subject->IsFlat());
2948 ASSERT(replacement->IsFlat());
2949
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002950 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002951
2952 int length = subject->length();
2953 Handle<String> subject_handle(subject);
2954 Handle<JSRegExp> regexp_handle(regexp);
2955 Handle<String> replacement_handle(replacement);
2956 Handle<JSArray> last_match_info_handle(last_match_info);
2957 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2958 subject_handle,
2959 0,
2960 last_match_info_handle);
2961 if (match.is_null()) {
2962 return Failure::Exception();
2963 }
2964 if (match->IsNull()) {
2965 return *subject_handle;
2966 }
2967
2968 int capture_count = regexp_handle->CaptureCount();
2969
2970 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002971 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002972 CompiledReplacement compiled_replacement;
2973 compiled_replacement.Compile(replacement_handle,
2974 capture_count,
2975 length);
2976
2977 bool is_global = regexp_handle->GetFlags().is_global();
2978
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002979 // Shortcut for simple non-regexp global replacements
2980 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002981 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002982 compiled_replacement.simple_hint()) {
2983 if (subject_handle->HasOnlyAsciiChars() &&
2984 replacement_handle->HasOnlyAsciiChars()) {
2985 return StringReplaceStringWithString<SeqAsciiString>(
2986 isolate, subject_handle, regexp_handle, replacement_handle);
2987 } else {
2988 return StringReplaceStringWithString<SeqTwoByteString>(
2989 isolate, subject_handle, regexp_handle, replacement_handle);
2990 }
2991 }
2992
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 // Guessing the number of parts that the final result string is built
2994 // from. Global regexps can match any number of times, so we guess
2995 // conservatively.
2996 int expected_parts =
2997 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002998 ReplacementStringBuilder builder(isolate->heap(),
2999 subject_handle,
3000 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003001
3002 // Index of end of last match.
3003 int prev = 0;
3004
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003005 // Number of parts added by compiled replacement plus preceeding
3006 // string and possibly suffix after last match. It is possible for
3007 // all components to use two elements when encoded as two smis.
3008 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003009 bool matched = true;
3010 do {
3011 ASSERT(last_match_info_handle->HasFastElements());
3012 // Increase the capacity of the builder before entering local handle-scope,
3013 // so its internal buffer can safely allocate a new handle if it grows.
3014 builder.EnsureCapacity(parts_added_per_loop);
3015
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003016 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003017 int start, end;
3018 {
3019 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003020 FixedArray* match_info_array =
3021 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003022
3023 ASSERT_EQ(capture_count * 2 + 2,
3024 RegExpImpl::GetLastCaptureCount(match_info_array));
3025 start = RegExpImpl::GetCapture(match_info_array, 0);
3026 end = RegExpImpl::GetCapture(match_info_array, 1);
3027 }
3028
3029 if (prev < start) {
3030 builder.AddSubjectSlice(prev, start);
3031 }
3032 compiled_replacement.Apply(&builder,
3033 start,
3034 end,
3035 last_match_info_handle);
3036 prev = end;
3037
3038 // Only continue checking for global regexps.
3039 if (!is_global) break;
3040
3041 // Continue from where the match ended, unless it was an empty match.
3042 int next = end;
3043 if (start == end) {
3044 next = end + 1;
3045 if (next > length) break;
3046 }
3047
3048 match = RegExpImpl::Exec(regexp_handle,
3049 subject_handle,
3050 next,
3051 last_match_info_handle);
3052 if (match.is_null()) {
3053 return Failure::Exception();
3054 }
3055 matched = !match->IsNull();
3056 } while (matched);
3057
3058 if (prev < length) {
3059 builder.AddSubjectSlice(prev, length);
3060 }
3061
3062 return *(builder.ToString());
3063}
3064
3065
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003066template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003067MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003068 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003069 String* subject,
3070 JSRegExp* regexp,
3071 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003072 ASSERT(subject->IsFlat());
3073
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003074 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003075
3076 Handle<String> subject_handle(subject);
3077 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003078
3079 // Shortcut for simple non-regexp global replacements
3080 if (regexp_handle->GetFlags().is_global() &&
3081 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3082 Handle<String> empty_string_handle(HEAP->empty_string());
3083 if (subject_handle->HasOnlyAsciiChars()) {
3084 return StringReplaceStringWithString<SeqAsciiString>(
3085 isolate, subject_handle, regexp_handle, empty_string_handle);
3086 } else {
3087 return StringReplaceStringWithString<SeqTwoByteString>(
3088 isolate, subject_handle, regexp_handle, empty_string_handle);
3089 }
3090 }
3091
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003092 Handle<JSArray> last_match_info_handle(last_match_info);
3093 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3094 subject_handle,
3095 0,
3096 last_match_info_handle);
3097 if (match.is_null()) return Failure::Exception();
3098 if (match->IsNull()) return *subject_handle;
3099
3100 ASSERT(last_match_info_handle->HasFastElements());
3101
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003102 int start, end;
3103 {
3104 AssertNoAllocation match_info_array_is_not_in_a_handle;
3105 FixedArray* match_info_array =
3106 FixedArray::cast(last_match_info_handle->elements());
3107
3108 start = RegExpImpl::GetCapture(match_info_array, 0);
3109 end = RegExpImpl::GetCapture(match_info_array, 1);
3110 }
3111
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003112 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003113 int new_length = length - (end - start);
3114 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003115 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003116 }
3117 Handle<ResultSeqString> answer;
3118 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003119 answer = Handle<ResultSeqString>::cast(
3120 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003121 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003122 answer = Handle<ResultSeqString>::cast(
3123 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003124 }
3125
3126 // If the regexp isn't global, only match once.
3127 if (!regexp_handle->GetFlags().is_global()) {
3128 if (start > 0) {
3129 String::WriteToFlat(*subject_handle,
3130 answer->GetChars(),
3131 0,
3132 start);
3133 }
3134 if (end < length) {
3135 String::WriteToFlat(*subject_handle,
3136 answer->GetChars() + start,
3137 end,
3138 length);
3139 }
3140 return *answer;
3141 }
3142
3143 int prev = 0; // Index of end of last match.
3144 int next = 0; // Start of next search (prev unless last match was empty).
3145 int position = 0;
3146
3147 do {
3148 if (prev < start) {
3149 // Add substring subject[prev;start] to answer string.
3150 String::WriteToFlat(*subject_handle,
3151 answer->GetChars() + position,
3152 prev,
3153 start);
3154 position += start - prev;
3155 }
3156 prev = end;
3157 next = end;
3158 // Continue from where the match ended, unless it was an empty match.
3159 if (start == end) {
3160 next++;
3161 if (next > length) break;
3162 }
3163 match = RegExpImpl::Exec(regexp_handle,
3164 subject_handle,
3165 next,
3166 last_match_info_handle);
3167 if (match.is_null()) return Failure::Exception();
3168 if (match->IsNull()) break;
3169
3170 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003171 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003172 {
3173 AssertNoAllocation match_info_array_is_not_in_a_handle;
3174 FixedArray* match_info_array =
3175 FixedArray::cast(last_match_info_handle->elements());
3176 start = RegExpImpl::GetCapture(match_info_array, 0);
3177 end = RegExpImpl::GetCapture(match_info_array, 1);
3178 }
3179 } while (true);
3180
3181 if (prev < length) {
3182 // Add substring subject[prev;length] to answer string.
3183 String::WriteToFlat(*subject_handle,
3184 answer->GetChars() + position,
3185 prev,
3186 length);
3187 position += length - prev;
3188 }
3189
3190 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003191 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003192 }
3193
3194 // Shorten string and fill
3195 int string_size = ResultSeqString::SizeFor(position);
3196 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3197 int delta = allocated_string_size - string_size;
3198
3199 answer->set_length(position);
3200 if (delta == 0) return *answer;
3201
3202 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003203 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003204 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003205 MemoryChunk::IncrementLiveBytesFromMutator(answer->address(), -delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003206 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003207
3208 return *answer;
3209}
3210
3211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003212RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003213 ASSERT(args.length() == 4);
3214
3215 CONVERT_CHECKED(String, subject, args[0]);
3216 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003217 Object* flat_subject;
3218 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3219 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3220 return maybe_flat_subject;
3221 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003222 }
3223 subject = String::cast(flat_subject);
3224 }
3225
3226 CONVERT_CHECKED(String, replacement, args[2]);
3227 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003228 Object* flat_replacement;
3229 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3230 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3231 return maybe_flat_replacement;
3232 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003233 }
3234 replacement = String::cast(flat_replacement);
3235 }
3236
3237 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3238 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3239
3240 ASSERT(last_match_info->HasFastElements());
3241
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003242 if (replacement->length() == 0) {
3243 if (subject->HasOnlyAsciiChars()) {
3244 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003245 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003246 } else {
3247 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003248 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003249 }
3250 }
3251
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003252 return StringReplaceRegExpWithString(isolate,
3253 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003254 regexp,
3255 replacement,
3256 last_match_info);
3257}
3258
3259
ulan@chromium.org2efb9002012-01-19 15:36:35 +00003260Handle<String> Runtime::StringReplaceOneCharWithString(Isolate* isolate,
3261 Handle<String> subject,
3262 Handle<String> search,
3263 Handle<String> replace,
3264 bool* found,
3265 int recursion_limit) {
3266 if (recursion_limit == 0) return Handle<String>::null();
3267 if (subject->IsConsString()) {
3268 ConsString* cons = ConsString::cast(*subject);
3269 Handle<String> first = Handle<String>(cons->first());
3270 Handle<String> second = Handle<String>(cons->second());
3271 Handle<String> new_first =
3272 StringReplaceOneCharWithString(isolate,
3273 first,
3274 search,
3275 replace,
3276 found,
3277 recursion_limit - 1);
3278 if (*found) return isolate->factory()->NewConsString(new_first, second);
3279 if (new_first.is_null()) return new_first;
3280
3281 Handle<String> new_second =
3282 StringReplaceOneCharWithString(isolate,
3283 second,
3284 search,
3285 replace,
3286 found,
3287 recursion_limit - 1);
3288 if (*found) return isolate->factory()->NewConsString(first, new_second);
3289 if (new_second.is_null()) return new_second;
3290
3291 return subject;
3292 } else {
3293 int index = StringMatch(isolate, subject, search, 0);
3294 if (index == -1) return subject;
3295 *found = true;
3296 Handle<String> first = isolate->factory()->NewSubString(subject, 0, index);
3297 Handle<String> cons1 = isolate->factory()->NewConsString(first, replace);
3298 Handle<String> second =
3299 isolate->factory()->NewSubString(subject, index + 1, subject->length());
3300 return isolate->factory()->NewConsString(cons1, second);
3301 }
3302}
3303
3304
3305RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceOneCharWithString) {
3306 ASSERT(args.length() == 3);
3307 HandleScope scope(isolate);
3308 CONVERT_ARG_CHECKED(String, subject, 0);
3309 CONVERT_ARG_CHECKED(String, search, 1);
3310 CONVERT_ARG_CHECKED(String, replace, 2);
3311
3312 // If the cons string tree is too deep, we simply abort the recursion and
3313 // retry with a flattened subject string.
3314 const int kRecursionLimit = 0x1000;
3315 bool found = false;
3316 Handle<String> result =
3317 Runtime::StringReplaceOneCharWithString(isolate,
3318 subject,
3319 search,
3320 replace,
3321 &found,
3322 kRecursionLimit);
3323 if (!result.is_null()) return *result;
3324 return *Runtime::StringReplaceOneCharWithString(isolate,
3325 FlattenGetString(subject),
3326 search,
3327 replace,
3328 &found,
3329 kRecursionLimit);
3330}
3331
3332
ager@chromium.org7c537e22008-10-16 08:43:32 +00003333// Perform string match of pattern on subject, starting at start index.
3334// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003335// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003336int Runtime::StringMatch(Isolate* isolate,
3337 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003338 Handle<String> pat,
3339 int start_index) {
3340 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003341 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003342
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003343 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003344 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003345
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003346 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003347 if (start_index + pattern_length > subject_length) return -1;
3348
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003349 if (!sub->IsFlat()) FlattenString(sub);
3350 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003351
ager@chromium.org7c537e22008-10-16 08:43:32 +00003352 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003353 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003354 String::FlatContent seq_sub = sub->GetFlatContent();
3355 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003356
ager@chromium.org7c537e22008-10-16 08:43:32 +00003357 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003358 if (seq_pat.IsAscii()) {
3359 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3360 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003361 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003362 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003363 pat_vector,
3364 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003365 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003366 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003367 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003368 pat_vector,
3369 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003370 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003371 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3372 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003373 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003374 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003375 pat_vector,
3376 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003377 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003378 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003379 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003380 pat_vector,
3381 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003382}
3383
3384
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003385RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003386 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003387 ASSERT(args.length() == 3);
3388
ager@chromium.org7c537e22008-10-16 08:43:32 +00003389 CONVERT_ARG_CHECKED(String, sub, 0);
3390 CONVERT_ARG_CHECKED(String, pat, 1);
3391
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003392 Object* index = args[2];
3393 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003394 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003395
ager@chromium.org870a0b62008-11-04 11:43:05 +00003396 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003397 int position =
3398 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003399 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003400}
3401
3402
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003403template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003404static int StringMatchBackwards(Vector<const schar> subject,
3405 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003406 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003407 int pattern_length = pattern.length();
3408 ASSERT(pattern_length >= 1);
3409 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003410
3411 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003412 for (int i = 0; i < pattern_length; i++) {
3413 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003414 if (c > String::kMaxAsciiCharCode) {
3415 return -1;
3416 }
3417 }
3418 }
3419
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003420 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003421 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003422 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003423 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003424 while (j < pattern_length) {
3425 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003426 break;
3427 }
3428 j++;
3429 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003430 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003431 return i;
3432 }
3433 }
3434 return -1;
3435}
3436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003437RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003438 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003439 ASSERT(args.length() == 3);
3440
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003441 CONVERT_ARG_CHECKED(String, sub, 0);
3442 CONVERT_ARG_CHECKED(String, pat, 1);
3443
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003444 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003445 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003446 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003447
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003448 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003449 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003450
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003451 if (start_index + pat_length > sub_length) {
3452 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003453 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003454
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003455 if (pat_length == 0) {
3456 return Smi::FromInt(start_index);
3457 }
3458
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003459 if (!sub->IsFlat()) FlattenString(sub);
3460 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003461
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003462 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003463 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3464
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003465 String::FlatContent sub_content = sub->GetFlatContent();
3466 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003467
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003468 if (pat_content.IsAscii()) {
3469 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3470 if (sub_content.IsAscii()) {
3471 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003472 pat_vector,
3473 start_index);
3474 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003475 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003476 pat_vector,
3477 start_index);
3478 }
3479 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003480 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3481 if (sub_content.IsAscii()) {
3482 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003483 pat_vector,
3484 start_index);
3485 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003486 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003487 pat_vector,
3488 start_index);
3489 }
3490 }
3491
3492 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003493}
3494
3495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003496RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003497 NoHandleAllocation ha;
3498 ASSERT(args.length() == 2);
3499
3500 CONVERT_CHECKED(String, str1, args[0]);
3501 CONVERT_CHECKED(String, str2, args[1]);
3502
3503 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003504 int str1_length = str1->length();
3505 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003506
3507 // Decide trivial cases without flattening.
3508 if (str1_length == 0) {
3509 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3510 return Smi::FromInt(-str2_length);
3511 } else {
3512 if (str2_length == 0) return Smi::FromInt(str1_length);
3513 }
3514
3515 int end = str1_length < str2_length ? str1_length : str2_length;
3516
3517 // No need to flatten if we are going to find the answer on the first
3518 // character. At this point we know there is at least one character
3519 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003520 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003521 if (d != 0) return Smi::FromInt(d);
3522
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003523 str1->TryFlatten();
3524 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003525
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003526 StringInputBuffer& buf1 =
3527 *isolate->runtime_state()->string_locale_compare_buf1();
3528 StringInputBuffer& buf2 =
3529 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003530
3531 buf1.Reset(str1);
3532 buf2.Reset(str2);
3533
3534 for (int i = 0; i < end; i++) {
3535 uint16_t char1 = buf1.GetNext();
3536 uint16_t char2 = buf2.GetNext();
3537 if (char1 != char2) return Smi::FromInt(char1 - char2);
3538 }
3539
3540 return Smi::FromInt(str1_length - str2_length);
3541}
3542
3543
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003544RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003545 NoHandleAllocation ha;
3546 ASSERT(args.length() == 3);
3547
3548 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003549 int start, end;
3550 // We have a fast integer-only case here to avoid a conversion to double in
3551 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003552 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3553 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3554 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3555 start = from_number;
3556 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003557 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003558 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3559 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003560 start = FastD2I(from_number);
3561 end = FastD2I(to_number);
3562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003563 RUNTIME_ASSERT(end >= start);
3564 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003565 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003566 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003567 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003568}
3569
3570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003571RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003572 ASSERT_EQ(3, args.length());
3573
3574 CONVERT_ARG_CHECKED(String, subject, 0);
3575 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3576 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3577 HandleScope handles;
3578
3579 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3580
3581 if (match.is_null()) {
3582 return Failure::Exception();
3583 }
3584 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003585 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003586 }
3587 int length = subject->length();
3588
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003589 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003590 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003591 int start;
3592 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003593 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003594 {
3595 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003596 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003597 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3598 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3599 }
3600 offsets.Add(start);
3601 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003602 if (start == end) if (++end > length) break;
3603 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003604 if (match.is_null()) {
3605 return Failure::Exception();
3606 }
3607 } while (!match->IsNull());
3608 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003609 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003610 Handle<String> substring = isolate->factory()->
3611 NewSubString(subject, offsets.at(0), offsets.at(1));
3612 elements->set(0, *substring);
3613 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003614 int from = offsets.at(i * 2);
3615 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003616 Handle<String> substring = isolate->factory()->
3617 NewProperSubString(subject, from, to);
3618 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003619 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003620 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003621 result->set_length(Smi::FromInt(matches));
3622 return *result;
3623}
3624
3625
lrn@chromium.org25156de2010-04-06 13:10:27 +00003626// Two smis before and after the match, for very long strings.
3627const int kMaxBuilderEntriesPerRegExpMatch = 5;
3628
3629
3630static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3631 Handle<JSArray> last_match_info,
3632 int match_start,
3633 int match_end) {
3634 // Fill last_match_info with a single capture.
3635 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3636 AssertNoAllocation no_gc;
3637 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3638 RegExpImpl::SetLastCaptureCount(elements, 2);
3639 RegExpImpl::SetLastInput(elements, *subject);
3640 RegExpImpl::SetLastSubject(elements, *subject);
3641 RegExpImpl::SetCapture(elements, 0, match_start);
3642 RegExpImpl::SetCapture(elements, 1, match_end);
3643}
3644
3645
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003646template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003647static bool SearchStringMultiple(Isolate* isolate,
3648 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003649 Vector<const PatternChar> pattern,
3650 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003651 FixedArrayBuilder* builder,
3652 int* match_pos) {
3653 int pos = *match_pos;
3654 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003655 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003656 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003657 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003658 while (pos <= max_search_start) {
3659 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3660 *match_pos = pos;
3661 return false;
3662 }
3663 // Position of end of previous match.
3664 int match_end = pos + pattern_length;
3665 int new_pos = search.Search(subject, match_end);
3666 if (new_pos >= 0) {
3667 // A match.
3668 if (new_pos > match_end) {
3669 ReplacementStringBuilder::AddSubjectSlice(builder,
3670 match_end,
3671 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003672 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003673 pos = new_pos;
3674 builder->Add(pattern_string);
3675 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003676 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003677 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003678 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003679
lrn@chromium.org25156de2010-04-06 13:10:27 +00003680 if (pos < max_search_start) {
3681 ReplacementStringBuilder::AddSubjectSlice(builder,
3682 pos + pattern_length,
3683 subject_length);
3684 }
3685 *match_pos = pos;
3686 return true;
3687}
3688
3689
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003690static bool SearchStringMultiple(Isolate* isolate,
3691 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003692 Handle<String> pattern,
3693 Handle<JSArray> last_match_info,
3694 FixedArrayBuilder* builder) {
3695 ASSERT(subject->IsFlat());
3696 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003697
3698 // Treating as if a previous match was before first character.
3699 int match_pos = -pattern->length();
3700
3701 for (;;) { // Break when search complete.
3702 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3703 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003704 String::FlatContent subject_content = subject->GetFlatContent();
3705 String::FlatContent pattern_content = pattern->GetFlatContent();
3706 if (subject_content.IsAscii()) {
3707 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3708 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003709 if (SearchStringMultiple(isolate,
3710 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003711 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003712 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713 builder,
3714 &match_pos)) break;
3715 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003716 if (SearchStringMultiple(isolate,
3717 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003718 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003719 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003720 builder,
3721 &match_pos)) break;
3722 }
3723 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003724 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3725 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003726 if (SearchStringMultiple(isolate,
3727 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003728 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003729 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003730 builder,
3731 &match_pos)) break;
3732 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 if (SearchStringMultiple(isolate,
3734 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003735 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003736 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003737 builder,
3738 &match_pos)) break;
3739 }
3740 }
3741 }
3742
3743 if (match_pos >= 0) {
3744 SetLastMatchInfoNoCaptures(subject,
3745 last_match_info,
3746 match_pos,
3747 match_pos + pattern->length());
3748 return true;
3749 }
3750 return false; // No matches at all.
3751}
3752
3753
3754static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003755 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003756 Handle<String> subject,
3757 Handle<JSRegExp> regexp,
3758 Handle<JSArray> last_match_array,
3759 FixedArrayBuilder* builder) {
3760 ASSERT(subject->IsFlat());
3761 int match_start = -1;
3762 int match_end = 0;
3763 int pos = 0;
3764 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3765 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3766
3767 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003768 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003769 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003770 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003771
3772 for (;;) { // Break on failure, return on exception.
3773 RegExpImpl::IrregexpResult result =
3774 RegExpImpl::IrregexpExecOnce(regexp,
3775 subject,
3776 pos,
3777 register_vector);
3778 if (result == RegExpImpl::RE_SUCCESS) {
3779 match_start = register_vector[0];
3780 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3781 if (match_end < match_start) {
3782 ReplacementStringBuilder::AddSubjectSlice(builder,
3783 match_end,
3784 match_start);
3785 }
3786 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003787 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003788 if (!first) {
3789 builder->Add(*isolate->factory()->NewProperSubString(subject,
3790 match_start,
3791 match_end));
3792 } else {
3793 builder->Add(*isolate->factory()->NewSubString(subject,
3794 match_start,
3795 match_end));
3796 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003797 if (match_start != match_end) {
3798 pos = match_end;
3799 } else {
3800 pos = match_end + 1;
3801 if (pos > subject_length) break;
3802 }
3803 } else if (result == RegExpImpl::RE_FAILURE) {
3804 break;
3805 } else {
3806 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3807 return result;
3808 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003809 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003810 }
3811
3812 if (match_start >= 0) {
3813 if (match_end < subject_length) {
3814 ReplacementStringBuilder::AddSubjectSlice(builder,
3815 match_end,
3816 subject_length);
3817 }
3818 SetLastMatchInfoNoCaptures(subject,
3819 last_match_array,
3820 match_start,
3821 match_end);
3822 return RegExpImpl::RE_SUCCESS;
3823 } else {
3824 return RegExpImpl::RE_FAILURE; // No matches at all.
3825 }
3826}
3827
3828
3829static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003830 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003831 Handle<String> subject,
3832 Handle<JSRegExp> regexp,
3833 Handle<JSArray> last_match_array,
3834 FixedArrayBuilder* builder) {
3835
3836 ASSERT(subject->IsFlat());
3837 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3838 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3839
3840 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003841 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003842
3843 RegExpImpl::IrregexpResult result =
3844 RegExpImpl::IrregexpExecOnce(regexp,
3845 subject,
3846 0,
3847 register_vector);
3848
3849 int capture_count = regexp->CaptureCount();
3850 int subject_length = subject->length();
3851
3852 // Position to search from.
3853 int pos = 0;
3854 // End of previous match. Differs from pos if match was empty.
3855 int match_end = 0;
3856 if (result == RegExpImpl::RE_SUCCESS) {
3857 // Need to keep a copy of the previous match for creating last_match_info
3858 // at the end, so we have two vectors that we swap between.
3859 OffsetsVector registers2(required_registers);
3860 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003861 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003862 do {
3863 int match_start = register_vector[0];
3864 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3865 if (match_end < match_start) {
3866 ReplacementStringBuilder::AddSubjectSlice(builder,
3867 match_end,
3868 match_start);
3869 }
3870 match_end = register_vector[1];
3871
3872 {
3873 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003874 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003875 // Arguments array to replace function is match, captures, index and
3876 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003877 Handle<FixedArray> elements =
3878 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003879 Handle<String> match;
3880 if (!first) {
3881 match = isolate->factory()->NewProperSubString(subject,
3882 match_start,
3883 match_end);
3884 } else {
3885 match = isolate->factory()->NewSubString(subject,
3886 match_start,
3887 match_end);
3888 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003889 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003890 for (int i = 1; i <= capture_count; i++) {
3891 int start = register_vector[i * 2];
3892 if (start >= 0) {
3893 int end = register_vector[i * 2 + 1];
3894 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003895 Handle<String> substring;
3896 if (!first) {
3897 substring = isolate->factory()->NewProperSubString(subject,
3898 start,
3899 end);
3900 } else {
3901 substring = isolate->factory()->NewSubString(subject, start, end);
3902 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003903 elements->set(i, *substring);
3904 } else {
3905 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003906 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003907 }
3908 }
3909 elements->set(capture_count + 1, Smi::FromInt(match_start));
3910 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003911 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003912 }
3913 // Swap register vectors, so the last successful match is in
3914 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003915 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003916 prev_register_vector = register_vector;
3917 register_vector = tmp;
3918
3919 if (match_end > match_start) {
3920 pos = match_end;
3921 } else {
3922 pos = match_end + 1;
3923 if (pos > subject_length) {
3924 break;
3925 }
3926 }
3927
3928 result = RegExpImpl::IrregexpExecOnce(regexp,
3929 subject,
3930 pos,
3931 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003932 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003933 } while (result == RegExpImpl::RE_SUCCESS);
3934
3935 if (result != RegExpImpl::RE_EXCEPTION) {
3936 // Finished matching, with at least one match.
3937 if (match_end < subject_length) {
3938 ReplacementStringBuilder::AddSubjectSlice(builder,
3939 match_end,
3940 subject_length);
3941 }
3942
3943 int last_match_capture_count = (capture_count + 1) * 2;
3944 int last_match_array_size =
3945 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3946 last_match_array->EnsureSize(last_match_array_size);
3947 AssertNoAllocation no_gc;
3948 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3949 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3950 RegExpImpl::SetLastSubject(elements, *subject);
3951 RegExpImpl::SetLastInput(elements, *subject);
3952 for (int i = 0; i < last_match_capture_count; i++) {
3953 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3954 }
3955 return RegExpImpl::RE_SUCCESS;
3956 }
3957 }
3958 // No matches at all, return failure or exception result directly.
3959 return result;
3960}
3961
3962
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003963RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003964 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003965 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003966
3967 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003968 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003969 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3970 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3971 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3972
3973 ASSERT(last_match_info->HasFastElements());
3974 ASSERT(regexp->GetFlags().is_global());
3975 Handle<FixedArray> result_elements;
3976 if (result_array->HasFastElements()) {
3977 result_elements =
3978 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003979 }
3980 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003981 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003982 }
3983 FixedArrayBuilder builder(result_elements);
3984
3985 if (regexp->TypeTag() == JSRegExp::ATOM) {
3986 Handle<String> pattern(
3987 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003988 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003989 if (SearchStringMultiple(isolate, subject, pattern,
3990 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003991 return *builder.ToJSArray(result_array);
3992 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003993 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003994 }
3995
3996 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3997
3998 RegExpImpl::IrregexpResult result;
3999 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004000 result = SearchRegExpNoCaptureMultiple(isolate,
4001 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00004002 regexp,
4003 last_match_info,
4004 &builder);
4005 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004006 result = SearchRegExpMultiple(isolate,
4007 subject,
4008 regexp,
4009 last_match_info,
4010 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00004011 }
4012 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004013 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00004014 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
4015 return Failure::Exception();
4016}
4017
4018
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004019RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004020 NoHandleAllocation ha;
4021 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004022 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004023 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004024
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004025 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00004026 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004027 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004028 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004029 // Character array used for conversion.
4030 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004031 return isolate->heap()->
4032 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00004033 }
4034 }
4035
4036 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004037 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004038 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004039 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040 }
4041 if (isinf(value)) {
4042 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004043 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004044 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004045 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004047 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004048 MaybeObject* result =
4049 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004050 DeleteArray(str);
4051 return result;
4052}
4053
4054
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004055RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004056 NoHandleAllocation ha;
4057 ASSERT(args.length() == 2);
4058
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004059 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004061 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004062 }
4063 if (isinf(value)) {
4064 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004065 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004066 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004067 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004068 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004069 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004070 int f = FastD2I(f_number);
4071 RUNTIME_ASSERT(f >= 0);
4072 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004073 MaybeObject* res =
4074 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004076 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077}
4078
4079
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004080RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 NoHandleAllocation ha;
4082 ASSERT(args.length() == 2);
4083
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004084 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004085 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004086 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 }
4088 if (isinf(value)) {
4089 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004090 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004092 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004094 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004095 int f = FastD2I(f_number);
4096 RUNTIME_ASSERT(f >= -1 && f <= 20);
4097 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004098 MaybeObject* res =
4099 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004100 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004101 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102}
4103
4104
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004105RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004106 NoHandleAllocation ha;
4107 ASSERT(args.length() == 2);
4108
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004109 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004110 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004111 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 }
4113 if (isinf(value)) {
4114 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004115 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004116 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004117 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004118 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004119 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004120 int f = FastD2I(f_number);
4121 RUNTIME_ASSERT(f >= 1 && f <= 21);
4122 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004123 MaybeObject* res =
4124 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004125 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004126 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004127}
4128
4129
4130// Returns a single character string where first character equals
4131// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004132static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004133 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004134 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004135 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004136 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004137 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004138 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004139}
4140
4141
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004142MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4143 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004144 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004145 // Handle [] indexing on Strings
4146 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004147 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4148 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004149 }
4150
4151 // Handle [] indexing on String objects
4152 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004153 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4154 Handle<Object> result =
4155 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4156 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004157 }
4158
4159 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004160 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004161 }
4162
4163 return object->GetElement(index);
4164}
4165
4166
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004167MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4168 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004169 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004170 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004171
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004172 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004173 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004174 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004175 isolate->factory()->NewTypeError("non_object_property_load",
4176 HandleVector(args, 2));
4177 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004178 }
4179
4180 // Check if the given key is an array index.
4181 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004182 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004183 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004184 }
4185
4186 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004187 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004188 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004189 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004190 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004191 bool has_pending_exception = false;
4192 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004193 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004194 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004195 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004196 }
4197
ager@chromium.org32912102009-01-16 10:38:43 +00004198 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004199 // the element if so.
4200 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004201 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004202 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004203 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004204 }
4205}
4206
4207
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004208RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004209 NoHandleAllocation ha;
4210 ASSERT(args.length() == 2);
4211
4212 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004213 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004214
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004215 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004216}
4217
4218
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004219// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004220RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004221 NoHandleAllocation ha;
4222 ASSERT(args.length() == 2);
4223
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004224 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004225 // itself.
4226 //
4227 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004228 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004229 // global proxy object never has properties. This is the case
4230 // because the global proxy object forwards everything to its hidden
4231 // prototype including local lookups.
4232 //
4233 // Additionally, we need to make sure that we do not cache results
4234 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004235 if (args[0]->IsJSObject()) {
4236 if (!args[0]->IsJSGlobalProxy() &&
4237 !args[0]->IsAccessCheckNeeded() &&
4238 args[1]->IsString()) {
4239 JSObject* receiver = JSObject::cast(args[0]);
4240 String* key = String::cast(args[1]);
4241 if (receiver->HasFastProperties()) {
4242 // Attempt to use lookup cache.
4243 Map* receiver_map = receiver->map();
4244 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4245 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4246 if (offset != -1) {
4247 Object* value = receiver->FastPropertyAt(offset);
4248 return value->IsTheHole()
4249 ? isolate->heap()->undefined_value()
4250 : value;
4251 }
4252 // Lookup cache miss. Perform lookup and update the cache if
4253 // appropriate.
4254 LookupResult result(isolate);
4255 receiver->LocalLookup(key, &result);
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004256 if (result.IsFound() && result.type() == FIELD) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004257 int offset = result.GetFieldIndex();
4258 keyed_lookup_cache->Update(receiver_map, key, offset);
4259 return receiver->FastPropertyAt(offset);
4260 }
4261 } else {
4262 // Attempt dictionary lookup.
4263 StringDictionary* dictionary = receiver->property_dictionary();
4264 int entry = dictionary->FindEntry(key);
4265 if ((entry != StringDictionary::kNotFound) &&
4266 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4267 Object* value = dictionary->ValueAt(entry);
4268 if (!receiver->IsGlobalObject()) return value;
4269 value = JSGlobalPropertyCell::cast(value)->value();
4270 if (!value->IsTheHole()) return value;
4271 // If value is the hole do the general lookup.
4272 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004273 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004274 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4275 // JSObject without a string key. If the key is a Smi, check for a
4276 // definite out-of-bounds access to elements, which is a strong indicator
4277 // that subsequent accesses will also call the runtime. Proactively
4278 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4279 // doubles for those future calls in the case that the elements would
4280 // become FAST_DOUBLE_ELEMENTS.
4281 Handle<JSObject> js_object(args.at<JSObject>(0));
4282 ElementsKind elements_kind = js_object->GetElementsKind();
4283 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4284 elements_kind == FAST_DOUBLE_ELEMENTS) {
4285 FixedArrayBase* elements = js_object->elements();
4286 if (args.at<Smi>(1)->value() >= elements->length()) {
4287 MaybeObject* maybe_object = TransitionElements(js_object,
4288 FAST_ELEMENTS,
4289 isolate);
4290 if (maybe_object->IsFailure()) return maybe_object;
4291 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004292 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004293 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004294 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4295 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004296 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004297 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004298 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004299 if (index >= 0 && index < str->length()) {
4300 Handle<Object> result = GetCharAt(str, index);
4301 return *result;
4302 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004303 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004304
4305 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004306 return Runtime::GetObjectProperty(isolate,
4307 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004308 args.at<Object>(1));
4309}
4310
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004311// Implements part of 8.12.9 DefineOwnProperty.
4312// There are 3 cases that lead here:
4313// Step 4b - define a new accessor property.
4314// Steps 9c & 12 - replace an existing data property with an accessor property.
4315// Step 12 - update an existing accessor property with an accessor or generic
4316// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004317RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004318 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004319 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004320 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4321 CONVERT_CHECKED(String, name, args[1]);
4322 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004323 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004324 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004325
ager@chromium.org5c838252010-02-19 08:53:10 +00004326 int unchecked = flag_attr->value();
4327 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004328 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004329
4330 RUNTIME_ASSERT(!obj->IsNull());
4331 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004332 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4333}
4334
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004335// Implements part of 8.12.9 DefineOwnProperty.
4336// There are 3 cases that lead here:
4337// Step 4a - define a new data property.
4338// Steps 9b & 12 - replace an existing accessor property with a data property.
4339// Step 12 - update an existing data property with a data or generic
4340// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004341RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004342 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004343 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004344 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4345 CONVERT_ARG_CHECKED(String, name, 1);
4346 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004347 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004348
ager@chromium.org5c838252010-02-19 08:53:10 +00004349 int unchecked = flag->value();
4350 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004351 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4352
4353 // Check if this is an element.
4354 uint32_t index;
4355 bool is_element = name->AsArrayIndex(&index);
4356
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004357 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004358 // If elements are in fast case we always implicitly assume that:
4359 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004360 if (is_element && (attr != NONE ||
4361 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004362 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004363 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004364 // We do not need to do access checks here since these has already
4365 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004366 Handle<Object> proto(js_object->GetPrototype());
4367 // If proxy is detached, ignore the assignment. Alternatively,
4368 // we could throw an exception.
4369 if (proto->IsNull()) return *obj_value;
4370 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004371 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004372
4373 // Don't allow element properties to be redefined on objects with external
4374 // array elements.
4375 if (js_object->HasExternalArrayElements()) {
4376 Handle<Object> args[2] = { js_object, name };
4377 Handle<Object> error =
4378 isolate->factory()->NewTypeError("redef_external_array_element",
4379 HandleVector(args, 2));
4380 return isolate->Throw(*error);
4381 }
4382
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004383 Handle<SeededNumberDictionary> dictionary =
4384 JSObject::NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004385 // Make sure that we never go back to fast case.
4386 dictionary->set_requires_slow_elements();
4387 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004388 Handle<SeededNumberDictionary> extended_dictionary =
4389 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004390 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004391 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004392 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4393 } else {
4394 js_object->set_elements(*extended_dictionary);
4395 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004396 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004397 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004398 }
4399
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004400 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004401 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004402
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004403 // Special case for callback properties.
jkummerow@chromium.org05ed9dd2012-01-23 14:42:48 +00004404 if (result.IsFound() && result.type() == CALLBACKS) {
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004405 Object* callback = result.GetCallbackObject();
4406 // To be compatible with Safari we do not change the value on API objects
4407 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4408 // the value.
4409 if (callback->IsAccessorInfo()) {
4410 return isolate->heap()->undefined_value();
4411 }
4412 // Avoid redefining foreign callback as data property, just use the stored
4413 // setter to update the value instead.
4414 // TODO(mstarzinger): So far this only works if property attributes don't
4415 // change, this should be fixed once we cleanup the underlying code.
4416 if (callback->IsForeign() && result.GetAttributes() == attr) {
4417 return js_object->SetPropertyWithCallback(callback,
4418 *name,
4419 *obj_value,
4420 result.holder(),
4421 kStrictMode);
4422 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004423 }
4424
ager@chromium.org5c838252010-02-19 08:53:10 +00004425 // Take special care when attributes are different and there is already
4426 // a property. For simplicity we normalize the property which enables us
4427 // to not worry about changing the instance_descriptor and creating a new
4428 // map. The current version of SetObjectProperty does not handle attributes
4429 // correctly in the case where a property is a field and is reset with
4430 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004431 if (result.IsProperty() &&
4432 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004433 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004434 if (js_object->IsJSGlobalProxy()) {
4435 // Since the result is a property, the prototype will exist so
4436 // we don't have to check for null.
4437 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004438 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004439 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004440 // Use IgnoreAttributes version since a readonly property may be
4441 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004442 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4443 *obj_value,
4444 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004445 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004446
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004447 return Runtime::ForceSetObjectProperty(isolate,
4448 js_object,
4449 name,
4450 obj_value,
4451 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004452}
4453
4454
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004455// Special case for elements if any of the flags are true.
4456// If elements are in fast case we always implicitly assume that:
4457// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4458static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4459 Handle<JSObject> js_object,
4460 uint32_t index,
4461 Handle<Object> value,
4462 PropertyAttributes attr) {
4463 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004464 Handle<SeededNumberDictionary> dictionary =
4465 JSObject::NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004466 // Make sure that we never go back to fast case.
4467 dictionary->set_requires_slow_elements();
4468 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004469 Handle<SeededNumberDictionary> extended_dictionary =
4470 SeededNumberDictionary::Set(dictionary, index, value, details);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004471 if (*extended_dictionary != *dictionary) {
4472 js_object->set_elements(*extended_dictionary);
4473 }
4474 return *value;
4475}
4476
4477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004478MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4479 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004480 Handle<Object> key,
4481 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004482 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004483 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004484 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004485
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004486 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004487 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004488 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004489 isolate->factory()->NewTypeError("non_object_property_store",
4490 HandleVector(args, 2));
4491 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004492 }
4493
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004494 if (object->IsJSProxy()) {
4495 bool has_pending_exception = false;
4496 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4497 if (has_pending_exception) return Failure::Exception();
4498 return JSProxy::cast(*object)->SetProperty(
4499 String::cast(*name), *value, attr, strict_mode);
4500 }
4501
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004502 // If the object isn't a JavaScript object, we ignore the store.
4503 if (!object->IsJSObject()) return *value;
4504
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004505 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4506
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004507 // Check if the given key is an array index.
4508 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004509 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004510 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4511 // of a string using [] notation. We need to support this too in
4512 // JavaScript.
4513 // In the case of a String object we just need to redirect the assignment to
4514 // the underlying string if the index is in range. Since the underlying
4515 // string does nothing with the assignment then we can ignore such
4516 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004517 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004518 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004519 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004520
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004521 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4522 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4523 }
4524
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004525 Handle<Object> result =
4526 JSObject::SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004527 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004528 return *value;
4529 }
4530
4531 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004532 Handle<Object> result;
4533 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004534 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4535 return NormalizeObjectSetElement(isolate,
4536 js_object,
4537 index,
4538 value,
4539 attr);
4540 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004541 result =
4542 JSObject::SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004543 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004544 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004545 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004546 result = JSReceiver::SetProperty(
4547 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004548 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004549 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004550 return *value;
4551 }
4552
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004553 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004554 bool has_pending_exception = false;
4555 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4556 if (has_pending_exception) return Failure::Exception();
4557 Handle<String> name = Handle<String>::cast(converted);
4558
4559 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004560 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004561 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004562 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004563 }
4564}
4565
4566
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004567MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4568 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004569 Handle<Object> key,
4570 Handle<Object> value,
4571 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004572 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004573
4574 // Check if the given key is an array index.
4575 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004576 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004577 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4578 // of a string using [] notation. We need to support this too in
4579 // JavaScript.
4580 // In the case of a String object we just need to redirect the assignment to
4581 // the underlying string if the index is in range. Since the underlying
4582 // string does nothing with the assignment then we can ignore such
4583 // assignments.
4584 if (js_object->IsStringObjectWithCharacterAt(index)) {
4585 return *value;
4586 }
4587
whesse@chromium.org7b260152011-06-20 15:33:18 +00004588 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004589 }
4590
4591 if (key->IsString()) {
4592 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004593 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004594 } else {
4595 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004596 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004597 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4598 *value,
4599 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004600 }
4601 }
4602
4603 // Call-back into JavaScript to convert the key to a string.
4604 bool has_pending_exception = false;
4605 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4606 if (has_pending_exception) return Failure::Exception();
4607 Handle<String> name = Handle<String>::cast(converted);
4608
4609 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004610 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004611 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004612 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004613 }
4614}
4615
4616
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004617MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004618 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004619 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004620 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004621
4622 // Check if the given key is an array index.
4623 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004624 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004625 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4626 // characters of a string using [] notation. In the case of a
4627 // String object we just need to redirect the deletion to the
4628 // underlying string if the index is in range. Since the
4629 // underlying string does nothing with the deletion, we can ignore
4630 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004631 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004632 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004633 }
4634
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004635 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004636 }
4637
4638 Handle<String> key_string;
4639 if (key->IsString()) {
4640 key_string = Handle<String>::cast(key);
4641 } else {
4642 // Call-back into JavaScript to convert the key to a string.
4643 bool has_pending_exception = false;
4644 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4645 if (has_pending_exception) return Failure::Exception();
4646 key_string = Handle<String>::cast(converted);
4647 }
4648
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004649 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004650 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004651}
4652
4653
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004654RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004655 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004656 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004657
4658 Handle<Object> object = args.at<Object>(0);
4659 Handle<Object> key = args.at<Object>(1);
4660 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004661 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004662 RUNTIME_ASSERT(
4663 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004664 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004665 PropertyAttributes attributes =
4666 static_cast<PropertyAttributes>(unchecked_attributes);
4667
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004668 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004669 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004670 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4671 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004672 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004673
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004674 return Runtime::SetObjectProperty(isolate,
4675 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004676 key,
4677 value,
4678 attributes,
4679 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004680}
4681
4682
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004683RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4684 NoHandleAllocation ha;
4685 RUNTIME_ASSERT(args.length() == 1);
4686 Handle<Object> object = args.at<Object>(0);
4687 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4688}
4689
4690
4691RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4692 NoHandleAllocation ha;
4693 RUNTIME_ASSERT(args.length() == 1);
4694 Handle<Object> object = args.at<Object>(0);
4695 return TransitionElements(object, FAST_ELEMENTS, isolate);
4696}
4697
4698
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004699// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004700// This is used to decide if we should transform null and undefined
4701// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004702RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004703 NoHandleAllocation ha;
4704 RUNTIME_ASSERT(args.length() == 1);
4705
4706 Handle<Object> object = args.at<Object>(0);
4707
4708 if (object->IsJSFunction()) {
4709 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004710 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004711 }
4712 return isolate->heap()->undefined_value();
4713}
4714
4715
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004716RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4717 RUNTIME_ASSERT(args.length() == 5);
4718 CONVERT_ARG_CHECKED(JSObject, object, 0);
4719 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4720 Handle<Object> value = args.at<Object>(2);
4721 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4722 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4723 HandleScope scope;
4724
4725 Object* raw_boilerplate_object = literals->get(literal_index);
4726 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4727#if DEBUG
4728 ElementsKind elements_kind = object->GetElementsKind();
4729#endif
4730 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4731 // Smis should never trigger transitions.
4732 ASSERT(!value->IsSmi());
4733
4734 if (value->IsNumber()) {
4735 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004736 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4737 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004738 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4739 FixedDoubleArray* double_array =
4740 FixedDoubleArray::cast(object->elements());
4741 HeapNumber* number = HeapNumber::cast(*value);
4742 double_array->set(store_index, number->Number());
4743 } else {
4744 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4745 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004746 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4747 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004748 FixedArray* object_array =
4749 FixedArray::cast(object->elements());
4750 object_array->set(store_index, *value);
4751 }
4752 return *object;
4753}
4754
4755
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004756// Set a local property, even if it is READ_ONLY. If the property does not
4757// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004758RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004759 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004760 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004761 CONVERT_CHECKED(JSObject, object, args[0]);
4762 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004763 // Compute attributes.
4764 PropertyAttributes attributes = NONE;
4765 if (args.length() == 4) {
4766 CONVERT_CHECKED(Smi, value_obj, args[3]);
4767 int unchecked_value = value_obj->value();
4768 // Only attribute bits should be set.
4769 RUNTIME_ASSERT(
4770 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4771 attributes = static_cast<PropertyAttributes>(unchecked_value);
4772 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004774 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004775 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004776}
4777
4778
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004779RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004780 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004781 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004782
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004783 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004784 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004785 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4786 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004787 ? JSReceiver::STRICT_DELETION
4788 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789}
4790
4791
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004792static Object* HasLocalPropertyImplementation(Isolate* isolate,
4793 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004794 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004795 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004796 // Handle hidden prototypes. If there's a hidden prototype above this thing
4797 // then we have to check it for properties, because they are supposed to
4798 // look like they are on this object.
4799 Handle<Object> proto(object->GetPrototype());
4800 if (proto->IsJSObject() &&
4801 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004802 return HasLocalPropertyImplementation(isolate,
4803 Handle<JSObject>::cast(proto),
4804 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004805 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004806 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004807}
4808
4809
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004810RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004811 NoHandleAllocation ha;
4812 ASSERT(args.length() == 2);
4813 CONVERT_CHECKED(String, key, args[1]);
4814
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004815 uint32_t index;
4816 const bool key_is_array_index = key->AsArrayIndex(&index);
4817
ager@chromium.org9085a012009-05-11 19:22:57 +00004818 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004819 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004820 if (obj->IsJSObject()) {
4821 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004822 // Fast case: either the key is a real named property or it is not
4823 // an array index and there are no interceptors or hidden
4824 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004825 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004826 Map* map = object->map();
4827 if (!key_is_array_index &&
4828 !map->has_named_interceptor() &&
4829 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4830 return isolate->heap()->false_value();
4831 }
4832 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004833 HandleScope scope(isolate);
4834 return HasLocalPropertyImplementation(isolate,
4835 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004836 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004837 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004838 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004839 String* string = String::cast(obj);
4840 if (index < static_cast<uint32_t>(string->length())) {
4841 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004842 }
4843 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004844 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004845}
4846
4847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004848RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004849 NoHandleAllocation na;
4850 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004851 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4852 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004853
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004854 bool result = receiver->HasProperty(key);
4855 if (isolate->has_pending_exception()) return Failure::Exception();
4856 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004857}
4858
4859
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004860RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004861 NoHandleAllocation na;
4862 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004863 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4864 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004865
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004866 bool result = receiver->HasElement(index->value());
4867 if (isolate->has_pending_exception()) return Failure::Exception();
4868 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004869}
4870
4871
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004872RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004873 NoHandleAllocation ha;
4874 ASSERT(args.length() == 2);
4875
4876 CONVERT_CHECKED(JSObject, object, args[0]);
4877 CONVERT_CHECKED(String, key, args[1]);
4878
4879 uint32_t index;
4880 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004881 JSObject::LocalElementType type = object->HasLocalElement(index);
4882 switch (type) {
4883 case JSObject::UNDEFINED_ELEMENT:
4884 case JSObject::STRING_CHARACTER_ELEMENT:
4885 return isolate->heap()->false_value();
4886 case JSObject::INTERCEPTED_ELEMENT:
4887 case JSObject::FAST_ELEMENT:
4888 return isolate->heap()->true_value();
4889 case JSObject::DICTIONARY_ELEMENT: {
4890 if (object->IsJSGlobalProxy()) {
4891 Object* proto = object->GetPrototype();
4892 if (proto->IsNull()) {
4893 return isolate->heap()->false_value();
4894 }
4895 ASSERT(proto->IsJSGlobalObject());
4896 object = JSObject::cast(proto);
4897 }
4898 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004899 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004900 if (elements->map() ==
4901 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004902 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004903 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004904 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004905 }
4906 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004907 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004908 PropertyDetails details = dictionary->DetailsAt(entry);
4909 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4910 }
4911 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004912 }
4913
ager@chromium.org870a0b62008-11-04 11:43:05 +00004914 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004915 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004916}
4917
4918
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004919RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004920 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004921 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004922 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4923 bool threw = false;
4924 Handle<JSArray> result = GetKeysFor(object, &threw);
4925 if (threw) return Failure::Exception();
4926 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004927}
4928
4929
4930// Returns either a FixedArray as Runtime_GetPropertyNames,
4931// or, if the given object has an enum cache that contains
4932// all enumerable properties of the object and its prototypes
4933// have none, the map of the object. This is used to speed up
4934// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004935RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004936 ASSERT(args.length() == 1);
4937
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004938 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004939
4940 if (raw_object->IsSimpleEnum()) return raw_object->map();
4941
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004942 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004943 Handle<JSReceiver> object(raw_object);
4944 bool threw = false;
4945 Handle<FixedArray> content =
4946 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4947 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004948
4949 // Test again, since cache may have been built by preceding call.
4950 if (object->IsSimpleEnum()) return object->map();
4951
4952 return *content;
4953}
4954
4955
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004956// Find the length of the prototype chain that is to to handled as one. If a
4957// prototype object is hidden it is to be viewed as part of the the object it
4958// is prototype for.
4959static int LocalPrototypeChainLength(JSObject* obj) {
4960 int count = 1;
4961 Object* proto = obj->GetPrototype();
4962 while (proto->IsJSObject() &&
4963 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4964 count++;
4965 proto = JSObject::cast(proto)->GetPrototype();
4966 }
4967 return count;
4968}
4969
4970
4971// Return the names of the local named properties.
4972// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004973RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004974 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004975 ASSERT(args.length() == 1);
4976 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004977 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004978 }
4979 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4980
4981 // Skip the global proxy as it has no properties and always delegates to the
4982 // real global object.
4983 if (obj->IsJSGlobalProxy()) {
4984 // Only collect names if access is permitted.
4985 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004986 !isolate->MayNamedAccess(*obj,
4987 isolate->heap()->undefined_value(),
4988 v8::ACCESS_KEYS)) {
4989 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4990 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004991 }
4992 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4993 }
4994
4995 // Find the number of objects making up this.
4996 int length = LocalPrototypeChainLength(*obj);
4997
4998 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004999 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005000 int total_property_count = 0;
5001 Handle<JSObject> jsproto = obj;
5002 for (int i = 0; i < length; i++) {
5003 // Only collect names if access is permitted.
5004 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005005 !isolate->MayNamedAccess(*jsproto,
5006 isolate->heap()->undefined_value(),
5007 v8::ACCESS_KEYS)) {
5008 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
5009 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005010 }
5011 int n;
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +00005012 n = jsproto->NumberOfLocalProperties();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005013 local_property_count[i] = n;
5014 total_property_count += n;
5015 if (i < length - 1) {
5016 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5017 }
5018 }
5019
5020 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005021 Handle<FixedArray> names =
5022 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005023
5024 // Get the property names.
5025 jsproto = obj;
5026 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005027 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005028 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00005029 jsproto->GetLocalPropertyNames(*names, next_copy_index);
5030 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00005031 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005032 proto_with_hidden_properties++;
5033 }
5034 if (i < length - 1) {
5035 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
5036 }
5037 }
5038
5039 // Filter out name of hidden propeties object.
5040 if (proto_with_hidden_properties > 0) {
5041 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005042 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005043 names->length() - proto_with_hidden_properties);
5044 int dest_pos = 0;
5045 for (int i = 0; i < total_property_count; i++) {
5046 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005047 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005048 continue;
5049 }
5050 names->set(dest_pos++, name);
5051 }
5052 }
5053
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005055}
5056
5057
5058// Return the names of the local indexed properties.
5059// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005060RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005061 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005062 ASSERT(args.length() == 1);
5063 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005064 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005065 }
5066 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5067
5068 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005069 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005070 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005071 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005072}
5073
5074
5075// Return information on whether an object has a named or indexed interceptor.
5076// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005077RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005078 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005079 ASSERT(args.length() == 1);
5080 if (!args[0]->IsJSObject()) {
5081 return Smi::FromInt(0);
5082 }
5083 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5084
5085 int result = 0;
5086 if (obj->HasNamedInterceptor()) result |= 2;
5087 if (obj->HasIndexedInterceptor()) result |= 1;
5088
5089 return Smi::FromInt(result);
5090}
5091
5092
5093// Return property names from named interceptor.
5094// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005095RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005096 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005097 ASSERT(args.length() == 1);
5098 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5099
5100 if (obj->HasNamedInterceptor()) {
5101 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5102 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5103 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005104 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005105}
5106
5107
5108// Return element names from indexed interceptor.
5109// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005110RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005111 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005112 ASSERT(args.length() == 1);
5113 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5114
5115 if (obj->HasIndexedInterceptor()) {
5116 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5117 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5118 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005119 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005120}
5121
5122
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005123RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005124 ASSERT_EQ(args.length(), 1);
5125 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005126 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005127 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005128
5129 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005130 // Do access checks before going to the global object.
5131 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005132 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005133 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005134 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5135 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005136 }
5137
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005138 Handle<Object> proto(object->GetPrototype());
5139 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005141 object = Handle<JSObject>::cast(proto);
5142 }
5143
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005144 bool threw = false;
5145 Handle<FixedArray> contents =
5146 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5147 if (threw) return Failure::Exception();
5148
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005149 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5150 // property array and since the result is mutable we have to create
5151 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005152 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005153 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005154 for (int i = 0; i < length; i++) {
5155 Object* entry = contents->get(i);
5156 if (entry->IsString()) {
5157 copy->set(i, entry);
5158 } else {
5159 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005160 HandleScope scope(isolate);
5161 Handle<Object> entry_handle(entry, isolate);
5162 Handle<Object> entry_str =
5163 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005164 copy->set(i, *entry_str);
5165 }
5166 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005167 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005168}
5169
5170
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005171RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005172 NoHandleAllocation ha;
5173 ASSERT(args.length() == 1);
5174
5175 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005176 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005177 it.AdvanceToArgumentsFrame();
5178 JavaScriptFrame* frame = it.frame();
5179
5180 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005181 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005182
5183 // Try to convert the key to an index. If successful and within
5184 // index return the the argument from the frame.
5185 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005186 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187 return frame->GetParameter(index);
5188 }
5189
5190 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005191 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005192 bool exception = false;
5193 Handle<Object> converted =
5194 Execution::ToString(args.at<Object>(0), &exception);
5195 if (exception) return Failure::Exception();
5196 Handle<String> key = Handle<String>::cast(converted);
5197
5198 // Try to convert the string key into an array index.
5199 if (key->AsArrayIndex(&index)) {
5200 if (index < n) {
5201 return frame->GetParameter(index);
5202 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005204 }
5205 }
5206
5207 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005208 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5209 if (key->Equals(isolate->heap()->callee_symbol())) {
5210 Object* function = frame->function();
5211 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005212 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005213 return isolate->Throw(*isolate->factory()->NewTypeError(
5214 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5215 }
5216 return function;
5217 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005218
5219 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005220 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005221}
5222
5223
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005224RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005225 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005226 Object* object = args[0];
5227 return (object->IsJSObject() && !object->IsGlobalObject())
5228 ? JSObject::cast(object)->TransformToFastProperties(0)
5229 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005230}
5231
5232
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005233RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005234 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005235 Object* obj = args[0];
5236 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5237 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5238 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005239}
5240
5241
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005242RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005243 NoHandleAllocation ha;
5244 ASSERT(args.length() == 1);
5245
5246 return args[0]->ToBoolean();
5247}
5248
5249
5250// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5251// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005252RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005253 NoHandleAllocation ha;
5254
5255 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005256 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005257 HeapObject* heap_obj = HeapObject::cast(obj);
5258
5259 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005260 if (heap_obj->map()->is_undetectable()) {
5261 return isolate->heap()->undefined_symbol();
5262 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005263
5264 InstanceType instance_type = heap_obj->map()->instance_type();
5265 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005266 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005267 }
5268
5269 switch (instance_type) {
5270 case ODDBALL_TYPE:
5271 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005272 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005273 }
5274 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005275 return FLAG_harmony_typeof
5276 ? isolate->heap()->null_symbol()
5277 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005278 }
5279 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005280 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005281 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005282 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005283 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005284 default:
5285 // For any kind of object not handled above, the spec rule for
5286 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005287 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005288 }
5289}
5290
5291
lrn@chromium.org25156de2010-04-06 13:10:27 +00005292static bool AreDigits(const char*s, int from, int to) {
5293 for (int i = from; i < to; i++) {
5294 if (s[i] < '0' || s[i] > '9') return false;
5295 }
5296
5297 return true;
5298}
5299
5300
5301static int ParseDecimalInteger(const char*s, int from, int to) {
5302 ASSERT(to - from < 10); // Overflow is not possible.
5303 ASSERT(from < to);
5304 int d = s[from] - '0';
5305
5306 for (int i = from + 1; i < to; i++) {
5307 d = 10 * d + (s[i] - '0');
5308 }
5309
5310 return d;
5311}
5312
5313
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005314RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 NoHandleAllocation ha;
5316 ASSERT(args.length() == 1);
5317 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005318 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005319
5320 // Fast case: short integer or some sorts of junk values.
5321 int len = subject->length();
5322 if (subject->IsSeqAsciiString()) {
5323 if (len == 0) return Smi::FromInt(0);
5324
5325 char const* data = SeqAsciiString::cast(subject)->GetChars();
5326 bool minus = (data[0] == '-');
5327 int start_pos = (minus ? 1 : 0);
5328
5329 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005330 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005331 } else if (data[start_pos] > '9') {
5332 // Fast check for a junk value. A valid string may start from a
5333 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5334 // the 'I' character ('Infinity'). All of that have codes not greater than
5335 // '9' except 'I'.
5336 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005337 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005338 }
5339 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5340 // The maximal/minimal smi has 10 digits. If the string has less digits we
5341 // know it will fit into the smi-data type.
5342 int d = ParseDecimalInteger(data, start_pos, len);
5343 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005344 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005345 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005346 } else if (!subject->HasHashCode() &&
5347 len <= String::kMaxArrayIndexSize &&
5348 (len == 1 || data[0] != '0')) {
5349 // String hash is not calculated yet but all the data are present.
5350 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005351 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005352#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005353 subject->Hash(); // Force hash calculation.
5354 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5355 static_cast<int>(hash));
5356#endif
5357 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005358 }
5359 return Smi::FromInt(d);
5360 }
5361 }
5362
5363 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005364 return isolate->heap()->NumberFromDouble(
5365 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005366}
5367
5368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005369RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 NoHandleAllocation ha;
5371 ASSERT(args.length() == 1);
5372
5373 CONVERT_CHECKED(JSArray, codes, args[0]);
5374 int length = Smi::cast(codes->length())->value();
5375
5376 // Check if the string can be ASCII.
5377 int i;
5378 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005379 Object* element;
5380 { MaybeObject* maybe_element = codes->GetElement(i);
5381 // We probably can't get an exception here, but just in order to enforce
5382 // the checking of inputs in the runtime calls we check here.
5383 if (!maybe_element->ToObject(&element)) return maybe_element;
5384 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005385 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5386 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5387 break;
5388 }
5389
lrn@chromium.org303ada72010-10-27 09:33:13 +00005390 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005391 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005392 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005393 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005394 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005395 }
5396
lrn@chromium.org303ada72010-10-27 09:33:13 +00005397 Object* object = NULL;
5398 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005399 String* result = String::cast(object);
5400 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005401 Object* element;
5402 { MaybeObject* maybe_element = codes->GetElement(i);
5403 if (!maybe_element->ToObject(&element)) return maybe_element;
5404 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005405 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005406 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005407 }
5408 return result;
5409}
5410
5411
5412// kNotEscaped is generated by the following:
5413//
5414// #!/bin/perl
5415// for (my $i = 0; $i < 256; $i++) {
5416// print "\n" if $i % 16 == 0;
5417// my $c = chr($i);
5418// my $escaped = 1;
5419// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5420// print $escaped ? "0, " : "1, ";
5421// }
5422
5423
5424static bool IsNotEscaped(uint16_t character) {
5425 // Only for 8 bit characters, the rest are always escaped (in a different way)
5426 ASSERT(character < 256);
5427 static const char kNotEscaped[256] = {
5428 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5429 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5430 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5431 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5432 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5433 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5434 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5435 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5436 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5437 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5438 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5439 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5440 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5441 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5442 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5443 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5444 };
5445 return kNotEscaped[character] != 0;
5446}
5447
5448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005449RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005450 const char hex_chars[] = "0123456789ABCDEF";
5451 NoHandleAllocation ha;
5452 ASSERT(args.length() == 1);
5453 CONVERT_CHECKED(String, source, args[0]);
5454
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005455 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005456
5457 int escaped_length = 0;
5458 int length = source->length();
5459 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005460 Access<StringInputBuffer> buffer(
5461 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005462 buffer->Reset(source);
5463 while (buffer->has_more()) {
5464 uint16_t character = buffer->GetNext();
5465 if (character >= 256) {
5466 escaped_length += 6;
5467 } else if (IsNotEscaped(character)) {
5468 escaped_length++;
5469 } else {
5470 escaped_length += 3;
5471 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005472 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005473 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005474 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005475 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005476 return Failure::OutOfMemoryException();
5477 }
5478 }
5479 }
5480 // No length change implies no change. Return original string if no change.
5481 if (escaped_length == length) {
5482 return source;
5483 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005484 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005485 { MaybeObject* maybe_o =
5486 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005487 if (!maybe_o->ToObject(&o)) return maybe_o;
5488 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 String* destination = String::cast(o);
5490 int dest_position = 0;
5491
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005492 Access<StringInputBuffer> buffer(
5493 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494 buffer->Rewind();
5495 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005496 uint16_t chr = buffer->GetNext();
5497 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005498 destination->Set(dest_position, '%');
5499 destination->Set(dest_position+1, 'u');
5500 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5501 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5502 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5503 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005505 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005506 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005507 dest_position++;
5508 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005509 destination->Set(dest_position, '%');
5510 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5511 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005512 dest_position += 3;
5513 }
5514 }
5515 return destination;
5516}
5517
5518
5519static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5520 static const signed char kHexValue['g'] = {
5521 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5522 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5523 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5524 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5525 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5526 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5527 -1, 10, 11, 12, 13, 14, 15 };
5528
5529 if (character1 > 'f') return -1;
5530 int hi = kHexValue[character1];
5531 if (hi == -1) return -1;
5532 if (character2 > 'f') return -1;
5533 int lo = kHexValue[character2];
5534 if (lo == -1) return -1;
5535 return (hi << 4) + lo;
5536}
5537
5538
ager@chromium.org870a0b62008-11-04 11:43:05 +00005539static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005540 int i,
5541 int length,
5542 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005543 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005544 int32_t hi = 0;
5545 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005546 if (character == '%' &&
5547 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005548 source->Get(i + 1) == 'u' &&
5549 (hi = TwoDigitHex(source->Get(i + 2),
5550 source->Get(i + 3))) != -1 &&
5551 (lo = TwoDigitHex(source->Get(i + 4),
5552 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005553 *step = 6;
5554 return (hi << 8) + lo;
5555 } else if (character == '%' &&
5556 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005557 (lo = TwoDigitHex(source->Get(i + 1),
5558 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005559 *step = 3;
5560 return lo;
5561 } else {
5562 *step = 1;
5563 return character;
5564 }
5565}
5566
5567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005568RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005569 NoHandleAllocation ha;
5570 ASSERT(args.length() == 1);
5571 CONVERT_CHECKED(String, source, args[0]);
5572
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005573 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005574
5575 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005576 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005577
5578 int unescaped_length = 0;
5579 for (int i = 0; i < length; unescaped_length++) {
5580 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005581 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005582 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005583 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005584 i += step;
5585 }
5586
5587 // No length change implies no change. Return original string if no change.
5588 if (unescaped_length == length)
5589 return source;
5590
lrn@chromium.org303ada72010-10-27 09:33:13 +00005591 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005592 { MaybeObject* maybe_o =
5593 ascii ?
5594 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5595 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005596 if (!maybe_o->ToObject(&o)) return maybe_o;
5597 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005598 String* destination = String::cast(o);
5599
5600 int dest_position = 0;
5601 for (int i = 0; i < length; dest_position++) {
5602 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005603 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005604 i += step;
5605 }
5606 return destination;
5607}
5608
5609
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005610static const unsigned int kQuoteTableLength = 128u;
5611
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005612static const int kJsonQuotesCharactersPerEntry = 8;
5613static const char* const JsonQuotes =
5614 "\\u0000 \\u0001 \\u0002 \\u0003 "
5615 "\\u0004 \\u0005 \\u0006 \\u0007 "
5616 "\\b \\t \\n \\u000b "
5617 "\\f \\r \\u000e \\u000f "
5618 "\\u0010 \\u0011 \\u0012 \\u0013 "
5619 "\\u0014 \\u0015 \\u0016 \\u0017 "
5620 "\\u0018 \\u0019 \\u001a \\u001b "
5621 "\\u001c \\u001d \\u001e \\u001f "
5622 " ! \\\" # "
5623 "$ % & ' "
5624 "( ) * + "
5625 ", - . / "
5626 "0 1 2 3 "
5627 "4 5 6 7 "
5628 "8 9 : ; "
5629 "< = > ? "
5630 "@ A B C "
5631 "D E F G "
5632 "H I J K "
5633 "L M N O "
5634 "P Q R S "
5635 "T U V W "
5636 "X Y Z [ "
5637 "\\\\ ] ^ _ "
5638 "` a b c "
5639 "d e f g "
5640 "h i j k "
5641 "l m n o "
5642 "p q r s "
5643 "t u v w "
5644 "x y z { "
5645 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005646
5647
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005648// For a string that is less than 32k characters it should always be
5649// possible to allocate it in new space.
5650static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5651
5652
5653// Doing JSON quoting cannot make the string more than this many times larger.
5654static const int kJsonQuoteWorstCaseBlowup = 6;
5655
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005656static const int kSpaceForQuotesAndComma = 3;
5657static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005658
5659// Covers the entire ASCII range (all other characters are unchanged by JSON
5660// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005661static const byte JsonQuoteLengths[kQuoteTableLength] = {
5662 6, 6, 6, 6, 6, 6, 6, 6,
5663 2, 2, 2, 6, 2, 2, 6, 6,
5664 6, 6, 6, 6, 6, 6, 6, 6,
5665 6, 6, 6, 6, 6, 6, 6, 6,
5666 1, 1, 2, 1, 1, 1, 1, 1,
5667 1, 1, 1, 1, 1, 1, 1, 1,
5668 1, 1, 1, 1, 1, 1, 1, 1,
5669 1, 1, 1, 1, 1, 1, 1, 1,
5670 1, 1, 1, 1, 1, 1, 1, 1,
5671 1, 1, 1, 1, 1, 1, 1, 1,
5672 1, 1, 1, 1, 1, 1, 1, 1,
5673 1, 1, 1, 1, 2, 1, 1, 1,
5674 1, 1, 1, 1, 1, 1, 1, 1,
5675 1, 1, 1, 1, 1, 1, 1, 1,
5676 1, 1, 1, 1, 1, 1, 1, 1,
5677 1, 1, 1, 1, 1, 1, 1, 1,
5678};
5679
5680
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005681template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005682MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005683
5684
5685template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005686MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5687 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005688}
5689
5690
5691template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005692MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5693 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005694}
5695
5696
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005697template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005698static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5699 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005700 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005701 const Char* read_cursor = characters.start();
5702 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005703 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005704 int quoted_length = kSpaceForQuotes;
5705 while (read_cursor < end) {
5706 Char c = *(read_cursor++);
5707 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5708 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005709 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005710 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005711 }
5712 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005713 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5714 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005715 Object* new_object;
5716 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005717 return new_alloc;
5718 }
5719 StringType* new_string = StringType::cast(new_object);
5720
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005721 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005722 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005723 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005724 *(write_cursor++) = '"';
5725
5726 read_cursor = characters.start();
5727 while (read_cursor < end) {
5728 Char c = *(read_cursor++);
5729 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5730 *(write_cursor++) = c;
5731 } else {
5732 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5733 const char* replacement = JsonQuotes +
5734 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5735 for (int i = 0; i < len; i++) {
5736 *write_cursor++ = *replacement++;
5737 }
5738 }
5739 }
5740 *(write_cursor++) = '"';
5741 return new_string;
5742}
5743
5744
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005745template <typename SinkChar, typename SourceChar>
5746static inline SinkChar* WriteQuoteJsonString(
5747 Isolate* isolate,
5748 SinkChar* write_cursor,
5749 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005750 // SinkChar is only char if SourceChar is guaranteed to be char.
5751 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005752 const SourceChar* read_cursor = characters.start();
5753 const SourceChar* end = read_cursor + characters.length();
5754 *(write_cursor++) = '"';
5755 while (read_cursor < end) {
5756 SourceChar c = *(read_cursor++);
5757 if (sizeof(SourceChar) > 1u &&
5758 static_cast<unsigned>(c) >= kQuoteTableLength) {
5759 *(write_cursor++) = static_cast<SinkChar>(c);
5760 } else {
5761 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5762 const char* replacement = JsonQuotes +
5763 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5764 write_cursor[0] = replacement[0];
5765 if (len > 1) {
5766 write_cursor[1] = replacement[1];
5767 if (len > 2) {
5768 ASSERT(len == 6);
5769 write_cursor[2] = replacement[2];
5770 write_cursor[3] = replacement[3];
5771 write_cursor[4] = replacement[4];
5772 write_cursor[5] = replacement[5];
5773 }
5774 }
5775 write_cursor += len;
5776 }
5777 }
5778 *(write_cursor++) = '"';
5779 return write_cursor;
5780}
5781
5782
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005783template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784static MaybeObject* QuoteJsonString(Isolate* isolate,
5785 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005786 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005788 int worst_case_length =
5789 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005790 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005791 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005792 }
5793
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005794 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5795 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005796 Object* new_object;
5797 if (!new_alloc->ToObject(&new_object)) {
5798 return new_alloc;
5799 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005800 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005801 // Even if our string is small enough to fit in new space we still have to
5802 // handle it being allocated in old space as may happen in the third
5803 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5804 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005805 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005806 }
5807 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005808 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005809
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005810 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005811 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005812 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005813 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5814 write_cursor,
5815 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005816 int final_length = static_cast<int>(
5817 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005818 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005819 isolate->heap()->new_space()->
5820 template ShrinkStringAtAllocationBoundary<StringType>(
5821 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005822 return new_string;
5823}
5824
5825
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005826RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005827 NoHandleAllocation ha;
5828 CONVERT_CHECKED(String, str, args[0]);
5829 if (!str->IsFlat()) {
5830 MaybeObject* try_flatten = str->TryFlatten();
5831 Object* flat;
5832 if (!try_flatten->ToObject(&flat)) {
5833 return try_flatten;
5834 }
5835 str = String::cast(flat);
5836 ASSERT(str->IsFlat());
5837 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005838 String::FlatContent flat = str->GetFlatContent();
5839 ASSERT(flat.IsFlat());
5840 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005841 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005842 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005843 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005844 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005845 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005846 }
5847}
5848
5849
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005850RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005851 NoHandleAllocation ha;
5852 CONVERT_CHECKED(String, str, args[0]);
5853 if (!str->IsFlat()) {
5854 MaybeObject* try_flatten = str->TryFlatten();
5855 Object* flat;
5856 if (!try_flatten->ToObject(&flat)) {
5857 return try_flatten;
5858 }
5859 str = String::cast(flat);
5860 ASSERT(str->IsFlat());
5861 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005862 String::FlatContent flat = str->GetFlatContent();
5863 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005864 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005865 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005866 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005867 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005868 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005869 }
5870}
5871
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005872
5873template <typename Char, typename StringType>
5874static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5875 FixedArray* array,
5876 int worst_case_length) {
5877 int length = array->length();
5878
5879 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5880 worst_case_length);
5881 Object* new_object;
5882 if (!new_alloc->ToObject(&new_object)) {
5883 return new_alloc;
5884 }
5885 if (!isolate->heap()->new_space()->Contains(new_object)) {
5886 // Even if our string is small enough to fit in new space we still have to
5887 // handle it being allocated in old space as may happen in the third
5888 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5889 // CEntryStub::GenerateCore.
5890 return isolate->heap()->undefined_value();
5891 }
5892 AssertNoAllocation no_gc;
5893 StringType* new_string = StringType::cast(new_object);
5894 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5895
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005896 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005897 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005898 *(write_cursor++) = '[';
5899 for (int i = 0; i < length; i++) {
5900 if (i != 0) *(write_cursor++) = ',';
5901 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005902 String::FlatContent content = str->GetFlatContent();
5903 ASSERT(content.IsFlat());
5904 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005905 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5906 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005907 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005908 } else {
5909 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5910 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005911 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005912 }
5913 }
5914 *(write_cursor++) = ']';
5915
5916 int final_length = static_cast<int>(
5917 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005918 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005919 isolate->heap()->new_space()->
5920 template ShrinkStringAtAllocationBoundary<StringType>(
5921 new_string, final_length);
5922 return new_string;
5923}
5924
5925
5926RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5927 NoHandleAllocation ha;
5928 ASSERT(args.length() == 1);
5929 CONVERT_CHECKED(JSArray, array, args[0]);
5930
5931 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5932 FixedArray* elements = FixedArray::cast(array->elements());
5933 int n = elements->length();
5934 bool ascii = true;
5935 int total_length = 0;
5936
5937 for (int i = 0; i < n; i++) {
5938 Object* elt = elements->get(i);
5939 if (!elt->IsString()) return isolate->heap()->undefined_value();
5940 String* element = String::cast(elt);
5941 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5942 total_length += element->length();
5943 if (ascii && element->IsTwoByteRepresentation()) {
5944 ascii = false;
5945 }
5946 }
5947
5948 int worst_case_length =
5949 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5950 + total_length * kJsonQuoteWorstCaseBlowup;
5951
5952 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5953 return isolate->heap()->undefined_value();
5954 }
5955
5956 if (ascii) {
5957 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5958 elements,
5959 worst_case_length);
5960 } else {
5961 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5962 elements,
5963 worst_case_length);
5964 }
5965}
5966
5967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005968RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005969 NoHandleAllocation ha;
5970
5971 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005972 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005973
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005974 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005975
lrn@chromium.org25156de2010-04-06 13:10:27 +00005976 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005977 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005978 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005979}
5980
5981
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005982RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005983 NoHandleAllocation ha;
5984 CONVERT_CHECKED(String, str, args[0]);
5985
5986 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005987 double value = StringToDouble(isolate->unicode_cache(),
5988 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005989
5990 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005991 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005992}
5993
5994
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005996MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005997 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005998 String* s,
5999 int length,
6000 int input_string_length,
6001 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006002 // We try this twice, once with the assumption that the result is no longer
6003 // than the input and, if that assumption breaks, again with the exact
6004 // length. This may not be pretty, but it is nicer than what was here before
6005 // and I hereby claim my vaffel-is.
6006 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006007 // Allocate the resulting string.
6008 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006009 // NOTE: This assumes that the upper/lower case of an ASCII
6010 // character is also ASCII. This is currently the case, but it
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006011 // might break in the future if we implement more context and locale
6012 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006013 Object* o;
6014 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006015 ? isolate->heap()->AllocateRawAsciiString(length)
6016 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006017 if (!maybe_o->ToObject(&o)) return maybe_o;
6018 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006019 String* result = String::cast(o);
6020 bool has_changed_character = false;
6021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006022 // Convert all characters to upper case, assuming that they will fit
6023 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006024 Access<StringInputBuffer> buffer(
6025 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006026 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00006027 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006028 // We can assume that the string is not empty
6029 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006030 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00006031 bool has_next = buffer->has_more();
6032 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006033 int char_length = mapping->get(current, next, chars);
6034 if (char_length == 0) {
6035 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006036 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006037 i++;
6038 } else if (char_length == 1) {
6039 // Common case: converting the letter resulted in one character.
6040 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006041 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006042 has_changed_character = true;
6043 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006044 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006045 // We've assumed that the result would be as long as the
6046 // input but here is a character that converts to several
6047 // characters. No matter, we calculate the exact length
6048 // of the result and try the whole thing again.
6049 //
6050 // Note that this leaves room for optimization. We could just
6051 // memcpy what we already have to the result string. Also,
6052 // the result string is the last object allocated we could
6053 // "realloc" it and probably, in the vast majority of cases,
6054 // extend the existing string to be able to hold the full
6055 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00006056 int next_length = 0;
6057 if (has_next) {
6058 next_length = mapping->get(next, 0, chars);
6059 if (next_length == 0) next_length = 1;
6060 }
6061 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006062 while (buffer->has_more()) {
6063 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00006064 // NOTE: we use 0 as the next character here because, while
6065 // the next character may affect what a character converts to,
6066 // it does not in any case affect the length of what it convert
6067 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006068 int char_length = mapping->get(current, 0, chars);
6069 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00006070 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006071 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006072 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006073 return Failure::OutOfMemoryException();
6074 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006075 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006076 // Try again with the real length.
6077 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006078 } else {
6079 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006080 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006081 i++;
6082 }
6083 has_changed_character = true;
6084 }
6085 current = next;
6086 }
6087 if (has_changed_character) {
6088 return result;
6089 } else {
6090 // If we didn't actually change anything in doing the conversion
6091 // we simple return the result and let the converted string
6092 // become garbage; there is no reason to keep two identical strings
6093 // alive.
6094 return s;
6095 }
6096}
6097
6098
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006099namespace {
6100
lrn@chromium.org303ada72010-10-27 09:33:13 +00006101static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6102
6103
6104// Given a word and two range boundaries returns a word with high bit
6105// set in every byte iff the corresponding input byte was strictly in
6106// the range (m, n). All the other bits in the result are cleared.
6107// This function is only useful when it can be inlined and the
6108// boundaries are statically known.
6109// Requires: all bytes in the input word and the boundaries must be
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006110// ASCII (less than 0x7F).
lrn@chromium.org303ada72010-10-27 09:33:13 +00006111static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006112 // Every byte in an ASCII string is less than or equal to 0x7F.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006113 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6114 // Use strict inequalities since in edge cases the function could be
6115 // further simplified.
6116 ASSERT(0 < m && m < n && n < 0x7F);
6117 // Has high bit set in every w byte less than n.
6118 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6119 // Has high bit set in every w byte greater than m.
6120 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6121 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6122}
6123
6124
6125enum AsciiCaseConversion {
6126 ASCII_TO_LOWER,
6127 ASCII_TO_UPPER
6128};
6129
6130
6131template <AsciiCaseConversion dir>
6132struct FastAsciiConverter {
6133 static bool Convert(char* dst, char* src, int length) {
6134#ifdef DEBUG
6135 char* saved_dst = dst;
6136 char* saved_src = src;
6137#endif
6138 // We rely on the distance between upper and lower case letters
6139 // being a known power of 2.
6140 ASSERT('a' - 'A' == (1 << 5));
6141 // Boundaries for the range of input characters than require conversion.
6142 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6143 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6144 bool changed = false;
6145 char* const limit = src + length;
6146#ifdef V8_HOST_CAN_READ_UNALIGNED
6147 // Process the prefix of the input that requires no conversion one
6148 // (machine) word at a time.
6149 while (src <= limit - sizeof(uintptr_t)) {
6150 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6151 if (AsciiRangeMask(w, lo, hi) != 0) {
6152 changed = true;
6153 break;
6154 }
6155 *reinterpret_cast<uintptr_t*>(dst) = w;
6156 src += sizeof(uintptr_t);
6157 dst += sizeof(uintptr_t);
6158 }
6159 // Process the remainder of the input performing conversion when
6160 // required one word at a time.
6161 while (src <= limit - sizeof(uintptr_t)) {
6162 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6163 uintptr_t m = AsciiRangeMask(w, lo, hi);
6164 // The mask has high (7th) bit set in every byte that needs
6165 // conversion and we know that the distance between cases is
6166 // 1 << 5.
6167 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6168 src += sizeof(uintptr_t);
6169 dst += sizeof(uintptr_t);
6170 }
6171#endif
6172 // Process the last few bytes of the input (or the whole input if
6173 // unaligned access is not supported).
6174 while (src < limit) {
6175 char c = *src;
6176 if (lo < c && c < hi) {
6177 c ^= (1 << 5);
6178 changed = true;
6179 }
6180 *dst = c;
6181 ++src;
6182 ++dst;
6183 }
6184#ifdef DEBUG
6185 CheckConvert(saved_dst, saved_src, length, changed);
6186#endif
6187 return changed;
6188 }
6189
6190#ifdef DEBUG
6191 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6192 bool expected_changed = false;
6193 for (int i = 0; i < length; i++) {
6194 if (dst[i] == src[i]) continue;
6195 expected_changed = true;
6196 if (dir == ASCII_TO_LOWER) {
6197 ASSERT('A' <= src[i] && src[i] <= 'Z');
6198 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6199 } else {
6200 ASSERT(dir == ASCII_TO_UPPER);
6201 ASSERT('a' <= src[i] && src[i] <= 'z');
6202 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6203 }
6204 }
6205 ASSERT(expected_changed == changed);
6206 }
6207#endif
6208};
6209
6210
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006211struct ToLowerTraits {
6212 typedef unibrow::ToLowercase UnibrowConverter;
6213
lrn@chromium.org303ada72010-10-27 09:33:13 +00006214 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006215};
6216
6217
6218struct ToUpperTraits {
6219 typedef unibrow::ToUppercase UnibrowConverter;
6220
lrn@chromium.org303ada72010-10-27 09:33:13 +00006221 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006222};
6223
6224} // namespace
6225
6226
6227template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006228MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006229 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006230 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006231 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006232 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006233 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006234 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006235
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006236 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006237 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006238 if (length == 0) return s;
6239
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006240 // Simpler handling of ASCII strings.
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006241 //
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006242 // NOTE: This assumes that the upper/lower case of an ASCII
6243 // character is also ASCII. This is currently the case, but it
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006244 // might break in the future if we implement more context and locale
6245 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006246 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006247 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006248 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006249 if (!maybe_o->ToObject(&o)) return maybe_o;
6250 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006251 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006252 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006253 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006254 return has_changed_character ? result : s;
6255 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006256
lrn@chromium.org303ada72010-10-27 09:33:13 +00006257 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006258 { MaybeObject* maybe_answer =
6259 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006260 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6261 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006262 if (answer->IsSmi()) {
6263 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006264 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006265 ConvertCaseHelper(isolate,
6266 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006267 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6268 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006269 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006270 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006271}
6272
6273
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006274RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006275 return ConvertCase<ToLowerTraits>(
6276 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006277}
6278
6279
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006280RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006281 return ConvertCase<ToUpperTraits>(
6282 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006283}
6284
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006285
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006286static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006287 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006288}
6289
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006290
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006291RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006292 NoHandleAllocation ha;
6293 ASSERT(args.length() == 3);
6294
6295 CONVERT_CHECKED(String, s, args[0]);
6296 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6297 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6298
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006299 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006300 int length = s->length();
6301
6302 int left = 0;
6303 if (trimLeft) {
6304 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6305 left++;
6306 }
6307 }
6308
6309 int right = length;
6310 if (trimRight) {
6311 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6312 right--;
6313 }
6314 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006315 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006316}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006317
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006318
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006319RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006320 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006321 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006322 CONVERT_ARG_CHECKED(String, subject, 0);
6323 CONVERT_ARG_CHECKED(String, pattern, 1);
6324 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6325
6326 int subject_length = subject->length();
6327 int pattern_length = pattern->length();
6328 RUNTIME_ASSERT(pattern_length > 0);
6329
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006330 if (limit == 0xffffffffu) {
6331 Handle<Object> cached_answer(StringSplitCache::Lookup(
6332 isolate->heap()->string_split_cache(),
6333 *subject,
6334 *pattern));
6335 if (*cached_answer != Smi::FromInt(0)) {
6336 Handle<JSArray> result =
6337 isolate->factory()->NewJSArrayWithElements(
6338 Handle<FixedArray>::cast(cached_answer));
6339 return *result;
6340 }
6341 }
6342
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006343 // The limit can be very large (0xffffffffu), but since the pattern
6344 // isn't empty, we can never create more parts than ~half the length
6345 // of the subject.
6346
6347 if (!subject->IsFlat()) FlattenString(subject);
6348
6349 static const int kMaxInitialListCapacity = 16;
6350
danno@chromium.org40cb8782011-05-25 07:58:50 +00006351 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006352
6353 // Find (up to limit) indices of separator and end-of-string in subject
6354 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6355 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006356 if (!pattern->IsFlat()) FlattenString(pattern);
6357
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006358 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006359
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006360 if (static_cast<uint32_t>(indices.length()) < limit) {
6361 indices.Add(subject_length);
6362 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006363
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006364 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006365
6366 // Create JSArray of substrings separated by separator.
6367 int part_count = indices.length();
6368
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006369 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006370 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006371 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006372 result->set_length(Smi::FromInt(part_count));
6373
6374 ASSERT(result->HasFastElements());
6375
6376 if (part_count == 1 && indices.at(0) == subject_length) {
6377 FixedArray::cast(result->elements())->set(0, *subject);
6378 return *result;
6379 }
6380
6381 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6382 int part_start = 0;
6383 for (int i = 0; i < part_count; i++) {
6384 HandleScope local_loop_handle;
6385 int part_end = indices.at(i);
6386 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006387 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006388 elements->set(i, *substring);
6389 part_start = part_end + pattern_length;
6390 }
6391
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006392 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006393 if (result->HasFastElements()) {
6394 StringSplitCache::Enter(isolate->heap(),
6395 isolate->heap()->string_split_cache(),
6396 *subject,
6397 *pattern,
6398 *elements);
6399 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006400 }
6401
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006402 return *result;
6403}
6404
6405
ulan@chromium.org2efb9002012-01-19 15:36:35 +00006406// Copies ASCII characters to the given fixed array looking up
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006407// one-char strings in the cache. Gives up on the first char that is
6408// not in the cache and fills the remainder with smi zeros. Returns
6409// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006410static int CopyCachedAsciiCharsToArray(Heap* heap,
6411 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006412 FixedArray* elements,
6413 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006414 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006415 FixedArray* ascii_cache = heap->single_character_string_cache();
6416 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006417 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006418 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006419 for (i = 0; i < length; ++i) {
6420 Object* value = ascii_cache->get(chars[i]);
6421 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006422 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006423 }
6424 if (i < length) {
6425 ASSERT(Smi::FromInt(0) == 0);
6426 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6427 }
6428#ifdef DEBUG
6429 for (int j = 0; j < length; ++j) {
6430 Object* element = elements->get(j);
6431 ASSERT(element == Smi::FromInt(0) ||
6432 (element->IsString() && String::cast(element)->LooksValid()));
6433 }
6434#endif
6435 return i;
6436}
6437
6438
6439// Converts a String to JSArray.
6440// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006441RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006442 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006443 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006444 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006445 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006446
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006447 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006448 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006449
6450 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006451 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006452 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006453 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006454 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006455 { MaybeObject* maybe_obj =
6456 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006457 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6458 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006460 String::FlatContent content = s->GetFlatContent();
6461 if (content.IsAscii()) {
6462 Vector<const char> chars = content.ToAsciiVector();
6463 // Note, this will initialize all elements (not only the prefix)
6464 // to prevent GC from seeing partially initialized array.
6465 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6466 chars.start(),
6467 *elements,
6468 length);
6469 } else {
6470 MemsetPointer(elements->data_start(),
6471 isolate->heap()->undefined_value(),
6472 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006473 }
6474 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006475 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006476 }
6477 for (int i = position; i < length; ++i) {
6478 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6479 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006480 }
6481
6482#ifdef DEBUG
6483 for (int i = 0; i < length; ++i) {
6484 ASSERT(String::cast(elements->get(i))->length() == 1);
6485 }
6486#endif
6487
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006488 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006489}
6490
6491
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006492RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006493 NoHandleAllocation ha;
6494 ASSERT(args.length() == 1);
6495 CONVERT_CHECKED(String, value, args[0]);
6496 return value->ToObject();
6497}
6498
6499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006500bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006501 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006502 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006503 return char_length == 0;
6504}
6505
6506
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006507RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006508 NoHandleAllocation ha;
6509 ASSERT(args.length() == 1);
6510
6511 Object* number = args[0];
6512 RUNTIME_ASSERT(number->IsNumber());
6513
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006514 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006515}
6516
6517
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006518RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006519 NoHandleAllocation ha;
6520 ASSERT(args.length() == 1);
6521
6522 Object* number = args[0];
6523 RUNTIME_ASSERT(number->IsNumber());
6524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006525 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006526}
6527
6528
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006529RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006530 NoHandleAllocation ha;
6531 ASSERT(args.length() == 1);
6532
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006533 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006534
6535 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6536 if (number > 0 && number <= Smi::kMaxValue) {
6537 return Smi::FromInt(static_cast<int>(number));
6538 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006539 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540}
6541
6542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006543RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006544 NoHandleAllocation ha;
6545 ASSERT(args.length() == 1);
6546
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006547 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006548
6549 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6550 if (number > 0 && number <= Smi::kMaxValue) {
6551 return Smi::FromInt(static_cast<int>(number));
6552 }
6553
6554 double double_value = DoubleToInteger(number);
6555 // Map both -0 and +0 to +0.
6556 if (double_value == 0) double_value = 0;
6557
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006558 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006559}
6560
6561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006562RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006563 NoHandleAllocation ha;
6564 ASSERT(args.length() == 1);
6565
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006566 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006567 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006568}
6569
6570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006571RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006572 NoHandleAllocation ha;
6573 ASSERT(args.length() == 1);
6574
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006575 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006576
6577 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6578 if (number > 0 && number <= Smi::kMaxValue) {
6579 return Smi::FromInt(static_cast<int>(number));
6580 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006581 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006582}
6583
6584
ager@chromium.org870a0b62008-11-04 11:43:05 +00006585// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6586// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006587RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006588 NoHandleAllocation ha;
6589 ASSERT(args.length() == 1);
6590
6591 Object* obj = args[0];
6592 if (obj->IsSmi()) {
6593 return obj;
6594 }
6595 if (obj->IsHeapNumber()) {
6596 double value = HeapNumber::cast(obj)->value();
6597 int int_value = FastD2I(value);
6598 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6599 return Smi::FromInt(int_value);
6600 }
6601 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006602 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006603}
6604
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006606RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006607 NoHandleAllocation ha;
6608 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006609 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006610}
6611
6612
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006613RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006614 NoHandleAllocation ha;
6615 ASSERT(args.length() == 2);
6616
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006617 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6618 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006619 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006620}
6621
6622
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006623RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006624 NoHandleAllocation ha;
6625 ASSERT(args.length() == 2);
6626
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006627 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6628 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006629 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006630}
6631
6632
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006633RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006634 NoHandleAllocation ha;
6635 ASSERT(args.length() == 2);
6636
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006637 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6638 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006639 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006640}
6641
6642
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006643RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006644 NoHandleAllocation ha;
6645 ASSERT(args.length() == 1);
6646
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006647 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006648 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006649}
6650
6651
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006652RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006653 NoHandleAllocation ha;
6654 ASSERT(args.length() == 0);
6655
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006656 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006657}
6658
6659
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006660RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006661 NoHandleAllocation ha;
6662 ASSERT(args.length() == 2);
6663
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006664 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6665 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006666 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006667}
6668
6669
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006670RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006671 NoHandleAllocation ha;
6672 ASSERT(args.length() == 2);
6673
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006674 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6675 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006676
ager@chromium.org3811b432009-10-28 14:53:37 +00006677 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006678 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680}
6681
6682
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006683RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006684 NoHandleAllocation ha;
6685 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 CONVERT_CHECKED(String, str1, args[0]);
6687 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006688 isolate->counters()->string_add_runtime()->Increment();
6689 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006690}
6691
6692
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006693template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006694static inline void StringBuilderConcatHelper(String* special,
6695 sinkchar* sink,
6696 FixedArray* fixed_array,
6697 int array_length) {
6698 int position = 0;
6699 for (int i = 0; i < array_length; i++) {
6700 Object* element = fixed_array->get(i);
6701 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006702 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006703 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006704 int pos;
6705 int len;
6706 if (encoded_slice > 0) {
6707 // Position and length encoded in one smi.
6708 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6709 len = StringBuilderSubstringLength::decode(encoded_slice);
6710 } else {
6711 // Position and length encoded in two smis.
6712 Object* obj = fixed_array->get(++i);
6713 ASSERT(obj->IsSmi());
6714 pos = Smi::cast(obj)->value();
6715 len = -encoded_slice;
6716 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006717 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006718 sink + position,
6719 pos,
6720 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006721 position += len;
6722 } else {
6723 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006724 int element_length = string->length();
6725 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006726 position += element_length;
6727 }
6728 }
6729}
6730
6731
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006732RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006733 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006734 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006735 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006736 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006737 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006738 return Failure::OutOfMemoryException();
6739 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006740 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006741 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006742
6743 // This assumption is used by the slice encoding in one or two smis.
6744 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6745
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006746 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006747 if (maybe_result->IsFailure()) return maybe_result;
6748
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006749 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006750 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006751 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006752 }
6753 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006754 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006755 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006756 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006757
6758 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006759 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006760 } else if (array_length == 1) {
6761 Object* first = fixed_array->get(0);
6762 if (first->IsString()) return first;
6763 }
6764
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006765 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006766 int position = 0;
6767 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006768 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006769 Object* elt = fixed_array->get(i);
6770 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006771 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006772 int smi_value = Smi::cast(elt)->value();
6773 int pos;
6774 int len;
6775 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006776 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006777 pos = StringBuilderSubstringPosition::decode(smi_value);
6778 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006779 } else {
6780 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006781 len = -smi_value;
6782 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006783 i++;
6784 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006785 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006786 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006787 Object* next_smi = fixed_array->get(i);
6788 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006789 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006790 }
6791 pos = Smi::cast(next_smi)->value();
6792 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006793 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006794 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006795 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006796 ASSERT(pos >= 0);
6797 ASSERT(len >= 0);
6798 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006799 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006800 }
6801 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006802 } else if (elt->IsString()) {
6803 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006804 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006805 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006806 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006807 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006808 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006809 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006810 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006811 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006812 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006813 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006814 return Failure::OutOfMemoryException();
6815 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006816 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006817 }
6818
6819 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006820 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006821
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006822 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006823 { MaybeObject* maybe_object =
6824 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006825 if (!maybe_object->ToObject(&object)) return maybe_object;
6826 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006827 SeqAsciiString* answer = SeqAsciiString::cast(object);
6828 StringBuilderConcatHelper(special,
6829 answer->GetChars(),
6830 fixed_array,
6831 array_length);
6832 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006833 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006834 { MaybeObject* maybe_object =
6835 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006836 if (!maybe_object->ToObject(&object)) return maybe_object;
6837 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006838 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6839 StringBuilderConcatHelper(special,
6840 answer->GetChars(),
6841 fixed_array,
6842 array_length);
6843 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006844 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006845}
6846
6847
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006848RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006849 NoHandleAllocation ha;
6850 ASSERT(args.length() == 3);
6851 CONVERT_CHECKED(JSArray, array, args[0]);
6852 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006853 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006854 return Failure::OutOfMemoryException();
6855 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006856 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006857 CONVERT_CHECKED(String, separator, args[2]);
6858
6859 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006860 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006861 }
6862 FixedArray* fixed_array = FixedArray::cast(array->elements());
6863 if (fixed_array->length() < array_length) {
6864 array_length = fixed_array->length();
6865 }
6866
6867 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006868 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006869 } else if (array_length == 1) {
6870 Object* first = fixed_array->get(0);
6871 if (first->IsString()) return first;
6872 }
6873
6874 int separator_length = separator->length();
6875 int max_nof_separators =
6876 (String::kMaxLength + separator_length - 1) / separator_length;
6877 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006878 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006879 return Failure::OutOfMemoryException();
6880 }
6881 int length = (array_length - 1) * separator_length;
6882 for (int i = 0; i < array_length; i++) {
6883 Object* element_obj = fixed_array->get(i);
6884 if (!element_obj->IsString()) {
6885 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006886 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006887 }
6888 String* element = String::cast(element_obj);
6889 int increment = element->length();
6890 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006891 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006892 return Failure::OutOfMemoryException();
6893 }
6894 length += increment;
6895 }
6896
6897 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006898 { MaybeObject* maybe_object =
6899 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006900 if (!maybe_object->ToObject(&object)) return maybe_object;
6901 }
6902 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6903
6904 uc16* sink = answer->GetChars();
6905#ifdef DEBUG
6906 uc16* end = sink + length;
6907#endif
6908
6909 String* first = String::cast(fixed_array->get(0));
6910 int first_length = first->length();
6911 String::WriteToFlat(first, sink, 0, first_length);
6912 sink += first_length;
6913
6914 for (int i = 1; i < array_length; i++) {
6915 ASSERT(sink + separator_length <= end);
6916 String::WriteToFlat(separator, sink, 0, separator_length);
6917 sink += separator_length;
6918
6919 String* element = String::cast(fixed_array->get(i));
6920 int element_length = element->length();
6921 ASSERT(sink + element_length <= end);
6922 String::WriteToFlat(element, sink, 0, element_length);
6923 sink += element_length;
6924 }
6925 ASSERT(sink == end);
6926
6927 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6928 return answer;
6929}
6930
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006931template <typename Char>
6932static void JoinSparseArrayWithSeparator(FixedArray* elements,
6933 int elements_length,
6934 uint32_t array_length,
6935 String* separator,
6936 Vector<Char> buffer) {
6937 int previous_separator_position = 0;
6938 int separator_length = separator->length();
6939 int cursor = 0;
6940 for (int i = 0; i < elements_length; i += 2) {
6941 int position = NumberToInt32(elements->get(i));
6942 String* string = String::cast(elements->get(i + 1));
6943 int string_length = string->length();
6944 if (string->length() > 0) {
6945 while (previous_separator_position < position) {
6946 String::WriteToFlat<Char>(separator, &buffer[cursor],
6947 0, separator_length);
6948 cursor += separator_length;
6949 previous_separator_position++;
6950 }
6951 String::WriteToFlat<Char>(string, &buffer[cursor],
6952 0, string_length);
6953 cursor += string->length();
6954 }
6955 }
6956 if (separator_length > 0) {
6957 // Array length must be representable as a signed 32-bit number,
6958 // otherwise the total string length would have been too large.
6959 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6960 int last_array_index = static_cast<int>(array_length - 1);
6961 while (previous_separator_position < last_array_index) {
6962 String::WriteToFlat<Char>(separator, &buffer[cursor],
6963 0, separator_length);
6964 cursor += separator_length;
6965 previous_separator_position++;
6966 }
6967 }
6968 ASSERT(cursor <= buffer.length());
6969}
6970
6971
6972RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6973 NoHandleAllocation ha;
6974 ASSERT(args.length() == 3);
6975 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006976 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6977 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006978 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6979 CONVERT_CHECKED(String, separator, args[2]);
6980 // elements_array is fast-mode JSarray of alternating positions
6981 // (increasing order) and strings.
6982 // array_length is length of original array (used to add separators);
6983 // separator is string to put between elements. Assumed to be non-empty.
6984
6985 // Find total length of join result.
6986 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006987 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006988 int max_string_length;
6989 if (is_ascii) {
6990 max_string_length = SeqAsciiString::kMaxLength;
6991 } else {
6992 max_string_length = SeqTwoByteString::kMaxLength;
6993 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006994 bool overflow = false;
6995 CONVERT_NUMBER_CHECKED(int, elements_length,
6996 Int32, elements_array->length());
6997 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6998 FixedArray* elements = FixedArray::cast(elements_array->elements());
6999 for (int i = 0; i < elements_length; i += 2) {
7000 RUNTIME_ASSERT(elements->get(i)->IsNumber());
7001 CONVERT_CHECKED(String, string, elements->get(i + 1));
7002 int length = string->length();
7003 if (is_ascii && !string->IsAsciiRepresentation()) {
7004 is_ascii = false;
7005 max_string_length = SeqTwoByteString::kMaxLength;
7006 }
7007 if (length > max_string_length ||
7008 max_string_length - length < string_length) {
7009 overflow = true;
7010 break;
7011 }
7012 string_length += length;
7013 }
7014 int separator_length = separator->length();
7015 if (!overflow && separator_length > 0) {
7016 if (array_length <= 0x7fffffffu) {
7017 int separator_count = static_cast<int>(array_length) - 1;
7018 int remaining_length = max_string_length - string_length;
7019 if ((remaining_length / separator_length) >= separator_count) {
7020 string_length += separator_length * (array_length - 1);
7021 } else {
7022 // Not room for the separators within the maximal string length.
7023 overflow = true;
7024 }
7025 } else {
7026 // Nonempty separator and at least 2^31-1 separators necessary
7027 // means that the string is too large to create.
7028 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
7029 overflow = true;
7030 }
7031 }
7032 if (overflow) {
7033 // Throw OutOfMemory exception for creating too large a string.
7034 V8::FatalProcessOutOfMemory("Array join result too large.");
7035 }
7036
7037 if (is_ascii) {
7038 MaybeObject* result_allocation =
7039 isolate->heap()->AllocateRawAsciiString(string_length);
7040 if (result_allocation->IsFailure()) return result_allocation;
7041 SeqAsciiString* result_string =
7042 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
7043 JoinSparseArrayWithSeparator<char>(elements,
7044 elements_length,
7045 array_length,
7046 separator,
7047 Vector<char>(result_string->GetChars(),
7048 string_length));
7049 return result_string;
7050 } else {
7051 MaybeObject* result_allocation =
7052 isolate->heap()->AllocateRawTwoByteString(string_length);
7053 if (result_allocation->IsFailure()) return result_allocation;
7054 SeqTwoByteString* result_string =
7055 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
7056 JoinSparseArrayWithSeparator<uc16>(elements,
7057 elements_length,
7058 array_length,
7059 separator,
7060 Vector<uc16>(result_string->GetChars(),
7061 string_length));
7062 return result_string;
7063 }
7064}
7065
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00007066
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007067RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007068 NoHandleAllocation ha;
7069 ASSERT(args.length() == 2);
7070
7071 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7072 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007073 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007074}
7075
7076
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007077RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007078 NoHandleAllocation ha;
7079 ASSERT(args.length() == 2);
7080
7081 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7082 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007083 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007084}
7085
7086
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007087RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007088 NoHandleAllocation ha;
7089 ASSERT(args.length() == 2);
7090
7091 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7092 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007093 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094}
7095
7096
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007097RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007098 NoHandleAllocation ha;
7099 ASSERT(args.length() == 1);
7100
7101 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007102 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007103}
7104
7105
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007106RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007107 NoHandleAllocation ha;
7108 ASSERT(args.length() == 2);
7109
7110 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7111 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007112 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007113}
7114
7115
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007116RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007117 NoHandleAllocation ha;
7118 ASSERT(args.length() == 2);
7119
7120 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7121 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007122 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007123}
7124
7125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007126RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007127 NoHandleAllocation ha;
7128 ASSERT(args.length() == 2);
7129
7130 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7131 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007132 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007133}
7134
7135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007136RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007137 NoHandleAllocation ha;
7138 ASSERT(args.length() == 2);
7139
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007140 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7141 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007142 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7143 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7144 if (x == y) return Smi::FromInt(EQUAL);
7145 Object* result;
7146 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7147 result = Smi::FromInt(EQUAL);
7148 } else {
7149 result = Smi::FromInt(NOT_EQUAL);
7150 }
7151 return result;
7152}
7153
7154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007155RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007156 NoHandleAllocation ha;
7157 ASSERT(args.length() == 2);
7158
7159 CONVERT_CHECKED(String, x, args[0]);
7160 CONVERT_CHECKED(String, y, args[1]);
7161
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007162 bool not_equal = !x->Equals(y);
7163 // This is slightly convoluted because the value that signifies
7164 // equality is 0 and inequality is 1 so we have to negate the result
7165 // from String::Equals.
7166 ASSERT(not_equal == 0 || not_equal == 1);
7167 STATIC_CHECK(EQUAL == 0);
7168 STATIC_CHECK(NOT_EQUAL == 1);
7169 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007170}
7171
7172
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007173RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007174 NoHandleAllocation ha;
7175 ASSERT(args.length() == 3);
7176
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007177 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7178 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007179 if (isnan(x) || isnan(y)) return args[2];
7180 if (x == y) return Smi::FromInt(EQUAL);
7181 if (isless(x, y)) return Smi::FromInt(LESS);
7182 return Smi::FromInt(GREATER);
7183}
7184
7185
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007186// Compare two Smis as if they were converted to strings and then
7187// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007188RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007189 NoHandleAllocation ha;
7190 ASSERT(args.length() == 2);
7191
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007192 // Extract the integer values from the Smis.
7193 CONVERT_CHECKED(Smi, x, args[0]);
7194 CONVERT_CHECKED(Smi, y, args[1]);
7195 int x_value = x->value();
7196 int y_value = y->value();
7197
7198 // If the integers are equal so are the string representations.
7199 if (x_value == y_value) return Smi::FromInt(EQUAL);
7200
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007201 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007202 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007203 if (x_value == 0 || y_value == 0)
7204 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007205
ager@chromium.org32912102009-01-16 10:38:43 +00007206 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007207 // smallest because the char code of '-' is less than the char code
7208 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007209
7210 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7211 // architectures using 32-bit Smis.
7212 uint32_t x_scaled = x_value;
7213 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007214 if (x_value < 0 || y_value < 0) {
7215 if (y_value >= 0) return Smi::FromInt(LESS);
7216 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007217 x_scaled = -x_value;
7218 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007219 }
7220
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007221 static const uint32_t kPowersOf10[] = {
7222 1, 10, 100, 1000, 10*1000, 100*1000,
7223 1000*1000, 10*1000*1000, 100*1000*1000,
7224 1000*1000*1000
7225 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007226
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007227 // If the integers have the same number of decimal digits they can be
7228 // compared directly as the numeric order is the same as the
7229 // lexicographic order. If one integer has fewer digits, it is scaled
7230 // by some power of 10 to have the same number of digits as the longer
7231 // integer. If the scaled integers are equal it means the shorter
7232 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007233
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007234 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7235 int x_log2 = IntegerLog2(x_scaled);
7236 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7237 x_log10 -= x_scaled < kPowersOf10[x_log10];
7238
7239 int y_log2 = IntegerLog2(y_scaled);
7240 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7241 y_log10 -= y_scaled < kPowersOf10[y_log10];
7242
7243 int tie = EQUAL;
7244
7245 if (x_log10 < y_log10) {
7246 // X has fewer digits. We would like to simply scale up X but that
7247 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7248 // be scaled up to 9_000_000_000. So we scale up by the next
7249 // smallest power and scale down Y to drop one digit. It is OK to
7250 // drop one digit from the longer integer since the final digit is
7251 // past the length of the shorter integer.
7252 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7253 y_scaled /= 10;
7254 tie = LESS;
7255 } else if (y_log10 < x_log10) {
7256 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7257 x_scaled /= 10;
7258 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007259 }
7260
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007261 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7262 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7263 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007264}
7265
7266
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007267static Object* StringInputBufferCompare(RuntimeState* state,
7268 String* x,
7269 String* y) {
7270 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7271 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007272 bufx.Reset(x);
7273 bufy.Reset(y);
7274 while (bufx.has_more() && bufy.has_more()) {
7275 int d = bufx.GetNext() - bufy.GetNext();
7276 if (d < 0) return Smi::FromInt(LESS);
7277 else if (d > 0) return Smi::FromInt(GREATER);
7278 }
7279
7280 // x is (non-trivial) prefix of y:
7281 if (bufy.has_more()) return Smi::FromInt(LESS);
7282 // y is prefix of x:
7283 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7284}
7285
7286
7287static Object* FlatStringCompare(String* x, String* y) {
7288 ASSERT(x->IsFlat());
7289 ASSERT(y->IsFlat());
7290 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7291 int prefix_length = x->length();
7292 if (y->length() < prefix_length) {
7293 prefix_length = y->length();
7294 equal_prefix_result = Smi::FromInt(GREATER);
7295 } else if (y->length() > prefix_length) {
7296 equal_prefix_result = Smi::FromInt(LESS);
7297 }
7298 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007299 String::FlatContent x_content = x->GetFlatContent();
7300 String::FlatContent y_content = y->GetFlatContent();
7301 if (x_content.IsAscii()) {
7302 Vector<const char> x_chars = x_content.ToAsciiVector();
7303 if (y_content.IsAscii()) {
7304 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007305 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007306 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007307 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007308 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7309 }
7310 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007311 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7312 if (y_content.IsAscii()) {
7313 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007314 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7315 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007316 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007317 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7318 }
7319 }
7320 Object* result;
7321 if (r == 0) {
7322 result = equal_prefix_result;
7323 } else {
7324 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7325 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007326 ASSERT(result ==
7327 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007328 return result;
7329}
7330
7331
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007332RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333 NoHandleAllocation ha;
7334 ASSERT(args.length() == 2);
7335
7336 CONVERT_CHECKED(String, x, args[0]);
7337 CONVERT_CHECKED(String, y, args[1]);
7338
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007340
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007341 // A few fast case tests before we flatten.
7342 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007343 if (y->length() == 0) {
7344 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007345 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007346 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347 return Smi::FromInt(LESS);
7348 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007349
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007350 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007351 if (d < 0) return Smi::FromInt(LESS);
7352 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007353
lrn@chromium.org303ada72010-10-27 09:33:13 +00007354 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007355 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007356 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7357 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007358 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007359 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7360 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007361
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007362 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007363 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364}
7365
7366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007367RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007368 NoHandleAllocation ha;
7369 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007370 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007371
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007372 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007373 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374}
7375
7376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007377RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007378 NoHandleAllocation ha;
7379 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007380 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007381
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007382 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007383 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384}
7385
7386
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007387RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007388 NoHandleAllocation ha;
7389 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007390 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007391
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007392 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007393 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007394}
7395
7396
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007397static const double kPiDividedBy4 = 0.78539816339744830962;
7398
7399
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007400RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007401 NoHandleAllocation ha;
7402 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007403 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007404
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007405 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7406 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007407 double result;
7408 if (isinf(x) && isinf(y)) {
7409 // Make sure that the result in case of two infinite arguments
7410 // is a multiple of Pi / 4. The sign of the result is determined
7411 // by the first argument (x) and the sign of the second argument
7412 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007413 int multiplier = (x < 0) ? -1 : 1;
7414 if (y < 0) multiplier *= 3;
7415 result = multiplier * kPiDividedBy4;
7416 } else {
7417 result = atan2(x, y);
7418 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007419 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007420}
7421
7422
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007423RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007424 NoHandleAllocation ha;
7425 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007426 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007427
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007428 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007429 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007430}
7431
7432
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007433RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007434 NoHandleAllocation ha;
7435 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007436 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007437
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007438 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007439 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007440}
7441
7442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007443RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007444 NoHandleAllocation ha;
7445 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007446 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007448 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007449 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007450}
7451
7452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007453RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007454 NoHandleAllocation ha;
7455 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007456 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007457
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007458 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007459 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007460}
7461
7462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007463RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007464 NoHandleAllocation ha;
7465 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007466 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007467
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007468 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007469 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007470}
7471
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007472// Slow version of Math.pow. We check for fast paths for special cases.
7473// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007474RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007475 NoHandleAllocation ha;
7476 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007477 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007478
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007479 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007480
7481 // If the second argument is a smi, it is much faster to call the
7482 // custom powi() function than the generic pow().
7483 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007484 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007485 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007486 }
7487
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007488 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007489 int y_int = static_cast<int>(y);
7490 double result;
7491 if (y == y_int) {
7492 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7493 } else if (y == 0.5) {
7494 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7495 } else if (y == -0.5) {
7496 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7497 } else {
7498 result = power_double_double(x, y);
7499 }
7500 if (isnan(result)) return isolate->heap()->nan_value();
7501 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007502}
7503
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007504// Fast version of Math.pow if we know that y is not an integer and y is not
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007505// -0.5 or 0.5. Used as slow case from full codegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007506RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007507 NoHandleAllocation ha;
7508 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007509 isolate->counters()->math_pow()->Increment();
7510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007511 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7512 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007513 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007514 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007515 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007516 double result = power_double_double(x, y);
7517 if (isnan(result)) return isolate->heap()->nan_value();
7518 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007519 }
7520}
7521
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007522
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007523RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007524 NoHandleAllocation ha;
7525 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007526 isolate->counters()->math_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007527
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007528 if (!args[0]->IsHeapNumber()) {
7529 // Must be smi. Return the argument unchanged for all the other types
7530 // to make fuzz-natives test happy.
7531 return args[0];
7532 }
7533
7534 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7535
7536 double value = number->value();
7537 int exponent = number->get_exponent();
7538 int sign = number->get_sign();
7539
danno@chromium.org160a7b02011-04-18 15:51:38 +00007540 if (exponent < -1) {
7541 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7542 if (sign) return isolate->heap()->minus_zero_value();
7543 return Smi::FromInt(0);
7544 }
7545
7546 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7547 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
ulan@chromium.org2efb9002012-01-19 15:36:35 +00007548 // argument holds for 32-bit smis).
danno@chromium.org160a7b02011-04-18 15:51:38 +00007549 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007550 return Smi::FromInt(static_cast<int>(value + 0.5));
7551 }
7552
7553 // If the magnitude is big enough, there's no place for fraction part. If we
7554 // try to add 0.5 to this number, 1.0 will be added instead.
7555 if (exponent >= 52) {
7556 return number;
7557 }
7558
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007559 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007560
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007561 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007562 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007563}
7564
7565
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007566RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007567 NoHandleAllocation ha;
7568 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007569 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007570
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007571 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007572 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007573}
7574
7575
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007576RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007577 NoHandleAllocation ha;
7578 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007579 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007580
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007581 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007582 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007583}
7584
7585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007586RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007587 NoHandleAllocation ha;
7588 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007589 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007590
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007591 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007592 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007593}
7594
7595
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007596static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007597 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7598 181, 212, 243, 273, 304, 334};
7599 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7600 182, 213, 244, 274, 305, 335};
7601
7602 year += month / 12;
7603 month %= 12;
7604 if (month < 0) {
7605 year--;
7606 month += 12;
7607 }
7608
7609 ASSERT(month >= 0);
7610 ASSERT(month < 12);
7611
7612 // year_delta is an arbitrary number such that:
7613 // a) year_delta = -1 (mod 400)
7614 // b) year + year_delta > 0 for years in the range defined by
7615 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7616 // Jan 1 1970. This is required so that we don't run into integer
7617 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007618 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007619 // operations.
7620 static const int year_delta = 399999;
7621 static const int base_day = 365 * (1970 + year_delta) +
7622 (1970 + year_delta) / 4 -
7623 (1970 + year_delta) / 100 +
7624 (1970 + year_delta) / 400;
7625
7626 int year1 = year + year_delta;
7627 int day_from_year = 365 * year1 +
7628 year1 / 4 -
7629 year1 / 100 +
7630 year1 / 400 -
7631 base_day;
7632
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007633 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7634 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007635 }
7636
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007637 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007638}
7639
7640
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007641RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007642 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007643 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007644
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007645 CONVERT_SMI_ARG_CHECKED(year, 0);
7646 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007647
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007648 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007649}
7650
7651
7652static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7653static const int kDaysIn4Years = 4 * 365 + 1;
7654static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7655static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7656static const int kDays1970to2000 = 30 * 365 + 7;
7657static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7658 kDays1970to2000;
7659static const int kYearsOffset = 400000;
7660
7661static const char kDayInYear[] = {
7662 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7663 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7664 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7665 22, 23, 24, 25, 26, 27, 28,
7666 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7667 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7668 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7669 22, 23, 24, 25, 26, 27, 28, 29, 30,
7670 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7671 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7672 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7673 22, 23, 24, 25, 26, 27, 28, 29, 30,
7674 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7675 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7676 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7677 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7678 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7679 22, 23, 24, 25, 26, 27, 28, 29, 30,
7680 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7681 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7682 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7683 22, 23, 24, 25, 26, 27, 28, 29, 30,
7684 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7685 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7686
7687 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7688 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7689 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7690 22, 23, 24, 25, 26, 27, 28,
7691 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7692 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7693 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7694 22, 23, 24, 25, 26, 27, 28, 29, 30,
7695 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7696 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7697 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7698 22, 23, 24, 25, 26, 27, 28, 29, 30,
7699 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7700 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7701 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7702 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7703 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7704 22, 23, 24, 25, 26, 27, 28, 29, 30,
7705 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7706 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7707 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7708 22, 23, 24, 25, 26, 27, 28, 29, 30,
7709 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7710 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7711
7712 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7713 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7714 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7715 22, 23, 24, 25, 26, 27, 28, 29,
7716 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7717 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7718 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7719 22, 23, 24, 25, 26, 27, 28, 29, 30,
7720 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7721 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7722 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7723 22, 23, 24, 25, 26, 27, 28, 29, 30,
7724 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7725 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7726 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7727 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7728 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7729 22, 23, 24, 25, 26, 27, 28, 29, 30,
7730 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7731 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7732 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7733 22, 23, 24, 25, 26, 27, 28, 29, 30,
7734 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7735 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7736
7737 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7738 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7739 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7740 22, 23, 24, 25, 26, 27, 28,
7741 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7742 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7743 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7744 22, 23, 24, 25, 26, 27, 28, 29, 30,
7745 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7746 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7747 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7748 22, 23, 24, 25, 26, 27, 28, 29, 30,
7749 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7750 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7751 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7752 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7753 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7754 22, 23, 24, 25, 26, 27, 28, 29, 30,
7755 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7756 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7757 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7758 22, 23, 24, 25, 26, 27, 28, 29, 30,
7759 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7760 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7761
7762static const char kMonthInYear[] = {
7763 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7764 0, 0, 0, 0, 0, 0,
7765 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7766 1, 1, 1,
7767 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7768 2, 2, 2, 2, 2, 2,
7769 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7770 3, 3, 3, 3, 3,
7771 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7772 4, 4, 4, 4, 4, 4,
7773 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7774 5, 5, 5, 5, 5,
7775 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7776 6, 6, 6, 6, 6, 6,
7777 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7778 7, 7, 7, 7, 7, 7,
7779 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7780 8, 8, 8, 8, 8,
7781 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7782 9, 9, 9, 9, 9, 9,
7783 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7784 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7785 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7786 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7787
7788 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7789 0, 0, 0, 0, 0, 0,
7790 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7791 1, 1, 1,
7792 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7793 2, 2, 2, 2, 2, 2,
7794 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7795 3, 3, 3, 3, 3,
7796 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7797 4, 4, 4, 4, 4, 4,
7798 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7799 5, 5, 5, 5, 5,
7800 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7801 6, 6, 6, 6, 6, 6,
7802 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7803 7, 7, 7, 7, 7, 7,
7804 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7805 8, 8, 8, 8, 8,
7806 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7807 9, 9, 9, 9, 9, 9,
7808 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7809 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7810 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7811 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7812
7813 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7814 0, 0, 0, 0, 0, 0,
7815 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7816 1, 1, 1, 1,
7817 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7818 2, 2, 2, 2, 2, 2,
7819 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7820 3, 3, 3, 3, 3,
7821 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7822 4, 4, 4, 4, 4, 4,
7823 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7824 5, 5, 5, 5, 5,
7825 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7826 6, 6, 6, 6, 6, 6,
7827 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7828 7, 7, 7, 7, 7, 7,
7829 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7830 8, 8, 8, 8, 8,
7831 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7832 9, 9, 9, 9, 9, 9,
7833 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7834 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7835 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7836 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7837
7838 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7839 0, 0, 0, 0, 0, 0,
7840 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
7841 1, 1, 1,
7842 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
7843 2, 2, 2, 2, 2, 2,
7844 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
7845 3, 3, 3, 3, 3,
7846 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
7847 4, 4, 4, 4, 4, 4,
7848 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
7849 5, 5, 5, 5, 5,
7850 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
7851 6, 6, 6, 6, 6, 6,
7852 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
7853 7, 7, 7, 7, 7, 7,
7854 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
7855 8, 8, 8, 8, 8,
7856 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
7857 9, 9, 9, 9, 9, 9,
7858 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7859 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7860 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7861 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7862
7863
7864// This function works for dates from 1970 to 2099.
7865static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007866 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007867#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007868 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007869#endif
7870
7871 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7872 date %= kDaysIn4Years;
7873
7874 month = kMonthInYear[date];
7875 day = kDayInYear[date];
7876
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007877 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007878}
7879
7880
7881static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007882 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007883#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007884 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007885#endif
7886
7887 date += kDaysOffset;
7888 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7889 date %= kDaysIn400Years;
7890
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007891 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007892
7893 date--;
7894 int yd1 = date / kDaysIn100Years;
7895 date %= kDaysIn100Years;
7896 year += 100 * yd1;
7897
7898 date++;
7899 int yd2 = date / kDaysIn4Years;
7900 date %= kDaysIn4Years;
7901 year += 4 * yd2;
7902
7903 date--;
7904 int yd3 = date / 365;
7905 date %= 365;
7906 year += yd3;
7907
7908 bool is_leap = (!yd1 || yd2) && !yd3;
7909
7910 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007911 ASSERT(is_leap || (date >= 0));
7912 ASSERT((date < 365) || (is_leap && (date < 366)));
7913 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007914 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7915 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007916
7917 if (is_leap) {
7918 day = kDayInYear[2*365 + 1 + date];
7919 month = kMonthInYear[2*365 + 1 + date];
7920 } else {
7921 day = kDayInYear[date];
7922 month = kMonthInYear[date];
7923 }
7924
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007925 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007926}
7927
7928
7929static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007930 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007931 if (date >= 0 && date < 32 * kDaysIn4Years) {
7932 DateYMDFromTimeAfter1970(date, year, month, day);
7933 } else {
7934 DateYMDFromTimeSlow(date, year, month, day);
7935 }
7936}
7937
7938
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007939RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007940 NoHandleAllocation ha;
7941 ASSERT(args.length() == 2);
7942
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007943 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007944 CONVERT_CHECKED(JSArray, res_array, args[1]);
7945
7946 int year, month, day;
7947 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7948
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007949 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7950 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007951 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007952
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007953 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7954 if (maybe->IsFailure()) return maybe;
7955 FixedArray* elms = FixedArray::cast(res_array->elements());
7956 elms->set(0, Smi::FromInt(year));
7957 elms->set(1, Smi::FromInt(month));
7958 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007959
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007960 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007961}
7962
7963
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007964RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007965 HandleScope scope(isolate);
7966 ASSERT(args.length() == 3);
7967
7968 Handle<JSFunction> callee = args.at<JSFunction>(0);
7969 Object** parameters = reinterpret_cast<Object**>(args[1]);
7970 const int argument_count = Smi::cast(args[2])->value();
7971
7972 Handle<JSObject> result =
7973 isolate->factory()->NewArgumentsObject(callee, argument_count);
7974 // Allocate the elements if needed.
7975 int parameter_count = callee->shared()->formal_parameter_count();
7976 if (argument_count > 0) {
7977 if (parameter_count > 0) {
7978 int mapped_count = Min(argument_count, parameter_count);
7979 Handle<FixedArray> parameter_map =
7980 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7981 parameter_map->set_map(
7982 isolate->heap()->non_strict_arguments_elements_map());
7983
7984 Handle<Map> old_map(result->map());
7985 Handle<Map> new_map =
7986 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007987 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007988
7989 result->set_map(*new_map);
7990 result->set_elements(*parameter_map);
7991
7992 // Store the context and the arguments array at the beginning of the
7993 // parameter map.
7994 Handle<Context> context(isolate->context());
7995 Handle<FixedArray> arguments =
7996 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7997 parameter_map->set(0, *context);
7998 parameter_map->set(1, *arguments);
7999
8000 // Loop over the actual parameters backwards.
8001 int index = argument_count - 1;
8002 while (index >= mapped_count) {
8003 // These go directly in the arguments array and have no
8004 // corresponding slot in the parameter map.
8005 arguments->set(index, *(parameters - index - 1));
8006 --index;
8007 }
8008
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008009 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00008010 while (index >= 0) {
8011 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008012 Handle<String> name(scope_info->ParameterName(index));
8013 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00008014 bool duplicate = false;
8015 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008016 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008017 duplicate = true;
8018 break;
8019 }
8020 }
8021
8022 if (duplicate) {
8023 // This goes directly in the arguments array with a hole in the
8024 // parameter map.
8025 arguments->set(index, *(parameters - index - 1));
8026 parameter_map->set_the_hole(index + 2);
8027 } else {
8028 // The context index goes in the parameter map with a hole in the
8029 // arguments array.
8030 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008031 for (int j = 0; j < context_local_count; ++j) {
8032 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00008033 context_index = j;
8034 break;
8035 }
8036 }
8037 ASSERT(context_index >= 0);
8038 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008039 parameter_map->set(index + 2, Smi::FromInt(
8040 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00008041 }
8042
8043 --index;
8044 }
8045 } else {
8046 // If there is no aliasing, the arguments object elements are not
8047 // special in any way.
8048 Handle<FixedArray> elements =
8049 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
8050 result->set_elements(*elements);
8051 for (int i = 0; i < argument_count; ++i) {
8052 elements->set(i, *(parameters - i - 1));
8053 }
8054 }
8055 }
8056 return *result;
8057}
8058
8059
8060RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008061 NoHandleAllocation ha;
8062 ASSERT(args.length() == 3);
8063
8064 JSFunction* callee = JSFunction::cast(args[0]);
8065 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008066 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008067
lrn@chromium.org303ada72010-10-27 09:33:13 +00008068 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008069 { MaybeObject* maybe_result =
8070 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008071 if (!maybe_result->ToObject(&result)) return maybe_result;
8072 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008073 // Allocate the elements if needed.
8074 if (length > 0) {
8075 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00008076 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008077 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008078 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
8079 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008080
8081 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008082 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008083 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008084 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008085
8086 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008087 for (int i = 0; i < length; i++) {
8088 array->set(i, *--parameters, mode);
8089 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008090 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008091 }
8092 return result;
8093}
8094
8095
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008096RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008097 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008098 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008099 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008100 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008101 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008102
whesse@chromium.org7b260152011-06-20 15:33:18 +00008103 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008104 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008105 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008106 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008107 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8108 context,
8109 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008110 return *result;
8111}
8112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008113
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008114// Find the arguments of the JavaScript function invocation that called
8115// into C++ code. Collect these in a newly allocated array of handles (possibly
8116// prefixed by a number of empty handles).
8117static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8118 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008119 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008120 // Find frame containing arguments passed to the caller.
8121 JavaScriptFrameIterator it;
8122 JavaScriptFrame* frame = it.frame();
8123 List<JSFunction*> functions(2);
8124 frame->GetFunctions(&functions);
8125 if (functions.length() > 1) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008126 int inlined_jsframe_index = functions.length() - 1;
8127 JSFunction* inlined_function = functions[inlined_jsframe_index];
8128 Vector<SlotRef> args_slots =
8129 SlotRef::ComputeSlotMappingForArguments(
8130 frame,
8131 inlined_jsframe_index,
8132 inlined_function->shared()->formal_parameter_count());
8133
8134 int args_count = args_slots.length();
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008135
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008136 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008137 SmartArrayPointer<Handle<Object> > param_data(
8138 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008139 for (int i = 0; i < args_count; i++) {
8140 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008141 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008142 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008143
8144 args_slots.Dispose();
8145
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008146 return param_data;
8147 } else {
8148 it.AdvanceToArgumentsFrame();
8149 frame = it.frame();
8150 int args_count = frame->ComputeParametersCount();
8151
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008152 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008153 SmartArrayPointer<Handle<Object> > param_data(
8154 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008155 for (int i = 0; i < args_count; i++) {
8156 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008157 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008158 }
8159 return param_data;
8160 }
8161}
8162
8163
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008164RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8165 HandleScope scope(isolate);
8166 ASSERT(args.length() == 4);
8167 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8168 RUNTIME_ASSERT(args[3]->IsNumber());
8169 Handle<Object> bindee = args.at<Object>(1);
8170
8171 // TODO(lrn): Create bound function in C++ code from premade shared info.
8172 bound_function->shared()->set_bound(true);
8173 // Get all arguments of calling function (Function.prototype.bind).
8174 int argc = 0;
8175 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8176 // Don't count the this-arg.
8177 if (argc > 0) {
8178 ASSERT(*arguments[0] == args[2]);
8179 argc--;
8180 } else {
8181 ASSERT(args[2]->IsUndefined());
8182 }
8183 // Initialize array of bindings (function, this, and any existing arguments
8184 // if the function was already bound).
8185 Handle<FixedArray> new_bindings;
8186 int i;
8187 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8188 Handle<FixedArray> old_bindings(
8189 JSFunction::cast(*bindee)->function_bindings());
8190 new_bindings =
8191 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8192 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8193 i = 0;
8194 for (int n = old_bindings->length(); i < n; i++) {
8195 new_bindings->set(i, old_bindings->get(i));
8196 }
8197 } else {
8198 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8199 new_bindings = isolate->factory()->NewFixedArray(array_size);
8200 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8201 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8202 i = 2;
8203 }
8204 // Copy arguments, skipping the first which is "this_arg".
8205 for (int j = 0; j < argc; j++, i++) {
8206 new_bindings->set(i, *arguments[j + 1]);
8207 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008208 new_bindings->set_map_no_write_barrier(
8209 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008210 bound_function->set_function_bindings(*new_bindings);
8211
8212 // Update length.
8213 Handle<String> length_symbol = isolate->factory()->length_symbol();
8214 Handle<Object> new_length(args.at<Object>(3));
8215 PropertyAttributes attr =
8216 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8217 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8218 return *bound_function;
8219}
8220
8221
8222RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8223 HandleScope handles(isolate);
8224 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008225 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008226 if (callable->IsJSFunction()) {
8227 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8228 if (function->shared()->bound()) {
8229 Handle<FixedArray> bindings(function->function_bindings());
8230 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8231 return *isolate->factory()->NewJSArrayWithElements(bindings);
8232 }
8233 }
8234 return isolate->heap()->undefined_value();
8235}
8236
8237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008238RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008239 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008240 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008241 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008242 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008243 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008244
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008245 // The argument is a bound function. Extract its bound arguments
8246 // and callable.
8247 Handle<FixedArray> bound_args =
8248 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8249 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8250 Handle<Object> bound_function(
8251 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8252 ASSERT(!bound_function->IsJSFunction() ||
8253 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008254
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008255 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008256 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008257 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008258 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008259 param_data[i] = Handle<Object>(bound_args->get(
8260 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008261 }
8262
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008263 if (!bound_function->IsJSFunction()) {
8264 bool exception_thrown;
8265 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8266 &exception_thrown);
8267 if (exception_thrown) return Failure::Exception();
8268 }
8269 ASSERT(bound_function->IsJSFunction());
8270
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008271 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008272 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008273 Execution::New(Handle<JSFunction>::cast(bound_function),
8274 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008275 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008276 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008277 }
8278 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008279 return *result;
8280}
8281
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008282
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008283static void TrySettingInlineConstructStub(Isolate* isolate,
8284 Handle<JSFunction> function) {
8285 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008286 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008287 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008288 }
8289 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008290 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008291 Handle<Code> code = compiler.CompileConstructStub(function);
8292 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008293 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008294}
8295
8296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008297RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008298 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008299 ASSERT(args.length() == 1);
8300
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008301 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008302
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008303 // If the constructor isn't a proper function we throw a type error.
8304 if (!constructor->IsJSFunction()) {
8305 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8306 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008307 isolate->factory()->NewTypeError("not_constructor", arguments);
8308 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008309 }
8310
8311 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008312
8313 // If function should not have prototype, construction is not allowed. In this
8314 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008315 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008316 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8317 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008318 isolate->factory()->NewTypeError("not_constructor", arguments);
8319 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008320 }
8321
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008322#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008323 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008324 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008325 if (debug->StepInActive()) {
8326 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008327 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008328#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008329
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008330 if (function->has_initial_map()) {
8331 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008332 // The 'Function' function ignores the receiver object when
8333 // called using 'new' and creates a new JSFunction object that
8334 // is returned. The receiver object is only used for error
8335 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008336 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008337 // allocate JSFunctions since it does not properly initialize
8338 // the shared part of the function. Since the receiver is
8339 // ignored anyway, we use the global object as the receiver
8340 // instead of a new JSFunction object. This way, errors are
8341 // reported the same way whether or not 'Function' is called
8342 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008343 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008344 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008345 }
8346
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008347 // The function should be compiled for the optimization hints to be
8348 // available. We cannot use EnsureCompiled because that forces a
8349 // compilation through the shared function info which makes it
8350 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008351 if (!function->is_compiled()) {
8352 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8353 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008354
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008355 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008356 if (!function->has_initial_map() &&
8357 shared->IsInobjectSlackTrackingInProgress()) {
8358 // The tracking is already in progress for another function. We can only
8359 // track one initial_map at a time, so we force the completion before the
8360 // function is called as a constructor for the first time.
8361 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008362 }
8363
8364 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008365 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8366 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008367 // Delay setting the stub if inobject slack tracking is in progress.
8368 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008369 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008370 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008371
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008372 isolate->counters()->constructed_objects()->Increment();
8373 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008374
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008375 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008376}
8377
8378
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008379RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008380 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008381 ASSERT(args.length() == 1);
8382
8383 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8384 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008385 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008386
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008387 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008388}
8389
8390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008391RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008392 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008393 ASSERT(args.length() == 1);
8394
8395 Handle<JSFunction> function = args.at<JSFunction>(0);
8396#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008397 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008398 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008399 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008400 PrintF("]\n");
8401 }
8402#endif
8403
lrn@chromium.org34e60782011-09-15 07:25:40 +00008404 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008405 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008406 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008407 return Failure::Exception();
8408 }
8409
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008410 // All done. Return the compiled code.
8411 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008412 return function->code();
8413}
8414
8415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008416RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008418 ASSERT(args.length() == 1);
8419 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008420
yangguo@chromium.org78d1ad42012-02-09 13:53:47 +00008421 function->shared()->set_profiler_ticks(0);
8422
lrn@chromium.org34e60782011-09-15 07:25:40 +00008423 // If the function is not compiled ignore the lazy
8424 // recompilation. This can happen if the debugger is activated and
8425 // the function is returned to the not compiled state.
8426 if (!function->shared()->is_compiled()) {
8427 function->ReplaceCode(function->shared()->code());
8428 return function->code();
8429 }
8430
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008431 // If the function is not optimizable or debugger is active continue using the
8432 // code from the full compiler.
8433 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008434 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008435 if (FLAG_trace_opt) {
8436 PrintF("[failed to optimize ");
8437 function->PrintName();
8438 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8439 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008440 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008441 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 function->ReplaceCode(function->shared()->code());
8443 return function->code();
8444 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008445 if (JSFunction::CompileOptimized(function,
8446 AstNode::kNoNumber,
8447 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008448 return function->code();
8449 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008450 if (FLAG_trace_opt) {
8451 PrintF("[failed to optimize ");
8452 function->PrintName();
8453 PrintF(": optimized compilation failed]\n");
8454 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008455 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008456 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008457}
8458
8459
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008460class ActivationsFinder : public ThreadVisitor {
8461 public:
8462 explicit ActivationsFinder(JSFunction* function)
8463 : function_(function), has_activations_(false) {}
8464
8465 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8466 if (has_activations_) return;
8467
8468 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8469 JavaScriptFrame* frame = it.frame();
8470 if (frame->is_optimized() && frame->function() == function_) {
8471 has_activations_ = true;
8472 return;
8473 }
8474 }
8475 }
8476
8477 bool has_activations() { return has_activations_; }
8478
8479 private:
8480 JSFunction* function_;
8481 bool has_activations_;
8482};
8483
8484
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008485RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008486 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008487 ASSERT(args.length() == 1);
8488 RUNTIME_ASSERT(args[0]->IsSmi());
8489 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008490 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008491 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8492 ASSERT(isolate->heap()->IsAllocationAllowed());
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008493 int jsframes = deoptimizer->jsframe_count();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008494
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008495 deoptimizer->MaterializeHeapNumbers();
8496 delete deoptimizer;
8497
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008498 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008499 JavaScriptFrame* frame = NULL;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +00008500 for (int i = 0; i < jsframes - 1; i++) it.Advance();
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008501 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008502
8503 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008504 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008505 Handle<Object> arguments;
8506 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008507 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008508 if (arguments.is_null()) {
8509 // FunctionGetArguments can't throw an exception, so cast away the
8510 // doubt with an assert.
8511 arguments = Handle<Object>(
8512 Accessors::FunctionGetArguments(*function,
8513 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008514 ASSERT(*arguments != isolate->heap()->null_value());
8515 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008516 }
8517 frame->SetExpression(i, *arguments);
8518 }
8519 }
8520
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008521 if (type == Deoptimizer::EAGER) {
8522 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008523 }
8524
8525 // Avoid doing too much work when running with --always-opt and keep
8526 // the optimized code around.
8527 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008528 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008529 }
8530
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008531 // Find other optimized activations of the function.
8532 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008533 while (!it.done()) {
8534 JavaScriptFrame* frame = it.frame();
8535 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008536 has_other_activations = true;
8537 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008538 }
8539 it.Advance();
8540 }
8541
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008542 if (!has_other_activations) {
8543 ActivationsFinder activations_finder(*function);
8544 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8545 has_other_activations = activations_finder.has_activations();
8546 }
8547
8548 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008549 if (FLAG_trace_deopt) {
8550 PrintF("[removing optimized code for: ");
8551 function->PrintName();
8552 PrintF("]\n");
8553 }
8554 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008555 } else {
8556 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008557 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008558 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008559}
8560
8561
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008562RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008563 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008564 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008565 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008566}
8567
8568
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008569RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008570 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008571 ASSERT(args.length() == 1);
8572 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008573 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008574
8575 Deoptimizer::DeoptimizeFunction(*function);
8576
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008577 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008578}
8579
8580
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008581RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8582#if defined(USE_SIMULATOR)
8583 return isolate->heap()->true_value();
8584#else
8585 return isolate->heap()->false_value();
8586#endif
8587}
8588
8589
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008590RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8591 HandleScope scope(isolate);
8592 ASSERT(args.length() == 1);
8593 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8594 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8595 function->MarkForLazyRecompilation();
8596 return isolate->heap()->undefined_value();
8597}
8598
8599
lrn@chromium.org1c092762011-05-09 09:42:16 +00008600RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8601 HandleScope scope(isolate);
8602 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008603 // The least significant bit (after untagging) indicates whether the
8604 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008605 if (!V8::UseCrankshaft()) {
8606 return Smi::FromInt(4); // 4 == "never".
8607 }
8608 if (FLAG_always_opt) {
8609 return Smi::FromInt(3); // 3 == "always".
8610 }
8611 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8612 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8613 : Smi::FromInt(2); // 2 == "no".
8614}
8615
8616
8617RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8618 HandleScope scope(isolate);
8619 ASSERT(args.length() == 1);
8620 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8621 return Smi::FromInt(function->shared()->opt_count());
8622}
8623
8624
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008625RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008626 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008627 ASSERT(args.length() == 1);
8628 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8629
8630 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008631 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008632
8633 // We have hit a back edge in an unoptimized frame for a function that was
8634 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008635 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008636 // Keep track of whether we've succeeded in optimizing.
8637 bool succeeded = unoptimized->optimizable();
8638 if (succeeded) {
8639 // If we are trying to do OSR when there are already optimized
8640 // activations of the function, it means (a) the function is directly or
8641 // indirectly recursive and (b) an optimized invocation has been
8642 // deoptimized so that we are currently in an unoptimized activation.
8643 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008644 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008645 while (succeeded && !it.done()) {
8646 JavaScriptFrame* frame = it.frame();
8647 succeeded = !frame->is_optimized() || frame->function() != *function;
8648 it.Advance();
8649 }
8650 }
8651
8652 int ast_id = AstNode::kNoNumber;
8653 if (succeeded) {
8654 // The top JS function is this one, the PC is somewhere in the
8655 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008656 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008657 JavaScriptFrame* frame = it.frame();
8658 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008659 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008660 ASSERT(unoptimized->contains(frame->pc()));
8661
8662 // Use linear search of the unoptimized code's stack check table to find
8663 // the AST id matching the PC.
8664 Address start = unoptimized->instruction_start();
8665 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008666 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008667 uint32_t table_length = Memory::uint32_at(table_cursor);
8668 table_cursor += kIntSize;
8669 for (unsigned i = 0; i < table_length; ++i) {
8670 // Table entries are (AST id, pc offset) pairs.
8671 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8672 if (pc_offset == target_pc_offset) {
8673 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8674 break;
8675 }
8676 table_cursor += 2 * kIntSize;
8677 }
8678 ASSERT(ast_id != AstNode::kNoNumber);
8679 if (FLAG_trace_osr) {
8680 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8681 function->PrintName();
8682 PrintF("]\n");
8683 }
8684
8685 // Try to compile the optimized code. A true return value from
8686 // CompileOptimized means that compilation succeeded, not necessarily
8687 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008688 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008689 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008690 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8691 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008692 if (data->OsrPcOffset()->value() >= 0) {
8693 if (FLAG_trace_osr) {
8694 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008695 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008696 }
8697 ASSERT(data->OsrAstId()->value() == ast_id);
8698 } else {
8699 // We may never generate the desired OSR entry if we emit an
8700 // early deoptimize.
8701 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008702 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008703 } else {
8704 succeeded = false;
8705 }
8706 }
8707
8708 // Revert to the original stack checks in the original unoptimized code.
8709 if (FLAG_trace_osr) {
8710 PrintF("[restoring original stack checks in ");
8711 function->PrintName();
8712 PrintF("]\n");
8713 }
8714 StackCheckStub check_stub;
8715 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008716 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008717 Deoptimizer::RevertStackCheckCode(*unoptimized,
8718 *check_code,
8719 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008720
8721 // Allow OSR only at nesting level zero again.
8722 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8723
8724 // If the optimization attempt succeeded, return the AST id tagged as a
8725 // smi. This tells the builtin that we need to translate the unoptimized
8726 // frame to an optimized one.
8727 if (succeeded) {
8728 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8729 return Smi::FromInt(ast_id);
8730 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008731 if (function->IsMarkedForLazyRecompilation()) {
8732 function->ReplaceCode(function->shared()->code());
8733 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008734 return Smi::FromInt(-1);
8735 }
8736}
8737
8738
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008739RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8740 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8741 return isolate->heap()->undefined_value();
8742}
8743
8744
danno@chromium.orgc612e022011-11-10 11:38:15 +00008745RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8746 HandleScope scope(isolate);
8747 ASSERT(args.length() >= 2);
8748 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8749 Object* receiver = args[0];
8750 int argc = args.length() - 2;
8751
8752 // If there are too many arguments, allocate argv via malloc.
8753 const int argv_small_size = 10;
8754 Handle<Object> argv_small_buffer[argv_small_size];
8755 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8756 Handle<Object>* argv = argv_small_buffer;
8757 if (argc > argv_small_size) {
8758 argv = new Handle<Object>[argc];
8759 if (argv == NULL) return isolate->StackOverflow();
8760 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8761 }
8762
8763 for (int i = 0; i < argc; ++i) {
8764 MaybeObject* maybe = args[1 + i];
8765 Object* object;
8766 if (!maybe->To<Object>(&object)) return maybe;
8767 argv[i] = Handle<Object>(object);
8768 }
8769
8770 bool threw;
8771 Handle<JSReceiver> hfun(fun);
8772 Handle<Object> hreceiver(receiver);
8773 Handle<Object> result =
8774 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8775
8776 if (threw) return Failure::Exception();
8777 return *result;
8778}
8779
8780
lrn@chromium.org34e60782011-09-15 07:25:40 +00008781RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8782 HandleScope scope(isolate);
8783 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008784 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8785 Handle<Object> receiver = args.at<Object>(1);
8786 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8787 CONVERT_SMI_ARG_CHECKED(offset, 3);
8788 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008789 ASSERT(offset >= 0);
8790 ASSERT(argc >= 0);
8791
8792 // If there are too many arguments, allocate argv via malloc.
8793 const int argv_small_size = 10;
8794 Handle<Object> argv_small_buffer[argv_small_size];
8795 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8796 Handle<Object>* argv = argv_small_buffer;
8797 if (argc > argv_small_size) {
8798 argv = new Handle<Object>[argc];
8799 if (argv == NULL) return isolate->StackOverflow();
8800 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8801 }
8802
8803 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008804 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008805 }
8806
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008807 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008808 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008809 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008810
8811 if (threw) return Failure::Exception();
8812 return *result;
8813}
8814
8815
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008816RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008817 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008818 ASSERT(args.length() == 1);
8819 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8820 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8821}
8822
8823
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008824RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008825 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008826 ASSERT(args.length() == 1);
8827 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8828 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8829}
8830
8831
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008832RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008833 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008834 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008835
kasper.lund7276f142008-07-30 08:49:36 +00008836 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008837 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008838 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008839 { MaybeObject* maybe_result =
8840 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008841 if (!maybe_result->ToObject(&result)) return maybe_result;
8842 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008843
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008844 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008845
kasper.lund7276f142008-07-30 08:49:36 +00008846 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008847}
8848
lrn@chromium.org303ada72010-10-27 09:33:13 +00008849
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008850RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8851 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008852 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008853 JSObject* extension_object;
8854 if (args[0]->IsJSObject()) {
8855 extension_object = JSObject::cast(args[0]);
8856 } else {
8857 // Convert the object to a proper JavaScript object.
8858 MaybeObject* maybe_js_object = args[0]->ToObject();
8859 if (!maybe_js_object->To(&extension_object)) {
8860 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8861 HandleScope scope(isolate);
8862 Handle<Object> handle = args.at<Object>(0);
8863 Handle<Object> result =
8864 isolate->factory()->NewTypeError("with_expression",
8865 HandleVector(&handle, 1));
8866 return isolate->Throw(*result);
8867 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008868 return maybe_js_object;
8869 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008870 }
8871 }
8872
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008873 JSFunction* function;
8874 if (args[1]->IsSmi()) {
8875 // A smi sentinel indicates a context nested inside global code rather
8876 // than some function. There is a canonical empty function that can be
8877 // gotten from the global context.
8878 function = isolate->context()->global_context()->closure();
8879 } else {
8880 function = JSFunction::cast(args[1]);
8881 }
8882
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008883 Context* context;
8884 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008885 isolate->heap()->AllocateWithContext(function,
8886 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008887 extension_object);
8888 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008889 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008890 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008891}
8892
8893
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008894RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008895 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008896 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008897 String* name = String::cast(args[0]);
8898 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008899 JSFunction* function;
8900 if (args[2]->IsSmi()) {
8901 // A smi sentinel indicates a context nested inside global code rather
8902 // than some function. There is a canonical empty function that can be
8903 // gotten from the global context.
8904 function = isolate->context()->global_context()->closure();
8905 } else {
8906 function = JSFunction::cast(args[2]);
8907 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008908 Context* context;
8909 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008910 isolate->heap()->AllocateCatchContext(function,
8911 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008912 name,
8913 thrown_object);
8914 if (!maybe_context->To(&context)) return maybe_context;
8915 isolate->set_context(context);
8916 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008917}
8918
8919
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008920RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8921 NoHandleAllocation ha;
8922 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008923 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008924 JSFunction* function;
8925 if (args[1]->IsSmi()) {
8926 // A smi sentinel indicates a context nested inside global code rather
8927 // than some function. There is a canonical empty function that can be
8928 // gotten from the global context.
8929 function = isolate->context()->global_context()->closure();
8930 } else {
8931 function = JSFunction::cast(args[1]);
8932 }
8933 Context* context;
8934 MaybeObject* maybe_context =
8935 isolate->heap()->AllocateBlockContext(function,
8936 isolate->context(),
8937 scope_info);
8938 if (!maybe_context->To(&context)) return maybe_context;
8939 isolate->set_context(context);
8940 return context;
8941}
8942
8943
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008944RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008945 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008946 ASSERT(args.length() == 2);
8947
8948 CONVERT_ARG_CHECKED(Context, context, 0);
8949 CONVERT_ARG_CHECKED(String, name, 1);
8950
8951 int index;
8952 PropertyAttributes attributes;
8953 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008954 BindingFlags binding_flags;
8955 Handle<Object> holder = context->Lookup(name,
8956 flags,
8957 &index,
8958 &attributes,
8959 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008961 // If the slot was not found the result is true.
8962 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008963 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008964 }
8965
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008966 // If the slot was found in a context, it should be DONT_DELETE.
8967 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008968 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008969 }
8970
8971 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008972 // the global object, or the subject of a with. Try to delete it
8973 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008974 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008975 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008976}
8977
8978
ager@chromium.orga1645e22009-09-09 19:27:10 +00008979// A mechanism to return a pair of Object pointers in registers (if possible).
8980// How this is achieved is calling convention-dependent.
8981// All currently supported x86 compiles uses calling conventions that are cdecl
8982// variants where a 64-bit value is returned in two 32-bit registers
8983// (edx:eax on ia32, r1:r0 on ARM).
8984// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8985// In Win64 calling convention, a struct of two pointers is returned in memory,
8986// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008987#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008988struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008989 MaybeObject* x;
8990 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008991};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008992
lrn@chromium.org303ada72010-10-27 09:33:13 +00008993static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008994 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008995 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8996 // In Win64 they are assigned to a hidden first argument.
8997 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008998}
8999#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009000typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009001static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009002 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009003 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009004}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009005#endif
9006
9007
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009008static inline MaybeObject* Unhole(Heap* heap,
9009 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009010 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9012 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009013 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009014}
9015
9016
danno@chromium.org40cb8782011-05-25 07:58:50 +00009017static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9018 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009019 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009020 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009021 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009022 JSFunction* context_extension_function =
9023 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009024 // If the holder isn't a context extension object, we just return it
9025 // as the receiver. This allows arguments objects to be used as
9026 // receivers, but only if they are put in the context scope chain
9027 // explicitly via a with-statement.
9028 Object* constructor = holder->map()->constructor();
9029 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009030 // Fall back to using the global object as the implicit receiver if
9031 // the property turns out to be a local variable allocated in a
9032 // context extension object - introduced via eval. Implicit global
9033 // receivers are indicated with the hole value.
9034 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009035}
9036
9037
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009038static ObjectPair LoadContextSlotHelper(Arguments args,
9039 Isolate* isolate,
9040 bool throw_error) {
9041 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009042 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009043
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009044 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009045 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009046 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009047 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009048 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009049
9050 int index;
9051 PropertyAttributes attributes;
9052 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009053 BindingFlags binding_flags;
9054 Handle<Object> holder = context->Lookup(name,
9055 flags,
9056 &index,
9057 &attributes,
9058 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009060 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009061 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009062 ASSERT(holder->IsContext());
9063 // If the "property" we were looking for is a local variable, the
9064 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009065 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009066 // Use the hole as the receiver to signal that the receiver is implicit
9067 // and that the global receiver should be used (as distinguished from an
9068 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009069 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009070 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009071 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009072 switch (binding_flags) {
9073 case MUTABLE_CHECK_INITIALIZED:
9074 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9075 if (value->IsTheHole()) {
9076 Handle<Object> reference_error =
9077 isolate->factory()->NewReferenceError("not_defined",
9078 HandleVector(&name, 1));
9079 return MakePair(isolate->Throw(*reference_error), NULL);
9080 }
9081 // FALLTHROUGH
9082 case MUTABLE_IS_INITIALIZED:
9083 case IMMUTABLE_IS_INITIALIZED:
9084 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9085 ASSERT(!value->IsTheHole());
9086 return MakePair(value, *receiver);
9087 case IMMUTABLE_CHECK_INITIALIZED:
9088 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9089 case MISSING_BINDING:
9090 UNREACHABLE();
9091 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009092 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009093 }
9094
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009095 // Otherwise, if the slot was found the holder is a context extension
9096 // object, subject of a with, or a global object. We read the named
9097 // property from it.
9098 if (!holder.is_null()) {
9099 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9100 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009101 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009102 Handle<Object> receiver_handle(object->IsGlobalObject()
9103 ? GlobalObject::cast(*object)->global_receiver()
9104 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009105
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009106 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009107 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009108 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009109 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009110 }
9111
9112 if (throw_error) {
9113 // The property doesn't exist - throw exception.
9114 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009115 isolate->factory()->NewReferenceError("not_defined",
9116 HandleVector(&name, 1));
9117 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009118 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009119 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009120 return MakePair(isolate->heap()->undefined_value(),
9121 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009122 }
9123}
9124
9125
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009126RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009127 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009128}
9129
9130
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009131RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009132 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009133}
9134
9135
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009136RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009137 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009138 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009139
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009140 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009141 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009142 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009143 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9144 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9145 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009146
9147 int index;
9148 PropertyAttributes attributes;
9149 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009150 BindingFlags binding_flags;
9151 Handle<Object> holder = context->Lookup(name,
9152 flags,
9153 &index,
9154 &attributes,
9155 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009156
9157 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009158 // The property was found in a context slot.
9159 Handle<Context> context = Handle<Context>::cast(holder);
9160 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9161 context->get(index)->IsTheHole()) {
9162 Handle<Object> error =
9163 isolate->factory()->NewReferenceError("not_defined",
9164 HandleVector(&name, 1));
9165 return isolate->Throw(*error);
9166 }
9167 // Ignore if read_only variable.
9168 if ((attributes & READ_ONLY) == 0) {
9169 // Context is a fixed array and set cannot fail.
9170 context->set(index, *value);
9171 } else if (strict_mode == kStrictMode) {
9172 // Setting read only property in strict mode.
9173 Handle<Object> error =
9174 isolate->factory()->NewTypeError("strict_cannot_assign",
9175 HandleVector(&name, 1));
9176 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177 }
9178 return *value;
9179 }
9180
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009181 // Slow case: The property is not in a context slot. It is either in a
9182 // context extension object, a property of the subject of a with, or a
9183 // property of the global object.
9184 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009185
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009186 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009187 // The property exists on the holder.
9188 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009189 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009190 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009191 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009192
9193 if (strict_mode == kStrictMode) {
9194 // Throw in strict mode (assignment to undefined variable).
9195 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009196 isolate->factory()->NewReferenceError(
9197 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009198 return isolate->Throw(*error);
9199 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009200 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009201 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009202 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009203 }
9204
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009205 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009206 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009207 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009208 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009209 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009210 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009211 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009212 // Setting read only property in strict mode.
9213 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009214 isolate->factory()->NewTypeError(
9215 "strict_cannot_assign", HandleVector(&name, 1));
9216 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009217 }
9218 return *value;
9219}
9220
9221
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009222RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009224 ASSERT(args.length() == 1);
9225
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009226 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227}
9228
9229
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009230RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009231 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009232 ASSERT(args.length() == 1);
9233
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009234 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009235}
9236
9237
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009238RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009239 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009241}
9242
9243
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009244RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009245 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246 ASSERT(args.length() == 1);
9247
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009248 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009250 isolate->factory()->NewReferenceError("not_defined",
9251 HandleVector(&name, 1));
9252 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009253}
9254
9255
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009256RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009257 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258
9259 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009260 if (isolate->stack_guard()->IsStackOverflow()) {
9261 NoHandleAllocation na;
9262 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009263 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009264
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009265 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266}
9267
9268
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009269static int StackSize() {
9270 int n = 0;
9271 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9272 return n;
9273}
9274
9275
9276static void PrintTransition(Object* result) {
9277 // indentation
9278 { const int nmax = 80;
9279 int n = StackSize();
9280 if (n <= nmax)
9281 PrintF("%4d:%*s", n, n, "");
9282 else
9283 PrintF("%4d:%*s", n, nmax, "...");
9284 }
9285
9286 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009287 JavaScriptFrame::PrintTop(stdout, true, false);
9288 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009289 } else {
9290 // function result
9291 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009292 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009293 PrintF("\n");
9294 }
9295}
9296
9297
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009298RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009299 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009300 NoHandleAllocation ha;
9301 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009302 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009303}
9304
9305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009306RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009307 NoHandleAllocation ha;
9308 PrintTransition(args[0]);
9309 return args[0]; // return TOS
9310}
9311
9312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009313RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009314 NoHandleAllocation ha;
9315 ASSERT(args.length() == 1);
9316
9317#ifdef DEBUG
9318 if (args[0]->IsString()) {
9319 // If we have a string, assume it's a code "marker"
9320 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009321 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009323 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9324 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009325 } else {
9326 PrintF("DebugPrint: ");
9327 }
9328 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009329 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009330 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009331 HeapObject::cast(args[0])->map()->Print();
9332 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009333#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009334 // ShortPrint is available in release mode. Print is not.
9335 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009336#endif
9337 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009338 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009339
9340 return args[0]; // return TOS
9341}
9342
9343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009344RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009345 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009346 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 isolate->PrintStack();
9348 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009349}
9350
9351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009352RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009353 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009354 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009355
9356 // According to ECMA-262, section 15.9.1, page 117, the precision of
9357 // the number in a Date object representing a particular instant in
9358 // time is milliseconds. Therefore, we floor the result of getting
9359 // the OS time.
9360 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009361 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009362}
9363
9364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009365RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009366 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009367 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009368
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009369 CONVERT_ARG_CHECKED(String, str, 0);
9370 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009371
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009372 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009373
9374 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009375 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009376 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009377 RUNTIME_ASSERT(output->HasFastElements());
9378
9379 AssertNoAllocation no_allocation;
9380
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009381 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009382 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9383 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009384 String::FlatContent str_content = str->GetFlatContent();
9385 if (str_content.IsAscii()) {
9386 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009387 output_array,
9388 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009389 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009390 ASSERT(str_content.IsTwoByte());
9391 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009392 output_array,
9393 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009394 }
9395
9396 if (result) {
9397 return *output;
9398 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009399 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009400 }
9401}
9402
9403
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009404RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009405 NoHandleAllocation ha;
9406 ASSERT(args.length() == 1);
9407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009408 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009409 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009410 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411}
9412
9413
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009414RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009415 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009416 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009417
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009418 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009419}
9420
9421
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009422RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009423 NoHandleAllocation ha;
9424 ASSERT(args.length() == 1);
9425
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009426 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009427 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009428}
9429
9430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009431RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009432 ASSERT(args.length() == 1);
9433 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009434 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009435 return JSGlobalObject::cast(global)->global_receiver();
9436}
9437
9438
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009439RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009440 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009441 ASSERT_EQ(1, args.length());
9442 CONVERT_ARG_CHECKED(String, source, 0);
9443
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009444 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009445 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009446 Handle<Object> result;
9447 if (source->IsSeqAsciiString()) {
9448 result = JsonParser<true>::Parse(source);
9449 } else {
9450 result = JsonParser<false>::Parse(source);
9451 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009452 if (result.is_null()) {
9453 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009454 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009455 return Failure::Exception();
9456 }
9457 return *result;
9458}
9459
9460
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009461bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9462 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009463 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9464 // Check with callback if set.
9465 AllowCodeGenerationFromStringsCallback callback =
9466 isolate->allow_code_gen_callback();
9467 if (callback == NULL) {
9468 // No callback set and code generation disallowed.
9469 return false;
9470 } else {
9471 // Callback set. Let it decide if code generation is allowed.
9472 VMState state(isolate, EXTERNAL);
9473 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009474 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009475}
9476
9477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009478RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009479 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009480 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009481 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009482
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009483 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009484 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009485
9486 // Check if global context allows code generation from
9487 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009488 if (context->allow_code_gen_from_strings()->IsFalse() &&
9489 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009490 return isolate->Throw(*isolate->factory()->NewError(
9491 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9492 }
9493
9494 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009495 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009496 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009497 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009498 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009499 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9500 context,
9501 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009502 return *fun;
9503}
9504
9505
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009506static ObjectPair CompileGlobalEval(Isolate* isolate,
9507 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009508 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009509 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009510 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009511 Handle<Context> context = Handle<Context>(isolate->context());
9512 Handle<Context> global_context = Handle<Context>(context->global_context());
9513
9514 // Check if global context allows code generation from
9515 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009516 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9517 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009518 isolate->Throw(*isolate->factory()->NewError(
9519 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9520 return MakePair(Failure::Exception(), NULL);
9521 }
9522
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009523 // Deal with a normal eval call with a string argument. Compile it
9524 // and return the compiled function bound in the local context.
9525 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9526 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009527 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009528 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009529 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009530 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009531 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009532 Handle<JSFunction> compiled =
9533 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009534 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009535 return MakePair(*compiled, *receiver);
9536}
9537
9538
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009539RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009540 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009541
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009543 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009544
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009545 // If "eval" didn't refer to the original GlobalEval, it's not a
9546 // direct call to eval.
9547 // (And even if it is, but the first argument isn't a string, just let
9548 // execution default to an indirect call to eval, which will also return
9549 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009550 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009551 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009552 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009553 }
9554
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009555 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009556 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557 return CompileGlobalEval(isolate,
9558 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009559 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009560 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009561 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009562}
9563
9564
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009565RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009566 // This utility adjusts the property attributes for newly created Function
9567 // object ("new Function(...)") by changing the map.
9568 // All it does is changing the prototype property to enumerable
9569 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009570 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009571 ASSERT(args.length() == 1);
9572 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009573
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009574 Handle<Map> map = func->shared()->is_classic_mode()
9575 ? isolate->function_instance_map()
9576 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009577
9578 ASSERT(func->map()->instance_type() == map->instance_type());
9579 ASSERT(func->map()->instance_size() == map->instance_size());
9580 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009581 return *func;
9582}
9583
9584
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009585RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009586 // Allocate a block of memory in NewSpace (filled with a filler).
9587 // Use as fallback for allocation in generated code when NewSpace
9588 // is full.
9589 ASSERT(args.length() == 1);
9590 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9591 int size = size_smi->value();
9592 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9593 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009594 Heap* heap = isolate->heap();
9595 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009596 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009597 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009598 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009599 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009600 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009601 }
9602 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009603 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009604}
9605
9606
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009607// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009608// array. Returns true if the element was pushed on the stack and
9609// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009610RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009611 ASSERT(args.length() == 2);
9612 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009613 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009614 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009615 int length = Smi::cast(array->length())->value();
9616 FixedArray* elements = FixedArray::cast(array->elements());
9617 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009618 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009619 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009620 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009621 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009622 { MaybeObject* maybe_obj =
9623 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009624 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9625 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009626 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009627}
9628
9629
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009630/**
9631 * A simple visitor visits every element of Array's.
9632 * The backend storage can be a fixed array for fast elements case,
9633 * or a dictionary for sparse array. Since Dictionary is a subtype
9634 * of FixedArray, the class can be used by both fast and slow cases.
9635 * The second parameter of the constructor, fast_elements, specifies
9636 * whether the storage is a FixedArray or Dictionary.
9637 *
9638 * An index limit is used to deal with the situation that a result array
9639 * length overflows 32-bit non-negative integer.
9640 */
9641class ArrayConcatVisitor {
9642 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009643 ArrayConcatVisitor(Isolate* isolate,
9644 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009645 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009646 isolate_(isolate),
9647 storage_(Handle<FixedArray>::cast(
9648 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009649 index_offset_(0u),
9650 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009651
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009652 ~ArrayConcatVisitor() {
9653 clear_storage();
9654 }
9655
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009656 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009657 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009658 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009659
9660 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009661 if (index < static_cast<uint32_t>(storage_->length())) {
9662 storage_->set(index, *elm);
9663 return;
9664 }
9665 // Our initial estimate of length was foiled, possibly by
9666 // getters on the arrays increasing the length of later arrays
9667 // during iteration.
9668 // This shouldn't happen in anything but pathological cases.
9669 SetDictionaryMode(index);
9670 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009671 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009672 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009673 Handle<SeededNumberDictionary> dict(
9674 SeededNumberDictionary::cast(*storage_));
9675 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009676 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009677 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009678 // Dictionary needed to grow.
9679 clear_storage();
9680 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009681 }
9682}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009683
9684 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009685 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9686 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009687 } else {
9688 index_offset_ += delta;
9689 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009690 }
9691
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009692 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009693 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009694 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009695 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009696 Handle<Map> map;
9697 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009698 map = isolate_->factory()->GetElementsTransitionMap(array,
9699 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009700 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009701 map = isolate_->factory()->GetElementsTransitionMap(array,
9702 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009703 }
9704 array->set_map(*map);
9705 array->set_length(*length);
9706 array->set_elements(*storage_);
9707 return array;
9708 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009709
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009710 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009711 // Convert storage to dictionary mode.
9712 void SetDictionaryMode(uint32_t index) {
9713 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009714 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009715 Handle<SeededNumberDictionary> slow_storage(
9716 isolate_->factory()->NewSeededNumberDictionary(
9717 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009718 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9719 for (uint32_t i = 0; i < current_length; i++) {
9720 HandleScope loop_scope;
9721 Handle<Object> element(current_storage->get(i));
9722 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009723 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009724 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009725 if (!new_storage.is_identical_to(slow_storage)) {
9726 slow_storage = loop_scope.CloseAndEscape(new_storage);
9727 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009728 }
9729 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009730 clear_storage();
9731 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009732 fast_elements_ = false;
9733 }
9734
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009735 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009736 isolate_->global_handles()->Destroy(
9737 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009738 }
9739
9740 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009741 storage_ = Handle<FixedArray>::cast(
9742 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009743 }
9744
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009745 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009746 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009747 // Index after last seen index. Always less than or equal to
9748 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009749 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009750 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009751};
9752
9753
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009754static uint32_t EstimateElementCount(Handle<JSArray> array) {
9755 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9756 int element_count = 0;
9757 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009758 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009759 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009760 // Fast elements can't have lengths that are not representable by
9761 // a 32-bit signed integer.
9762 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9763 int fast_length = static_cast<int>(length);
9764 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9765 for (int i = 0; i < fast_length; i++) {
9766 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009767 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009768 break;
9769 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009770 case FAST_DOUBLE_ELEMENTS:
9771 // TODO(1810): Decide if it's worthwhile to implement this.
9772 UNREACHABLE();
9773 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009774 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009775 Handle<SeededNumberDictionary> dictionary(
9776 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009777 int capacity = dictionary->Capacity();
9778 for (int i = 0; i < capacity; i++) {
9779 Handle<Object> key(dictionary->KeyAt(i));
9780 if (dictionary->IsKey(*key)) {
9781 element_count++;
9782 }
9783 }
9784 break;
9785 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009786 case NON_STRICT_ARGUMENTS_ELEMENTS:
9787 case EXTERNAL_BYTE_ELEMENTS:
9788 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9789 case EXTERNAL_SHORT_ELEMENTS:
9790 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9791 case EXTERNAL_INT_ELEMENTS:
9792 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9793 case EXTERNAL_FLOAT_ELEMENTS:
9794 case EXTERNAL_DOUBLE_ELEMENTS:
9795 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009796 // External arrays are always dense.
9797 return length;
9798 }
9799 // As an estimate, we assume that the prototype doesn't contain any
9800 // inherited elements.
9801 return element_count;
9802}
9803
9804
9805
9806template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009807static void IterateExternalArrayElements(Isolate* isolate,
9808 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009809 bool elements_are_ints,
9810 bool elements_are_guaranteed_smis,
9811 ArrayConcatVisitor* visitor) {
9812 Handle<ExternalArrayClass> array(
9813 ExternalArrayClass::cast(receiver->elements()));
9814 uint32_t len = static_cast<uint32_t>(array->length());
9815
9816 ASSERT(visitor != NULL);
9817 if (elements_are_ints) {
9818 if (elements_are_guaranteed_smis) {
9819 for (uint32_t j = 0; j < len; j++) {
9820 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009821 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009822 visitor->visit(j, e);
9823 }
9824 } else {
9825 for (uint32_t j = 0; j < len; j++) {
9826 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009827 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009828 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9829 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9830 visitor->visit(j, e);
9831 } else {
9832 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009833 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 visitor->visit(j, e);
9835 }
9836 }
9837 }
9838 } else {
9839 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009840 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009841 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009842 visitor->visit(j, e);
9843 }
9844 }
9845}
9846
9847
9848// Used for sorting indices in a List<uint32_t>.
9849static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9850 uint32_t a = *ap;
9851 uint32_t b = *bp;
9852 return (a == b) ? 0 : (a < b) ? -1 : 1;
9853}
9854
9855
9856static void CollectElementIndices(Handle<JSObject> object,
9857 uint32_t range,
9858 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009859 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009860 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009861 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009862 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009863 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9864 uint32_t length = static_cast<uint32_t>(elements->length());
9865 if (range < length) length = range;
9866 for (uint32_t i = 0; i < length; i++) {
9867 if (!elements->get(i)->IsTheHole()) {
9868 indices->Add(i);
9869 }
9870 }
9871 break;
9872 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009873 case FAST_DOUBLE_ELEMENTS: {
9874 // TODO(1810): Decide if it's worthwhile to implement this.
9875 UNREACHABLE();
9876 break;
9877 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009878 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009879 Handle<SeededNumberDictionary> dict(
9880 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009881 uint32_t capacity = dict->Capacity();
9882 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009883 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009884 Handle<Object> k(dict->KeyAt(j));
9885 if (dict->IsKey(*k)) {
9886 ASSERT(k->IsNumber());
9887 uint32_t index = static_cast<uint32_t>(k->Number());
9888 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009889 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009890 }
9891 }
9892 }
9893 break;
9894 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009895 default: {
9896 int dense_elements_length;
9897 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009898 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009899 dense_elements_length =
9900 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009901 break;
9902 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009903 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009904 dense_elements_length =
9905 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009906 break;
9907 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009908 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009909 dense_elements_length =
9910 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009911 break;
9912 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009913 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009914 dense_elements_length =
9915 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009916 break;
9917 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009918 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009919 dense_elements_length =
9920 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009921 break;
9922 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009923 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009924 dense_elements_length =
9925 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009926 break;
9927 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009928 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009929 dense_elements_length =
9930 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009931 break;
9932 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009933 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009934 dense_elements_length =
9935 ExternalFloatArray::cast(object->elements())->length();
9936 break;
9937 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009938 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009939 dense_elements_length =
9940 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009941 break;
9942 }
9943 default:
9944 UNREACHABLE();
9945 dense_elements_length = 0;
9946 break;
9947 }
9948 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9949 if (range <= length) {
9950 length = range;
9951 // We will add all indices, so we might as well clear it first
9952 // and avoid duplicates.
9953 indices->Clear();
9954 }
9955 for (uint32_t i = 0; i < length; i++) {
9956 indices->Add(i);
9957 }
9958 if (length == range) return; // All indices accounted for already.
9959 break;
9960 }
9961 }
9962
9963 Handle<Object> prototype(object->GetPrototype());
9964 if (prototype->IsJSObject()) {
9965 // The prototype will usually have no inherited element indices,
9966 // but we have to check.
9967 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9968 }
9969}
9970
9971
9972/**
9973 * A helper function that visits elements of a JSArray in numerical
9974 * order.
9975 *
9976 * The visitor argument called for each existing element in the array
9977 * with the element index and the element's value.
9978 * Afterwards it increments the base-index of the visitor by the array
9979 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009980 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009981 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009982static bool IterateElements(Isolate* isolate,
9983 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 ArrayConcatVisitor* visitor) {
9985 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9986 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009987 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 // Run through the elements FixedArray and use HasElement and GetElement
9990 // to check the prototype for missing elements.
9991 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9992 int fast_length = static_cast<int>(length);
9993 ASSERT(fast_length <= elements->length());
9994 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009995 HandleScope loop_scope(isolate);
9996 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009997 if (!element_value->IsTheHole()) {
9998 visitor->visit(j, element_value);
9999 } else if (receiver->HasElement(j)) {
10000 // Call GetElement on receiver, not its prototype, or getters won't
10001 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010002 element_value = Object::GetElement(receiver, j);
10003 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 visitor->visit(j, element_value);
10005 }
10006 }
10007 break;
10008 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010009 case FAST_DOUBLE_ELEMENTS: {
10010 // TODO(1810): Decide if it's worthwhile to implement this.
10011 UNREACHABLE();
10012 break;
10013 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010014 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010015 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010016 List<uint32_t> indices(dict->Capacity() / 2);
10017 // Collect all indices in the object and the prototypes less
10018 // than length. This might introduce duplicates in the indices list.
10019 CollectElementIndices(receiver, length, &indices);
10020 indices.Sort(&compareUInt32);
10021 int j = 0;
10022 int n = indices.length();
10023 while (j < n) {
10024 HandleScope loop_scope;
10025 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010026 Handle<Object> element = Object::GetElement(receiver, index);
10027 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010028 visitor->visit(index, element);
10029 // Skip to next different index (i.e., omit duplicates).
10030 do {
10031 j++;
10032 } while (j < n && indices[j] == index);
10033 }
10034 break;
10035 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010036 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010037 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10038 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010039 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010040 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010041 visitor->visit(j, e);
10042 }
10043 break;
10044 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010045 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010046 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010047 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010048 break;
10049 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010050 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010051 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010052 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010053 break;
10054 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010055 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010056 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010057 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010058 break;
10059 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010060 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010061 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010062 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010063 break;
10064 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010065 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010066 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010068 break;
10069 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010070 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010071 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010072 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010073 break;
10074 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010075 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010076 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010077 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010078 break;
10079 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010080 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010081 IterateExternalArrayElements<ExternalDoubleArray, double>(
10082 isolate, receiver, false, false, visitor);
10083 break;
10084 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010085 default:
10086 UNREACHABLE();
10087 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010088 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010089 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010090 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010091}
10092
10093
10094/**
10095 * Array::concat implementation.
10096 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010097 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010098 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010099 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010100RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010101 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010102 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010103
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010104 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10105 int argument_count = static_cast<int>(arguments->length()->Number());
10106 RUNTIME_ASSERT(arguments->HasFastElements());
10107 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010108
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010109 // Pass 1: estimate the length and number of elements of the result.
10110 // The actual length can be larger if any of the arguments have getters
10111 // that mutate other arguments (but will otherwise be precise).
10112 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010113
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010114 uint32_t estimate_result_length = 0;
10115 uint32_t estimate_nof_elements = 0;
10116 {
10117 for (int i = 0; i < argument_count; i++) {
10118 HandleScope loop_scope;
10119 Handle<Object> obj(elements->get(i));
10120 uint32_t length_estimate;
10121 uint32_t element_estimate;
10122 if (obj->IsJSArray()) {
10123 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010124 // TODO(1810): Find out if it's worthwhile to properly support
10125 // arbitrary ElementsKinds. For now, pessimistically transition to
10126 // FAST_ELEMENTS.
10127 if (array->HasFastDoubleElements()) {
10128 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010129 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010130 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010131 length_estimate =
10132 static_cast<uint32_t>(array->length()->Number());
10133 element_estimate =
10134 EstimateElementCount(array);
10135 } else {
10136 length_estimate = 1;
10137 element_estimate = 1;
10138 }
10139 // Avoid overflows by capping at kMaxElementCount.
10140 if (JSObject::kMaxElementCount - estimate_result_length <
10141 length_estimate) {
10142 estimate_result_length = JSObject::kMaxElementCount;
10143 } else {
10144 estimate_result_length += length_estimate;
10145 }
10146 if (JSObject::kMaxElementCount - estimate_nof_elements <
10147 element_estimate) {
10148 estimate_nof_elements = JSObject::kMaxElementCount;
10149 } else {
10150 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010151 }
10152 }
10153 }
10154
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010155 // If estimated number of elements is more than half of length, a
10156 // fixed array (fast case) is more time and space-efficient than a
10157 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010158 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010159
10160 Handle<FixedArray> storage;
10161 if (fast_case) {
10162 // The backing storage array must have non-existing elements to
10163 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010164 storage = isolate->factory()->NewFixedArrayWithHoles(
10165 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010166 } else {
10167 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10168 uint32_t at_least_space_for = estimate_nof_elements +
10169 (estimate_nof_elements >> 2);
10170 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010171 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010172 }
10173
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010174 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010175
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010176 for (int i = 0; i < argument_count; i++) {
10177 Handle<Object> obj(elements->get(i));
10178 if (obj->IsJSArray()) {
10179 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010180 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010181 return Failure::Exception();
10182 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010183 } else {
10184 visitor.visit(0, obj);
10185 visitor.increase_index_offset(1);
10186 }
10187 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010188
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010189 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010190}
10191
10192
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010193// This will not allocate (flatten the string), but it may run
10194// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010195RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010196 NoHandleAllocation ha;
10197 ASSERT(args.length() == 1);
10198
10199 CONVERT_CHECKED(String, string, args[0]);
10200 StringInputBuffer buffer(string);
10201 while (buffer.has_more()) {
10202 uint16_t character = buffer.GetNext();
10203 PrintF("%c", character);
10204 }
10205 return string;
10206}
10207
ager@chromium.org5ec48922009-05-05 07:25:34 +000010208// Moves all own elements of an object, that are below a limit, to positions
10209// starting at zero. All undefined values are placed after non-undefined values,
10210// and are followed by non-existing element. Does not change the length
10211// property.
10212// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010213RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010214 ASSERT(args.length() == 2);
10215 CONVERT_CHECKED(JSObject, object, args[0]);
10216 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10217 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010218}
10219
10220
10221// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010222RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223 ASSERT(args.length() == 2);
10224 CONVERT_CHECKED(JSArray, from, args[0]);
10225 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010226 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010227 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010228 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010229 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10230 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010231 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010232 } else if (new_elements->map() ==
10233 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010234 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010235 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010236 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010237 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010238 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010239 Object* new_map;
10240 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010241 to->set_map(Map::cast(new_map));
10242 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010243 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010244 Object* obj;
10245 { MaybeObject* maybe_obj = from->ResetElements();
10246 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10247 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010248 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010249 return to;
10250}
10251
10252
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010253// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010254RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010256 CONVERT_CHECKED(JSObject, object, args[0]);
10257 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010259 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10260 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010261 } else if (object->IsJSArray()) {
10262 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010263 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010264 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 }
10266}
10267
10268
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010269RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010270 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010271
10272 ASSERT_EQ(3, args.length());
10273
ager@chromium.orgac091b72010-05-05 07:34:42 +000010274 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010275 Handle<Object> key1 = args.at<Object>(1);
10276 Handle<Object> key2 = args.at<Object>(2);
10277
10278 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010279 if (!key1->ToArrayIndex(&index1)
10280 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010281 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010282 }
10283
ager@chromium.orgac091b72010-05-05 07:34:42 +000010284 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010285 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010286 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010287 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010288 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010289
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010290 RETURN_IF_EMPTY_HANDLE(
10291 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10292 RETURN_IF_EMPTY_HANDLE(
10293 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010294
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010295 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010296}
10297
10298
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010299// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010300// might have elements. Can either return keys (positive integers) or
10301// intervals (pair of a negative integer (-start-1) followed by a
10302// positive (length)) or undefined values.
10303// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010304RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010305 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010306 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010307 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010308 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010309 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010310 // Create an array and get all the keys into it, then remove all the
10311 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010312 bool threw = false;
10313 Handle<FixedArray> keys =
10314 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10315 if (threw) return Failure::Exception();
10316
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317 int keys_length = keys->length();
10318 for (int i = 0; i < keys_length; i++) {
10319 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010320 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010321 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010322 // Zap invalid keys.
10323 keys->set_undefined(i);
10324 }
10325 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010326 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010327 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010328 ASSERT(array->HasFastElements() ||
10329 array->HasFastSmiOnlyElements() ||
10330 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010333 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010334 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010335 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010336 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010337 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010338 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010339 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010340 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342 }
10343}
10344
10345
10346// DefineAccessor takes an optional final argument which is the
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010347// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010348// to the way accessors are implemented, it is set for both the getter
10349// and setter on the first call to DefineAccessor and ignored on
10350// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010351RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010352 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10353 // Compute attributes.
10354 PropertyAttributes attributes = NONE;
10355 if (args.length() == 5) {
10356 CONVERT_CHECKED(Smi, attrs, args[4]);
10357 int value = attrs->value();
10358 // Only attribute bits should be set.
10359 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10360 attributes = static_cast<PropertyAttributes>(value);
10361 }
10362
10363 CONVERT_CHECKED(JSObject, obj, args[0]);
10364 CONVERT_CHECKED(String, name, args[1]);
10365 CONVERT_CHECKED(Smi, flag, args[2]);
10366 CONVERT_CHECKED(JSFunction, fun, args[3]);
10367 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10368}
10369
10370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010371RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010372 ASSERT(args.length() == 3);
10373 CONVERT_CHECKED(JSObject, obj, args[0]);
10374 CONVERT_CHECKED(String, name, args[1]);
10375 CONVERT_CHECKED(Smi, flag, args[2]);
10376 return obj->LookupAccessor(name, flag->value() == 0);
10377}
10378
10379
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010380#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010381RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010382 ASSERT(args.length() == 0);
10383 return Execution::DebugBreakHelper();
10384}
10385
10386
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010387// Helper functions for wrapping and unwrapping stack frame ids.
10388static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010389 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010390 return Smi::FromInt(id >> 2);
10391}
10392
10393
10394static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10395 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10396}
10397
10398
10399// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010400// args[0]: debug event listener function to set or null or undefined for
10401// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010403RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010404 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010405 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10406 args[0]->IsUndefined() ||
10407 args[0]->IsNull());
10408 Handle<Object> callback = args.at<Object>(0);
10409 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010410 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010412 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010413}
10414
10415
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010416RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010417 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010418 isolate->stack_guard()->DebugBreak();
10419 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010420}
10421
10422
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010423static MaybeObject* DebugLookupResultValue(Heap* heap,
10424 Object* receiver,
10425 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010426 LookupResult* result,
10427 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010428 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010429 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010430 case NORMAL:
10431 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010432 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010433 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010434 }
10435 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010436 case FIELD:
10437 value =
10438 JSObject::cast(
10439 result->holder())->FastPropertyAt(result->GetFieldIndex());
10440 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010441 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010442 }
10443 return value;
10444 case CONSTANT_FUNCTION:
10445 return result->GetConstantFunction();
10446 case CALLBACKS: {
10447 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010448 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010449 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10450 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010451 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010452 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010453 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010454 maybe_value = heap->isolate()->pending_exception();
10455 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010456 if (caught_exception != NULL) {
10457 *caught_exception = true;
10458 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010459 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010460 }
10461 return value;
10462 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010463 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010464 }
10465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010466 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010467 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010468 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010469 case CONSTANT_TRANSITION:
10470 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010471 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010472 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010473 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010474 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010475 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010476 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010478}
10479
10480
ager@chromium.org32912102009-01-16 10:38:43 +000010481// Get debugger related details for an object property.
10482// args[0]: object holding property
10483// args[1]: name of the property
10484//
10485// The array returned contains the following information:
10486// 0: Property value
10487// 1: Property details
10488// 2: Property value is exception
10489// 3: Getter function if defined
10490// 4: Setter function if defined
10491// Items 2-4 are only filled if the property has either a getter or a setter
10492// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010493RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010494 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010495
10496 ASSERT(args.length() == 2);
10497
10498 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10499 CONVERT_ARG_CHECKED(String, name, 1);
10500
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010501 // Make sure to set the current context to the context before the debugger was
10502 // entered (if the debugger is entered). The reason for switching context here
10503 // is that for some property lookups (accessors and interceptors) callbacks
10504 // into the embedding application can occour, and the embedding application
10505 // could have the assumption that its own global context is the current
10506 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010507 SaveContext save(isolate);
10508 if (isolate->debug()->InDebugger()) {
10509 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010510 }
10511
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010512 // Skip the global proxy as it has no properties and always delegates to the
10513 // real global object.
10514 if (obj->IsJSGlobalProxy()) {
10515 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10516 }
10517
10518
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010519 // Check if the name is trivially convertible to an index and get the element
10520 // if so.
10521 uint32_t index;
10522 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010523 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010524 Object* element_or_char;
10525 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010526 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010527 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10528 return maybe_element_or_char;
10529 }
10530 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010531 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010532 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010533 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 }
10535
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010536 // Find the number of objects making up this.
10537 int length = LocalPrototypeChainLength(*obj);
10538
10539 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010540 Handle<JSObject> jsproto = obj;
10541 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010542 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010543 jsproto->LocalLookup(*name, &result);
10544 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010545 // LookupResult is not GC safe as it holds raw object pointers.
10546 // GC can happen later in this code so put the required fields into
10547 // local variables using handles when required for later use.
10548 PropertyType result_type = result.type();
10549 Handle<Object> result_callback_obj;
10550 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010551 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10552 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010553 }
10554 Smi* property_details = result.GetPropertyDetails().AsSmi();
10555 // DebugLookupResultValue can cause GC so details from LookupResult needs
10556 // to be copied to handles before this.
10557 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010558 Object* raw_value;
10559 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010560 DebugLookupResultValue(isolate->heap(), *obj, *name,
10561 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010562 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10563 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010564 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010565
10566 // If the callback object is a fixed array then it contains JavaScript
10567 // getter and/or setter.
10568 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010569 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010570 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010571 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010572 details->set(0, *value);
10573 details->set(1, property_details);
10574 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010575 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010576 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10577 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010578 }
10579
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010580 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010581 }
10582 if (i < length - 1) {
10583 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10584 }
10585 }
10586
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010587 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588}
10589
10590
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010591RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010592 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010593
10594 ASSERT(args.length() == 2);
10595
10596 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10597 CONVERT_ARG_CHECKED(String, name, 1);
10598
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010599 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010600 obj->Lookup(*name, &result);
10601 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010604 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010605}
10606
10607
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608// Return the property type calculated from the property details.
10609// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010610RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010611 ASSERT(args.length() == 1);
10612 CONVERT_CHECKED(Smi, details, args[0]);
10613 PropertyType type = PropertyDetails(details).type();
10614 return Smi::FromInt(static_cast<int>(type));
10615}
10616
10617
10618// Return the property attribute calculated from the property details.
10619// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010620RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010621 ASSERT(args.length() == 1);
10622 CONVERT_CHECKED(Smi, details, args[0]);
10623 PropertyAttributes attributes = PropertyDetails(details).attributes();
10624 return Smi::FromInt(static_cast<int>(attributes));
10625}
10626
10627
10628// Return the property insertion index calculated from the property details.
10629// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010630RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010631 ASSERT(args.length() == 1);
10632 CONVERT_CHECKED(Smi, details, args[0]);
10633 int index = PropertyDetails(details).index();
10634 return Smi::FromInt(index);
10635}
10636
10637
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010638// Return property value from named interceptor.
10639// args[0]: object
10640// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010641RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010642 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010643 ASSERT(args.length() == 2);
10644 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10645 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10646 CONVERT_ARG_CHECKED(String, name, 1);
10647
10648 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010649 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010650}
10651
10652
10653// Return element value from indexed interceptor.
10654// args[0]: object
10655// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010656RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010657 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010658 ASSERT(args.length() == 2);
10659 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10660 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10661 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10662
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010663 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010664}
10665
10666
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010667RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010668 ASSERT(args.length() >= 1);
10669 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010670 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010671 if (isolate->debug()->break_id() == 0 ||
10672 break_id != isolate->debug()->break_id()) {
10673 return isolate->Throw(
10674 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010675 }
10676
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010677 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010678}
10679
10680
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010681RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010682 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010683 ASSERT(args.length() == 1);
10684
10685 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010686 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010687 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10688 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010689 if (!maybe_result->ToObject(&result)) return maybe_result;
10690 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010691
10692 // Count all frames which are relevant to debugging stack trace.
10693 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010694 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010695 if (id == StackFrame::NO_ID) {
10696 // If there is no JavaScript stack frame count is 0.
10697 return Smi::FromInt(0);
10698 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010699
10700 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10701 n += it.frame()->GetInlineCount();
10702 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010703 return Smi::FromInt(n);
10704}
10705
10706
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010707class FrameInspector {
10708 public:
10709 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010710 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010711 Isolate* isolate)
10712 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10713 // Calculate the deoptimized frame.
10714 if (frame->is_optimized()) {
10715 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010716 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010717 }
10718 has_adapted_arguments_ = frame_->has_adapted_arguments();
10719 is_optimized_ = frame_->is_optimized();
10720 }
10721
10722 ~FrameInspector() {
10723 // Get rid of the calculated deoptimized frame if any.
10724 if (deoptimized_frame_ != NULL) {
10725 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10726 isolate_);
10727 }
10728 }
10729
10730 int GetParametersCount() {
10731 return is_optimized_
10732 ? deoptimized_frame_->parameters_count()
10733 : frame_->ComputeParametersCount();
10734 }
10735 int expression_count() { return deoptimized_frame_->expression_count(); }
10736 Object* GetFunction() {
10737 return is_optimized_
10738 ? deoptimized_frame_->GetFunction()
10739 : frame_->function();
10740 }
10741 Object* GetParameter(int index) {
10742 return is_optimized_
10743 ? deoptimized_frame_->GetParameter(index)
10744 : frame_->GetParameter(index);
10745 }
10746 Object* GetExpression(int index) {
10747 return is_optimized_
10748 ? deoptimized_frame_->GetExpression(index)
10749 : frame_->GetExpression(index);
10750 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010751 int GetSourcePosition() {
10752 return is_optimized_
10753 ? deoptimized_frame_->GetSourcePosition()
10754 : frame_->LookupCode()->SourcePosition(frame_->pc());
10755 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010756
10757 // To inspect all the provided arguments the frame might need to be
10758 // replaced with the arguments frame.
10759 void SetArgumentsFrame(JavaScriptFrame* frame) {
10760 ASSERT(has_adapted_arguments_);
10761 frame_ = frame;
10762 is_optimized_ = frame_->is_optimized();
10763 ASSERT(!is_optimized_);
10764 }
10765
10766 private:
10767 JavaScriptFrame* frame_;
10768 DeoptimizedFrameInfo* deoptimized_frame_;
10769 Isolate* isolate_;
10770 bool is_optimized_;
10771 bool has_adapted_arguments_;
10772
10773 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10774};
10775
10776
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010777static const int kFrameDetailsFrameIdIndex = 0;
10778static const int kFrameDetailsReceiverIndex = 1;
10779static const int kFrameDetailsFunctionIndex = 2;
10780static const int kFrameDetailsArgumentCountIndex = 3;
10781static const int kFrameDetailsLocalCountIndex = 4;
10782static const int kFrameDetailsSourcePositionIndex = 5;
10783static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010784static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010785static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010786static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010787
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010788
10789static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10790 JavaScriptFrame* frame) {
10791 SaveContext* save = isolate->save_context();
10792 while (save != NULL && !save->IsBelowFrame(frame)) {
10793 save = save->prev();
10794 }
10795 ASSERT(save != NULL);
10796 return save;
10797}
10798
10799
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010800// Return an array with frame details
10801// args[0]: number: break id
10802// args[1]: number: frame index
10803//
10804// The array returned contains the following information:
10805// 0: Frame id
10806// 1: Receiver
10807// 2: Function
10808// 3: Argument count
10809// 4: Local count
10810// 5: Source position
10811// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010812// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010813// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010814// Arguments name, value
10815// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010816// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010817RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010818 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010819 ASSERT(args.length() == 2);
10820
10821 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010822 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010823 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10824 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010825 if (!maybe_check->ToObject(&check)) return maybe_check;
10826 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010827 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010828 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010829
10830 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010831 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010832 if (id == StackFrame::NO_ID) {
10833 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010834 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010835 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010836
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010837 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010838 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010839 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010840 if (index < count + it.frame()->GetInlineCount()) break;
10841 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010845 bool is_optimized = it.frame()->is_optimized();
10846
10847 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10848 if (is_optimized) {
10849 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010850 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010851 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010852 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010853
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854 // Traverse the saved contexts chain to find the active context for the
10855 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010856 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857
10858 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010859 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010860
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010861 // Find source position in unoptimized code.
10862 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010863
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010864 // Check for constructor frame. Inlined frames cannot be construct calls.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010865 bool inlined_frame = is_optimized && inlined_jsframe_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010866 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010867
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010868 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010869 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010870 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010871 Handle<ScopeInfo> scope_info(shared->scope_info());
10872 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010873
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010874 // Get the locals names and values into a temporary array.
10875 //
10876 // TODO(1240907): Hide compiler-introduced stack variables
10877 // (e.g. .result)? For users of the debugger, they will probably be
10878 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010879 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010880 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010881
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010882 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010883 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010884 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010885 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010886 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010887 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010888 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010889 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010890 // Get the context containing declarations.
10891 Handle<Context> context(
10892 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010893 for (; i < scope_info->LocalCount(); ++i) {
10894 Handle<String> name(scope_info->LocalName(i));
10895 VariableMode mode;
10896 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010897 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010898 locals->set(i * 2 + 1, context->get(
10899 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900 }
10901 }
10902
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010903 // Check whether this frame is positioned at return. If not top
10904 // frame or if the frame is optimized it cannot be at a return.
10905 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010906 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010907 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010908 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010909
10910 // If positioned just before return find the value to be returned and add it
10911 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010912 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010913 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010914 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010915 Address internal_frame_sp = NULL;
10916 while (!it2.done()) {
10917 if (it2.frame()->is_internal()) {
10918 internal_frame_sp = it2.frame()->sp();
10919 } else {
10920 if (it2.frame()->is_java_script()) {
10921 if (it2.frame()->id() == it.frame()->id()) {
10922 // The internal frame just before the JavaScript frame contains the
10923 // value to return on top. A debug break at return will create an
10924 // internal frame to store the return value (eax/rax/r0) before
10925 // entering the debug break exit frame.
10926 if (internal_frame_sp != NULL) {
10927 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010928 Handle<Object>(Memory::Object_at(internal_frame_sp),
10929 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010930 break;
10931 }
10932 }
10933 }
10934
10935 // Indicate that the previous frame was not an internal frame.
10936 internal_frame_sp = NULL;
10937 }
10938 it2.Advance();
10939 }
10940 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010941
10942 // Now advance to the arguments adapter frame (if any). It contains all
10943 // the provided parameters whereas the function frame always have the number
10944 // of arguments matching the functions parameters. The rest of the
10945 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010946 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010947 it.AdvanceToArgumentsFrame();
10948 frame_inspector.SetArgumentsFrame(it.frame());
10949 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010950
10951 // Find the number of arguments to fill. At least fill the number of
10952 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010953 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010954 if (argument_count < frame_inspector.GetParametersCount()) {
10955 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956 }
10957
10958 // Calculate the size of the result.
10959 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010960 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010961 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010962 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010963
10964 // Add the frame id.
10965 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10966
10967 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010968 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010969
10970 // Add the arguments count.
10971 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10972
10973 // Add the locals count
10974 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010975 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010976
10977 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010978 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010979 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10980 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010981 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010982 }
10983
10984 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010985 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010986
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010987 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010988 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010989
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010990 // Add flags to indicate information on whether this frame is
10991 // bit 0: invoked in the debugger context.
10992 // bit 1: optimized frame.
10993 // bit 2: inlined in optimized frame
10994 int flags = 0;
10995 if (*save->context() == *isolate->debug()->debug_context()) {
10996 flags |= 1 << 0;
10997 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010998 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010999 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011000 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011001 }
11002 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011003
11004 // Fill the dynamic part.
11005 int details_index = kFrameDetailsFirstDynamicIndex;
11006
11007 // Add arguments name and value.
11008 for (int i = 0; i < argument_count; i++) {
11009 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011010 if (i < scope_info->ParameterCount()) {
11011 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011012 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011013 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011014 }
11015
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011016 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011017 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011018 // Get the value from the stack.
11019 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011020 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011021 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011022 }
11023 }
11024
11025 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011026 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011027 details->set(details_index++, locals->get(i));
11028 }
11029
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011030 // Add the value being returned.
11031 if (at_return) {
11032 details->set(details_index++, *return_value);
11033 }
11034
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011035 // Add the receiver (same as in function frame).
11036 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11037 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011038 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011039 if (!receiver->IsJSObject() &&
11040 shared->is_classic_mode() &&
11041 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011042 // If the receiver is not a JSObject and the function is not a
11043 // builtin or strict-mode we have hit an optimization where a
11044 // value object is not converted into a wrapped JS objects. To
11045 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011046 // by creating correct wrapper object based on the calling frame's
11047 // global context.
11048 it.Advance();
11049 Handle<Context> calling_frames_global_context(
11050 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011051 receiver =
11052 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011053 }
11054 details->set(kFrameDetailsReceiverIndex, *receiver);
11055
11056 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011057 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011058}
11059
11060
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011061// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011062static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011063 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011064 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011065 Handle<Context> context,
11066 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011067 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011068 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11069 VariableMode mode;
11070 InitializationFlag init_flag;
11071 int context_index = scope_info->ContextSlotIndex(
11072 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011073
whesse@chromium.org7b260152011-06-20 15:33:18 +000011074 RETURN_IF_EMPTY_HANDLE_VALUE(
11075 isolate,
11076 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011077 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011078 Handle<Object>(context->get(context_index), isolate),
11079 NONE,
11080 kNonStrictMode),
11081 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011082 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011083
11084 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011085}
11086
11087
11088// Create a plain JSObject which materializes the local scope for the specified
11089// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011090static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011091 Isolate* isolate,
11092 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011093 FrameInspector* frame_inspector) {
11094 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011095 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011096 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011097
11098 // Allocate and initialize a JSObject with all the arguments, stack locals
11099 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011100 Handle<JSObject> local_scope =
11101 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011102
11103 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011104 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011105 Handle<Object> value(
11106 i < frame_inspector->GetParametersCount() ?
11107 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11108
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011109 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011110 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011111 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011112 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011113 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011114 NONE,
11115 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011116 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011117 }
11118
11119 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011120 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011121 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011122 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011123 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011124 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011125 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011126 NONE,
11127 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011128 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011129 }
11130
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011131 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011132 // Third fill all context locals.
11133 Handle<Context> frame_context(Context::cast(frame->context()));
11134 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011135 if (!CopyContextLocalsToScopeObject(
11136 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011137 return Handle<JSObject>();
11138 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011139
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011140 // Finally copy any properties from the function context extension.
11141 // These will be variables introduced by eval.
11142 if (function_context->closure() == *function) {
11143 if (function_context->has_extension() &&
11144 !function_context->IsGlobalContext()) {
11145 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011146 bool threw = false;
11147 Handle<FixedArray> keys =
11148 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11149 if (threw) return Handle<JSObject>();
11150
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011151 for (int i = 0; i < keys->length(); i++) {
11152 // Names of variables introduced by eval are strings.
11153 ASSERT(keys->get(i)->IsString());
11154 Handle<String> key(String::cast(keys->get(i)));
11155 RETURN_IF_EMPTY_HANDLE_VALUE(
11156 isolate,
11157 SetProperty(local_scope,
11158 key,
11159 GetProperty(ext, key),
11160 NONE,
11161 kNonStrictMode),
11162 Handle<JSObject>());
11163 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011164 }
11165 }
11166 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011167
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011168 return local_scope;
11169}
11170
11171
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011172static Handle<JSObject> MaterializeLocalScope(
11173 Isolate* isolate,
11174 JavaScriptFrame* frame,
11175 int inlined_jsframe_index) {
11176 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11177 return MaterializeLocalScopeWithFrameInspector(isolate,
11178 frame,
11179 &frame_inspector);
11180}
11181
11182
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011183// Create a plain JSObject which materializes the closure content for the
11184// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011185static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11186 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011187 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011188
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011189 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011190 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011191
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011192 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011193 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011194 Handle<JSObject> closure_scope =
11195 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011196
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011197 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011198 if (!CopyContextLocalsToScopeObject(
11199 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011200 return Handle<JSObject>();
11201 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011202
11203 // Finally copy any properties from the function context extension. This will
11204 // be variables introduced by eval.
11205 if (context->has_extension()) {
11206 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011207 bool threw = false;
11208 Handle<FixedArray> keys =
11209 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11210 if (threw) return Handle<JSObject>();
11211
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011212 for (int i = 0; i < keys->length(); i++) {
11213 // Names of variables introduced by eval are strings.
11214 ASSERT(keys->get(i)->IsString());
11215 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011216 RETURN_IF_EMPTY_HANDLE_VALUE(
11217 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011218 SetProperty(closure_scope,
11219 key,
11220 GetProperty(ext, key),
11221 NONE,
11222 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011223 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011224 }
11225 }
11226
11227 return closure_scope;
11228}
11229
11230
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011231// Create a plain JSObject which materializes the scope for the specified
11232// catch context.
11233static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11234 Handle<Context> context) {
11235 ASSERT(context->IsCatchContext());
11236 Handle<String> name(String::cast(context->extension()));
11237 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11238 Handle<JSObject> catch_scope =
11239 isolate->factory()->NewJSObject(isolate->object_function());
11240 RETURN_IF_EMPTY_HANDLE_VALUE(
11241 isolate,
11242 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11243 Handle<JSObject>());
11244 return catch_scope;
11245}
11246
11247
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011248// Create a plain JSObject which materializes the block scope for the specified
11249// block context.
11250static Handle<JSObject> MaterializeBlockScope(
11251 Isolate* isolate,
11252 Handle<Context> context) {
11253 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011254 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011255
11256 // Allocate and initialize a JSObject with all the arguments, stack locals
11257 // heap locals and extension properties of the debugged function.
11258 Handle<JSObject> block_scope =
11259 isolate->factory()->NewJSObject(isolate->object_function());
11260
11261 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011262 if (!CopyContextLocalsToScopeObject(
11263 isolate, scope_info, context, block_scope)) {
11264 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011265 }
11266
11267 return block_scope;
11268}
11269
11270
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011271// Iterate over the actual scopes visible from a stack frame. The iteration
11272// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011273// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011274// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011275class ScopeIterator {
11276 public:
11277 enum ScopeType {
11278 ScopeTypeGlobal = 0,
11279 ScopeTypeLocal,
11280 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011281 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011282 ScopeTypeCatch,
11283 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011284 };
11285
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011286 ScopeIterator(Isolate* isolate,
11287 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011288 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011289 : isolate_(isolate),
11290 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011291 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011292 function_(JSFunction::cast(frame->function())),
11293 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011294 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011295
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011296 // Catch the case when the debugger stops in an internal function.
11297 Handle<SharedFunctionInfo> shared_info(function_->shared());
11298 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11299 if (shared_info->script() == isolate->heap()->undefined_value()) {
11300 while (context_->closure() == *function_) {
11301 context_ = Handle<Context>(context_->previous(), isolate_);
11302 }
11303 return;
11304 }
11305
11306 // Get the debug info (create it if it does not exist).
11307 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11308 // Return if ensuring debug info failed.
11309 return;
11310 }
11311 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11312
11313 // Find the break point where execution has stopped.
11314 BreakLocationIterator break_location_iterator(debug_info,
11315 ALL_BREAK_LOCATIONS);
11316 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11317 if (break_location_iterator.IsExit()) {
11318 // We are within the return sequence. At the momemt it is not possible to
11319 // get a source position which is consistent with the current scope chain.
11320 // Thus all nested with, catch and block contexts are skipped and we only
11321 // provide the function scope.
11322 if (scope_info->HasContext()) {
11323 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11324 } else {
11325 while (context_->closure() == *function_) {
11326 context_ = Handle<Context>(context_->previous(), isolate_);
11327 }
11328 }
11329 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11330 } else {
11331 // Reparse the code and analyze the scopes.
11332 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11333 Handle<Script> script(Script::cast(shared_info->script()));
11334 Scope* scope = NULL;
11335
11336 // Check whether we are in global, eval or function code.
11337 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11338 if (scope_info->Type() != FUNCTION_SCOPE) {
11339 // Global or eval code.
11340 CompilationInfo info(script);
11341 if (scope_info->Type() == GLOBAL_SCOPE) {
11342 info.MarkAsGlobal();
11343 } else {
11344 ASSERT(scope_info->Type() == EVAL_SCOPE);
11345 info.MarkAsEval();
11346 info.SetCallingContext(Handle<Context>(function_->context()));
11347 }
11348 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11349 scope = info.function()->scope();
11350 }
11351 } else {
11352 // Function code
11353 CompilationInfo info(shared_info);
11354 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11355 scope = info.function()->scope();
11356 }
11357 }
11358
11359 // Retrieve the scope chain for the current position.
11360 if (scope != NULL) {
11361 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11362 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11363 } else {
11364 // A failed reparse indicates that the preparser has diverged from the
11365 // parser or that the preparse data given to the initial parse has been
11366 // faulty. We fail in debug mode but in release mode we only provide the
11367 // information we get from the context chain but nothing about
11368 // completely stack allocated scopes or stack allocated locals.
11369 UNREACHABLE();
11370 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011371 }
11372 }
11373
11374 // More scopes?
11375 bool Done() { return context_.is_null(); }
11376
11377 // Move to the next scope.
11378 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011379 ScopeType scope_type = Type();
11380 if (scope_type == ScopeTypeGlobal) {
11381 // The global scope is always the last in the chain.
11382 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011383 context_ = Handle<Context>();
11384 return;
11385 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011386 if (nested_scope_chain_.is_empty()) {
11387 context_ = Handle<Context>(context_->previous(), isolate_);
11388 } else {
11389 if (nested_scope_chain_.last()->HasContext()) {
11390 ASSERT(context_->previous() != NULL);
11391 context_ = Handle<Context>(context_->previous(), isolate_);
11392 }
11393 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011394 }
11395 }
11396
11397 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011398 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011399 if (!nested_scope_chain_.is_empty()) {
11400 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11401 switch (scope_info->Type()) {
11402 case FUNCTION_SCOPE:
11403 ASSERT(context_->IsFunctionContext() ||
11404 !scope_info->HasContext());
11405 return ScopeTypeLocal;
11406 case GLOBAL_SCOPE:
11407 ASSERT(context_->IsGlobalContext());
11408 return ScopeTypeGlobal;
11409 case WITH_SCOPE:
11410 ASSERT(context_->IsWithContext());
11411 return ScopeTypeWith;
11412 case CATCH_SCOPE:
11413 ASSERT(context_->IsCatchContext());
11414 return ScopeTypeCatch;
11415 case BLOCK_SCOPE:
11416 ASSERT(!scope_info->HasContext() ||
11417 context_->IsBlockContext());
11418 return ScopeTypeBlock;
11419 case EVAL_SCOPE:
11420 UNREACHABLE();
11421 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011422 }
11423 if (context_->IsGlobalContext()) {
11424 ASSERT(context_->global()->IsGlobalObject());
11425 return ScopeTypeGlobal;
11426 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011427 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011428 return ScopeTypeClosure;
11429 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011430 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011431 return ScopeTypeCatch;
11432 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011433 if (context_->IsBlockContext()) {
11434 return ScopeTypeBlock;
11435 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011436 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011437 return ScopeTypeWith;
11438 }
11439
11440 // Return the JavaScript object with the content of the current scope.
11441 Handle<JSObject> ScopeObject() {
11442 switch (Type()) {
11443 case ScopeIterator::ScopeTypeGlobal:
11444 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011445 case ScopeIterator::ScopeTypeLocal:
11446 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011447 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011448 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011449 case ScopeIterator::ScopeTypeWith:
11450 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011451 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11452 case ScopeIterator::ScopeTypeCatch:
11453 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011454 case ScopeIterator::ScopeTypeClosure:
11455 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011456 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011457 case ScopeIterator::ScopeTypeBlock:
11458 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011459 }
11460 UNREACHABLE();
11461 return Handle<JSObject>();
11462 }
11463
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011464 Handle<ScopeInfo> CurrentScopeInfo() {
11465 if (!nested_scope_chain_.is_empty()) {
11466 return nested_scope_chain_.last();
11467 } else if (context_->IsBlockContext()) {
11468 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11469 } else if (context_->IsFunctionContext()) {
11470 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11471 }
11472 return Handle<ScopeInfo>::null();
11473 }
11474
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011475 // Return the context for this scope. For the local context there might not
11476 // be an actual context.
11477 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011478 if (Type() == ScopeTypeGlobal ||
11479 nested_scope_chain_.is_empty()) {
11480 return context_;
11481 } else if (nested_scope_chain_.last()->HasContext()) {
11482 return context_;
11483 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011484 return Handle<Context>();
11485 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011486 }
11487
11488#ifdef DEBUG
11489 // Debug print of the content of the current scope.
11490 void DebugPrint() {
11491 switch (Type()) {
11492 case ScopeIterator::ScopeTypeGlobal:
11493 PrintF("Global:\n");
11494 CurrentContext()->Print();
11495 break;
11496
11497 case ScopeIterator::ScopeTypeLocal: {
11498 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011499 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011500 if (!CurrentContext().is_null()) {
11501 CurrentContext()->Print();
11502 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011503 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011504 if (extension->IsJSContextExtensionObject()) {
11505 extension->Print();
11506 }
11507 }
11508 }
11509 break;
11510 }
11511
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011512 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011513 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011514 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011515 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011516
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011517 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011518 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011519 CurrentContext()->extension()->Print();
11520 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011521 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011522
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011523 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011524 PrintF("Closure:\n");
11525 CurrentContext()->Print();
11526 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011527 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011528 if (extension->IsJSContextExtensionObject()) {
11529 extension->Print();
11530 }
11531 }
11532 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011533
11534 default:
11535 UNREACHABLE();
11536 }
11537 PrintF("\n");
11538 }
11539#endif
11540
11541 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011542 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011543 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011544 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011545 Handle<JSFunction> function_;
11546 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011547 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011548
11549 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11550};
11551
11552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011553RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011554 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011555 ASSERT(args.length() == 2);
11556
11557 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011558 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011559 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11560 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011561 if (!maybe_check->ToObject(&check)) return maybe_check;
11562 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011563 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11564
11565 // Get the frame where the debugging is performed.
11566 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011567 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011568 JavaScriptFrame* frame = it.frame();
11569
11570 // Count the visible scopes.
11571 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011572 for (ScopeIterator it(isolate, frame, 0);
11573 !it.Done();
11574 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011575 n++;
11576 }
11577
11578 return Smi::FromInt(n);
11579}
11580
11581
11582static const int kScopeDetailsTypeIndex = 0;
11583static const int kScopeDetailsObjectIndex = 1;
11584static const int kScopeDetailsSize = 2;
11585
11586// Return an array with scope details
11587// args[0]: number: break id
11588// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011589// args[2]: number: inlined frame index
11590// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011591//
11592// The array returned contains the following information:
11593// 0: Scope type
11594// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011595RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011596 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011597 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011598
11599 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011600 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011601 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11602 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011603 if (!maybe_check->ToObject(&check)) return maybe_check;
11604 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011605 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011606 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011607 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011608
11609 // Get the frame where the debugging is performed.
11610 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011611 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011612 JavaScriptFrame* frame = frame_it.frame();
11613
11614 // Find the requested scope.
11615 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011616 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011617 for (; !it.Done() && n < index; it.Next()) {
11618 n++;
11619 }
11620 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011621 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011622 }
11623
11624 // Calculate the size of the result.
11625 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011626 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011627
11628 // Fill in scope details.
11629 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011630 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011631 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011632 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011633
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011634 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011635}
11636
11637
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011638RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011639 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011640 ASSERT(args.length() == 0);
11641
11642#ifdef DEBUG
11643 // Print the scopes for the top frame.
11644 StackFrameLocator locator;
11645 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011646 for (ScopeIterator it(isolate, frame, 0);
11647 !it.Done();
11648 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011649 it.DebugPrint();
11650 }
11651#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011652 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011653}
11654
11655
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011656RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011657 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011658 ASSERT(args.length() == 1);
11659
11660 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011661 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011662 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11663 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011664 if (!maybe_result->ToObject(&result)) return maybe_result;
11665 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011666
11667 // Count all archived V8 threads.
11668 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011669 for (ThreadState* thread =
11670 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011671 thread != NULL;
11672 thread = thread->Next()) {
11673 n++;
11674 }
11675
11676 // Total number of threads is current thread and archived threads.
11677 return Smi::FromInt(n + 1);
11678}
11679
11680
11681static const int kThreadDetailsCurrentThreadIndex = 0;
11682static const int kThreadDetailsThreadIdIndex = 1;
11683static const int kThreadDetailsSize = 2;
11684
11685// Return an array with thread details
11686// args[0]: number: break id
11687// args[1]: number: thread index
11688//
11689// The array returned contains the following information:
11690// 0: Is current thread?
11691// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011692RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011693 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011694 ASSERT(args.length() == 2);
11695
11696 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011697 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011698 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11699 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011700 if (!maybe_check->ToObject(&check)) return maybe_check;
11701 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011702 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11703
11704 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011705 Handle<FixedArray> details =
11706 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011707
11708 // Thread index 0 is current thread.
11709 if (index == 0) {
11710 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011711 details->set(kThreadDetailsCurrentThreadIndex,
11712 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011713 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011714 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011715 } else {
11716 // Find the thread with the requested index.
11717 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011718 ThreadState* thread =
11719 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011720 while (index != n && thread != NULL) {
11721 thread = thread->Next();
11722 n++;
11723 }
11724 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011725 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011726 }
11727
11728 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011729 details->set(kThreadDetailsCurrentThreadIndex,
11730 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011731 details->set(kThreadDetailsThreadIdIndex,
11732 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011733 }
11734
11735 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011736 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011737}
11738
11739
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011740// Sets the disable break state
11741// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011742RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011743 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011744 ASSERT(args.length() == 1);
11745 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011746 isolate->debug()->set_disable_break(disable_break);
11747 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011748}
11749
11750
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011751RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011752 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011753 ASSERT(args.length() == 1);
11754
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011755 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11756 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011757 // Find the number of break points
11758 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011759 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011760 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011762 Handle<FixedArray>::cast(break_locations));
11763}
11764
11765
11766// Set a break point in a function
11767// args[0]: function
11768// args[1]: number: break source position (within the function source)
11769// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011770RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011771 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011773 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11774 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11776 RUNTIME_ASSERT(source_position >= 0);
11777 Handle<Object> break_point_object_arg = args.at<Object>(2);
11778
11779 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011780 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11781 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011782
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011783 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011784}
11785
11786
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011787Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11788 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011789 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790 // Iterate the heap looking for SharedFunctionInfo generated from the
11791 // script. The inner most SharedFunctionInfo containing the source position
11792 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011793 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011794 // which is found is not compiled it is compiled and the heap is iterated
11795 // again as the compilation might create inner functions from the newly
11796 // compiled function and the actual requested break point might be in one of
11797 // these functions.
11798 bool done = false;
11799 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011800 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011801 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011802 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011803 { // Extra scope for iterator and no-allocation.
11804 isolate->heap()->EnsureHeapIsIterable();
11805 AssertNoAllocation no_alloc_during_heap_iteration;
11806 HeapIterator iterator;
11807 for (HeapObject* obj = iterator.next();
11808 obj != NULL; obj = iterator.next()) {
11809 if (obj->IsSharedFunctionInfo()) {
11810 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11811 if (shared->script() == *script) {
11812 // If the SharedFunctionInfo found has the requested script data and
11813 // contains the source position it is a candidate.
11814 int start_position = shared->function_token_position();
11815 if (start_position == RelocInfo::kNoPosition) {
11816 start_position = shared->start_position();
11817 }
11818 if (start_position <= position &&
11819 position <= shared->end_position()) {
11820 // If there is no candidate or this function is within the current
11821 // candidate this is the new candidate.
11822 if (target.is_null()) {
11823 target_start_position = start_position;
11824 target = shared;
11825 } else {
11826 if (target_start_position == start_position &&
11827 shared->end_position() == target->end_position()) {
11828 // If a top-level function contain only one function
11829 // declartion the source for the top-level and the
11830 // function is the same. In that case prefer the non
11831 // top-level function.
11832 if (!shared->is_toplevel()) {
11833 target_start_position = start_position;
11834 target = shared;
11835 }
11836 } else if (target_start_position <= start_position &&
11837 shared->end_position() <= target->end_position()) {
11838 // This containment check includes equality as a function
11839 // inside a top-level function can share either start or end
11840 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011841 target_start_position = start_position;
11842 target = shared;
11843 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011844 }
11845 }
11846 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011847 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011848 } // End for loop.
11849 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011850
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011851 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011852 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011853 }
11854
11855 // If the candidate found is compiled we are done. NOTE: when lazy
11856 // compilation of inner functions is introduced some additional checking
11857 // needs to be done here to compile inner functions.
11858 done = target->is_compiled();
11859 if (!done) {
11860 // If the candidate is not compiled compile it to reveal any inner
11861 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011862 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011863 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011864 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865
11866 return *target;
11867}
11868
11869
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011870// Changes the state of a break point in a script and returns source position
11871// where break point was set. NOTE: Regarding performance see the NOTE for
11872// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011873// args[0]: script to set break point in
11874// args[1]: number: break source position (within the script source)
11875// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011876RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011877 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878 ASSERT(args.length() == 3);
11879 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11880 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11881 RUNTIME_ASSERT(source_position >= 0);
11882 Handle<Object> break_point_object_arg = args.at<Object>(2);
11883
11884 // Get the script from the script wrapper.
11885 RUNTIME_ASSERT(wrapper->value()->IsScript());
11886 Handle<Script> script(Script::cast(wrapper->value()));
11887
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011888 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011889 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011890 if (!result->IsUndefined()) {
11891 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11892 // Find position within function. The script position might be before the
11893 // source position of the first function.
11894 int position;
11895 if (shared->start_position() > source_position) {
11896 position = 0;
11897 } else {
11898 position = source_position - shared->start_position();
11899 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011900 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011901 position += shared->start_position();
11902 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011903 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905}
11906
11907
11908// Clear a break point
11909// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011910RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011911 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011912 ASSERT(args.length() == 1);
11913 Handle<Object> break_point_object_arg = args.at<Object>(0);
11914
11915 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011916 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011917
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011918 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011919}
11920
11921
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011922// Change the state of break on exceptions.
11923// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11924// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011925RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011926 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011927 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011928 RUNTIME_ASSERT(args[0]->IsNumber());
11929 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011930
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011931 // If the number doesn't match an enum value, the ChangeBreakOnException
11932 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011933 ExceptionBreakType type =
11934 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011935 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011936 isolate->debug()->ChangeBreakOnException(type, enable);
11937 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011938}
11939
11940
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011941// Returns the state of break on exceptions
11942// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011943RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011944 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011945 ASSERT(args.length() == 1);
11946 RUNTIME_ASSERT(args[0]->IsNumber());
11947
11948 ExceptionBreakType type =
11949 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011950 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011951 return Smi::FromInt(result);
11952}
11953
11954
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011955// Prepare for stepping
11956// args[0]: break id for checking execution state
11957// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011958// args[2]: number of times to perform the step, for step out it is the number
11959// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011960RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011961 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011962 ASSERT(args.length() == 3);
11963 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011964 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011965 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11966 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011967 if (!maybe_check->ToObject(&check)) return maybe_check;
11968 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011970 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011971 }
11972
11973 // Get the step action and check validity.
11974 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11975 if (step_action != StepIn &&
11976 step_action != StepNext &&
11977 step_action != StepOut &&
11978 step_action != StepInMin &&
11979 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011980 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011981 }
11982
11983 // Get the number of steps.
11984 int step_count = NumberToInt32(args[2]);
11985 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011986 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011987 }
11988
ager@chromium.orga1645e22009-09-09 19:27:10 +000011989 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011990 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011991
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011992 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011993 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11994 step_count);
11995 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996}
11997
11998
11999// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012000RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012001 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012002 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012003 isolate->debug()->ClearStepping();
12004 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012005}
12006
12007
12008// Creates a copy of the with context chain. The copy of the context chain is
12009// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012010static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
12011 Handle<JSFunction> function,
12012 Handle<Context> base,
12013 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012014 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012015 HandleScope scope(isolate);
12016 List<Handle<ScopeInfo> > scope_chain;
12017 List<Handle<Context> > context_chain;
12018
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012019 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012020 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12021 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12022 ASSERT(!it.Done());
12023 scope_chain.Add(it.CurrentScopeInfo());
12024 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012025 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012026
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012027 // At the end of the chain. Return the base context to link to.
12028 Handle<Context> context = base;
12029
12030 // Iteratively copy and or materialize the nested contexts.
12031 while (!scope_chain.is_empty()) {
12032 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12033 Handle<Context> current = context_chain.RemoveLast();
12034 ASSERT(!(scope_info->HasContext() & current.is_null()));
12035
12036 if (scope_info->Type() == CATCH_SCOPE) {
12037 Handle<String> name(String::cast(current->extension()));
12038 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12039 context =
12040 isolate->factory()->NewCatchContext(function,
12041 context,
12042 name,
12043 thrown_object);
12044 } else if (scope_info->Type() == BLOCK_SCOPE) {
12045 // Materialize the contents of the block scope into a JSObject.
12046 Handle<JSObject> block_scope_object =
12047 MaterializeBlockScope(isolate, current);
12048 if (block_scope_object.is_null()) {
12049 return Handle<Context>::null();
12050 }
12051 // Allocate a new function context for the debug evaluation and set the
12052 // extension object.
12053 Handle<Context> new_context =
12054 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12055 function);
12056 new_context->set_extension(*block_scope_object);
12057 new_context->set_previous(*context);
12058 context = new_context;
12059 } else {
12060 ASSERT(scope_info->Type() == WITH_SCOPE);
12061 ASSERT(current->IsWithContext());
12062 Handle<JSObject> extension(JSObject::cast(current->extension()));
12063 context =
12064 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012065 }
erikcorry0ad885c2011-11-21 13:51:57 +000012066 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012067
12068 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012069}
12070
12071
12072// Helper function to find or create the arguments object for
12073// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012074static Handle<Object> GetArgumentsObject(Isolate* isolate,
12075 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012076 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012077 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012078 Handle<Context> function_context) {
12079 // Try to find the value of 'arguments' to pass as parameter. If it is not
12080 // found (that is the debugged function does not reference 'arguments' and
12081 // does not support eval) then create an 'arguments' object.
12082 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012083 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012084 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012085 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012086 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012087 }
12088 }
12089
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012090 if (scope_info->HasHeapAllocatedLocals()) {
12091 VariableMode mode;
12092 InitializationFlag init_flag;
12093 index = scope_info->ContextSlotIndex(
12094 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012095 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012096 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012097 }
12098 }
12099
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012100 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12101 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012102 Handle<JSObject> arguments =
12103 isolate->factory()->NewArgumentsObject(function, length);
12104 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012105
12106 AssertNoAllocation no_gc;
12107 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012108 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012109 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012111 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012112 return arguments;
12113}
12114
12115
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012116static const char kSourceStr[] =
12117 "(function(arguments,__source__){return eval(__source__);})";
12118
12119
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012120// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012121// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012122// extension part has all the parameters and locals of the function on the
12123// stack frame. A function which calls eval with the code to evaluate is then
12124// compiled in this context and called in this context. As this context
12125// replaces the context of the function on the stack frame a new (empty)
12126// function is created as well to be used as the closure for the context.
12127// This function and the context acts as replacements for the function on the
12128// stack frame presenting the same view of the values of parameters and
12129// local variables as if the piece of JavaScript was evaluated at the point
12130// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012131RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012132 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012133
12134 // Check the execution state and decode arguments frame and source to be
12135 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012136 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012137 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012138 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12139 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012140 if (!maybe_check_result->ToObject(&check_result)) {
12141 return maybe_check_result;
12142 }
12143 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012145 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012146 CONVERT_ARG_CHECKED(String, source, 3);
12147 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12148 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012149
12150 // Handle the processing of break.
12151 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012152
12153 // Get the frame where the debugging is performed.
12154 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012155 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012156 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012157 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12158 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012159 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012160
12161 // Traverse the saved contexts chain to find the active context for the
12162 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012163 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12164
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012165 SaveContext savex(isolate);
12166 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012167
12168 // Create the (empty) function replacing the function on the stack frame for
12169 // the purpose of evaluating in the context created below. It is important
12170 // that this function does not describe any parameters and local variables
12171 // in the context. If it does then this will cause problems with the lookup
12172 // in Context::Lookup, where context slots for parameters and local variables
12173 // are looked at before the extension object.
12174 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012175 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12176 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012177 go_between->set_context(function->context());
12178#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012179 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12180 ASSERT(go_between_scope_info->ParameterCount() == 0);
12181 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012182#endif
12183
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012184 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012185 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12186 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012187 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012188
12189 // Allocate a new context for the debug evaluation and set the extension
12190 // object build.
12191 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012192 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12193 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012194 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012195 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012196 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012197 Handle<Context> function_context;
12198 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012199 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012200 function_context = Handle<Context>(frame_context->declaration_context());
12201 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012202 context = CopyNestedScopeContextChain(isolate,
12203 go_between,
12204 context,
12205 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012206 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012207
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012208 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012209 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012210 context =
12211 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012212 }
12213
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012214 // Wrap the evaluation statement in a new function compiled in the newly
12215 // created context. The function has one parameter which has to be called
12216 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012217 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012218 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012219
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012220 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012221 isolate->factory()->NewStringFromAscii(
12222 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012223
12224 // Currently, the eval code will be executed in non-strict mode,
12225 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012226 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012227 Compiler::CompileEval(function_source,
12228 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012229 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012230 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012231 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012232 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012234 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235
12236 // Invoke the result of the compilation to get the evaluation function.
12237 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012238 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012239 Handle<Object> evaluation_function =
12240 Execution::Call(compiled_function, receiver, 0, NULL,
12241 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012242 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012243
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012244 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012245 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012246 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012247 scope_info,
12248 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012249
12250 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012251 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012252 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012253 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12254 receiver,
12255 ARRAY_SIZE(argv),
12256 argv,
12257 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012258 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012259
12260 // Skip the global proxy as it has no properties and always delegates to the
12261 // real global object.
12262 if (result->IsJSGlobalProxy()) {
12263 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12264 }
12265
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012266 return *result;
12267}
12268
12269
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012270RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012271 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012272
12273 // Check the execution state and decode arguments frame and source to be
12274 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012275 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012276 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012277 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12278 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012279 if (!maybe_check_result->ToObject(&check_result)) {
12280 return maybe_check_result;
12281 }
12282 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012283 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012284 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012285 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012286
12287 // Handle the processing of break.
12288 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012289
12290 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012291 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012292 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012293 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012294 top = top->prev();
12295 }
12296 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012297 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012298 }
12299
12300 // Get the global context now set to the top context from before the
12301 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012302 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012303
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012304 bool is_global = true;
12305
12306 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012307 // Create a new with context with the additional context information between
12308 // the context of the debugged function and the eval code to be executed.
12309 context = isolate->factory()->NewWithContext(
12310 Handle<JSFunction>(context->closure()),
12311 context,
12312 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012313 is_global = false;
12314 }
12315
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012316 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012317 // Currently, the eval code will be executed in non-strict mode,
12318 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012319 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012320 Compiler::CompileEval(source,
12321 context,
12322 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012323 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012324 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012325 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012326 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012327 Handle<JSFunction>(
12328 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12329 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012330
12331 // Invoke the result of the compilation to get the evaluation function.
12332 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012333 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012334 Handle<Object> result =
12335 Execution::Call(compiled_function, receiver, 0, NULL,
12336 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012337 // Clear the oneshot breakpoints so that the debugger does not step further.
12338 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012339 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012340 return *result;
12341}
12342
12343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012344RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012345 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012346 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012347
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012348 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012349 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012350
12351 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012352 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012353 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12354 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12355 // because using
12356 // instances->set(i, *GetScriptWrapper(script))
12357 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012358 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012359 Handle<JSValue> wrapper = GetScriptWrapper(script);
12360 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012361 }
12362
12363 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012364 Handle<JSObject> result =
12365 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012366 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367 return *result;
12368}
12369
12370
12371// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012372static int DebugReferencedBy(HeapIterator* iterator,
12373 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012374 Object* instance_filter, int max_references,
12375 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012376 JSFunction* arguments_function) {
12377 NoHandleAllocation ha;
12378 AssertNoAllocation no_alloc;
12379
12380 // Iterate the heap.
12381 int count = 0;
12382 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012383 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012384 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012385 (max_references == 0 || count < max_references)) {
12386 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012387 if (heap_obj->IsJSObject()) {
12388 // Skip context extension objects and argument arrays as these are
12389 // checked in the context of functions using them.
12390 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012391 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012392 obj->map()->constructor() == arguments_function) {
12393 continue;
12394 }
12395
12396 // Check if the JS object has a reference to the object looked for.
12397 if (obj->ReferencesObject(target)) {
12398 // Check instance filter if supplied. This is normally used to avoid
12399 // references from mirror objects (see Runtime_IsInPrototypeChain).
12400 if (!instance_filter->IsUndefined()) {
12401 Object* V = obj;
12402 while (true) {
12403 Object* prototype = V->GetPrototype();
12404 if (prototype->IsNull()) {
12405 break;
12406 }
12407 if (instance_filter == prototype) {
12408 obj = NULL; // Don't add this object.
12409 break;
12410 }
12411 V = prototype;
12412 }
12413 }
12414
12415 if (obj != NULL) {
12416 // Valid reference found add to instance array if supplied an update
12417 // count.
12418 if (instances != NULL && count < instances_size) {
12419 instances->set(count, obj);
12420 }
12421 last = obj;
12422 count++;
12423 }
12424 }
12425 }
12426 }
12427
12428 // Check for circular reference only. This can happen when the object is only
12429 // referenced from mirrors and has a circular reference in which case the
12430 // object is not really alive and would have been garbage collected if not
12431 // referenced from the mirror.
12432 if (count == 1 && last == target) {
12433 count = 0;
12434 }
12435
12436 // Return the number of referencing objects found.
12437 return count;
12438}
12439
12440
12441// Scan the heap for objects with direct references to an object
12442// args[0]: the object to find references to
12443// args[1]: constructor function for instances to exclude (Mirror)
12444// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012445RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012446 ASSERT(args.length() == 3);
12447
12448 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012449 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12450 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012451 // The heap iterator reserves the right to do a GC to make the heap iterable.
12452 // Due to the GC above we know it won't need to do that, but it seems cleaner
12453 // to get the heap iterator constructed before we start having unprotected
12454 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012455
12456 // Check parameters.
12457 CONVERT_CHECKED(JSObject, target, args[0]);
12458 Object* instance_filter = args[1];
12459 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12460 instance_filter->IsJSObject());
12461 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12462 RUNTIME_ASSERT(max_references >= 0);
12463
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012464
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012465 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012466 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012467 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012468 JSFunction* arguments_function =
12469 JSFunction::cast(arguments_boilerplate->map()->constructor());
12470
12471 // Get the number of referencing objects.
12472 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012473 HeapIterator heap_iterator;
12474 count = DebugReferencedBy(&heap_iterator,
12475 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012476 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012477
12478 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012479 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012480 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012481 if (!maybe_object->ToObject(&object)) return maybe_object;
12482 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012483 FixedArray* instances = FixedArray::cast(object);
12484
12485 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012486 // AllocateFixedArray above does not make the heap non-iterable.
12487 ASSERT(HEAP->IsHeapIterable());
12488 HeapIterator heap_iterator2;
12489 count = DebugReferencedBy(&heap_iterator2,
12490 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012491 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012492
12493 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012494 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012495 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012496 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012497 if (!maybe_result->ToObject(&result)) return maybe_result;
12498 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012499}
12500
12501
12502// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012503static int DebugConstructedBy(HeapIterator* iterator,
12504 JSFunction* constructor,
12505 int max_references,
12506 FixedArray* instances,
12507 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012508 AssertNoAllocation no_alloc;
12509
12510 // Iterate the heap.
12511 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012512 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012513 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012514 (max_references == 0 || count < max_references)) {
12515 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012516 if (heap_obj->IsJSObject()) {
12517 JSObject* obj = JSObject::cast(heap_obj);
12518 if (obj->map()->constructor() == constructor) {
12519 // Valid reference found add to instance array if supplied an update
12520 // count.
12521 if (instances != NULL && count < instances_size) {
12522 instances->set(count, obj);
12523 }
12524 count++;
12525 }
12526 }
12527 }
12528
12529 // Return the number of referencing objects found.
12530 return count;
12531}
12532
12533
12534// Scan the heap for objects constructed by a specific function.
12535// args[0]: the constructor to find instances of
12536// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012537RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012538 ASSERT(args.length() == 2);
12539
12540 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012541 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12542 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012543
12544 // Check parameters.
12545 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12546 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12547 RUNTIME_ASSERT(max_references >= 0);
12548
12549 // Get the number of referencing objects.
12550 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012551 HeapIterator heap_iterator;
12552 count = DebugConstructedBy(&heap_iterator,
12553 constructor,
12554 max_references,
12555 NULL,
12556 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012557
12558 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012559 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012560 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012561 if (!maybe_object->ToObject(&object)) return maybe_object;
12562 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012563 FixedArray* instances = FixedArray::cast(object);
12564
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012565 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012566 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012567 HeapIterator heap_iterator2;
12568 count = DebugConstructedBy(&heap_iterator2,
12569 constructor,
12570 max_references,
12571 instances,
12572 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012573
12574 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012575 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012576 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12577 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012578 if (!maybe_result->ToObject(&result)) return maybe_result;
12579 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012580 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012581}
12582
12583
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012584// Find the effective prototype object as returned by __proto__.
12585// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012586RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012587 ASSERT(args.length() == 1);
12588
12589 CONVERT_CHECKED(JSObject, obj, args[0]);
12590
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012591 // Use the __proto__ accessor.
12592 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012593}
12594
12595
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012596RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012597 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012598 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012599 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012600}
12601
12602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012603RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012604#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012605 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012606 ASSERT(args.length() == 1);
12607 // Get the function and make sure it is compiled.
12608 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012609 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012610 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012611 return Failure::Exception();
12612 }
12613 func->code()->PrintLn();
12614#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012615 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012616}
ager@chromium.org9085a012009-05-11 19:22:57 +000012617
12618
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012619RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012620#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012621 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012622 ASSERT(args.length() == 1);
12623 // Get the function and make sure it is compiled.
12624 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012625 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012626 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012627 return Failure::Exception();
12628 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012629 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012630#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012631 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012632}
12633
12634
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012635RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012636 NoHandleAllocation ha;
12637 ASSERT(args.length() == 1);
12638
12639 CONVERT_CHECKED(JSFunction, f, args[0]);
12640 return f->shared()->inferred_name();
12641}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012642
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012643
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012644static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12645 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012646 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012647 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648 int counter = 0;
12649 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012650 for (HeapObject* obj = iterator->next();
12651 obj != NULL;
12652 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012653 ASSERT(obj != NULL);
12654 if (!obj->IsSharedFunctionInfo()) {
12655 continue;
12656 }
12657 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12658 if (shared->script() != script) {
12659 continue;
12660 }
12661 if (counter < buffer_size) {
12662 buffer->set(counter, shared);
12663 }
12664 counter++;
12665 }
12666 return counter;
12667}
12668
12669// For a script finds all SharedFunctionInfo's in the heap that points
12670// to this script. Returns JSArray of SharedFunctionInfo wrapped
12671// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012672RUNTIME_FUNCTION(MaybeObject*,
12673 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012674 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012675 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012676 CONVERT_CHECKED(JSValue, script_value, args[0]);
12677
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012678
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012679 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12680
12681 const int kBufferSize = 32;
12682
12683 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012684 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012685 int number;
12686 {
12687 isolate->heap()->EnsureHeapIsIterable();
12688 AssertNoAllocation no_allocations;
12689 HeapIterator heap_iterator;
12690 Script* scr = *script;
12691 FixedArray* arr = *array;
12692 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12693 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012694 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012695 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012696 isolate->heap()->EnsureHeapIsIterable();
12697 AssertNoAllocation no_allocations;
12698 HeapIterator heap_iterator;
12699 Script* scr = *script;
12700 FixedArray* arr = *array;
12701 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012702 }
12703
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012704 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012705 result->set_length(Smi::FromInt(number));
12706
12707 LiveEdit::WrapSharedFunctionInfos(result);
12708
12709 return *result;
12710}
12711
12712// For a script calculates compilation information about all its functions.
12713// The script source is explicitly specified by the second argument.
12714// The source of the actual script is not used, however it is important that
12715// all generated code keeps references to this particular instance of script.
12716// Returns a JSArray of compilation infos. The array is ordered so that
12717// each function with all its descendant is always stored in a continues range
12718// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012719RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012720 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012721 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012722 CONVERT_CHECKED(JSValue, script, args[0]);
12723 CONVERT_ARG_CHECKED(String, source, 1);
12724 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12725
12726 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12727
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012728 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012729 return Failure::Exception();
12730 }
12731
12732 return result;
12733}
12734
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012735// Changes the source of the script to a new_source.
12736// If old_script_name is provided (i.e. is a String), also creates a copy of
12737// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012738RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012739 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012740 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012741 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12742 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012743 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012744
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012745 CONVERT_CHECKED(Script, original_script_pointer,
12746 original_script_value->value());
12747 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012748
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012749 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12750 new_source,
12751 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012752
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012753 if (old_script->IsScript()) {
12754 Handle<Script> script_handle(Script::cast(old_script));
12755 return *(GetScriptWrapper(script_handle));
12756 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012757 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012758 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012759}
12760
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012761
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012762RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012763 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012764 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012765 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12766 return LiveEdit::FunctionSourceUpdated(shared_info);
12767}
12768
12769
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012770// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012771RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012772 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012773 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012774 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12775 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12776
ager@chromium.orgac091b72010-05-05 07:34:42 +000012777 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012778}
12779
12780// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012781RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012782 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012783 HandleScope scope(isolate);
12784 Handle<Object> function_object(args[0], isolate);
12785 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012786
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012787 if (function_object->IsJSValue()) {
12788 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12789 if (script_object->IsJSValue()) {
12790 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012791 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012792 }
12793
12794 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12795 } else {
12796 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12797 // and we check it in this function.
12798 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012799
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012800 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012801}
12802
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012803
12804// In a code of a parent function replaces original function as embedded object
12805// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012806RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012807 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012808 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012809
12810 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12811 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12812 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12813
12814 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12815 subst_wrapper);
12816
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012817 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012818}
12819
12820
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012821// Updates positions of a shared function info (first parameter) according
12822// to script source change. Text change is described in second parameter as
12823// array of groups of 3 numbers:
12824// (change_begin, change_end, change_end_new_position).
12825// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012826RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012827 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012828 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012829 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12830 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12831
ager@chromium.orgac091b72010-05-05 07:34:42 +000012832 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012833}
12834
12835
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012836// For array of SharedFunctionInfo's (each wrapped in JSValue)
12837// checks that none of them have activations on stacks (of any thread).
12838// Returns array of the same length with corresponding results of
12839// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012840RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012841 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012842 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012843 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012844 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012845
ager@chromium.org357bf652010-04-12 11:30:10 +000012846 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012847}
12848
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012849// Compares 2 strings line-by-line, then token-wise and returns diff in form
12850// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12851// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012852RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012853 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012854 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012855 CONVERT_ARG_CHECKED(String, s1, 0);
12856 CONVERT_ARG_CHECKED(String, s2, 1);
12857
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012858 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012859}
12860
12861
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012862// A testing entry. Returns statement position which is the closest to
12863// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012864RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012865 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012866 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012867 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12868 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12869
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012870 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012871
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012872 if (code->kind() != Code::FUNCTION &&
12873 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012874 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012875 }
12876
12877 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012878 int closest_pc = 0;
12879 int distance = kMaxInt;
12880 while (!it.done()) {
12881 int statement_position = static_cast<int>(it.rinfo()->data());
12882 // Check if this break point is closer that what was previously found.
12883 if (source_position <= statement_position &&
12884 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012885 closest_pc =
12886 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012887 distance = statement_position - source_position;
12888 // Check whether we can't get any closer.
12889 if (distance == 0) break;
12890 }
12891 it.next();
12892 }
12893
12894 return Smi::FromInt(closest_pc);
12895}
12896
12897
ager@chromium.org357bf652010-04-12 11:30:10 +000012898// Calls specified function with or without entering the debugger.
12899// This is used in unit tests to run code as if debugger is entered or simply
12900// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012901RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012902 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012903 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012904 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12905 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12906
12907 Handle<Object> result;
12908 bool pending_exception;
12909 {
12910 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012911 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012912 &pending_exception);
12913 } else {
12914 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012915 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012916 &pending_exception);
12917 }
12918 }
12919 if (!pending_exception) {
12920 return *result;
12921 } else {
12922 return Failure::Exception();
12923 }
12924}
12925
12926
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012927// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012928RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012929 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012930 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012931 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12932 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012933 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012934}
12935
12936
12937// Performs a GC.
12938// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012939RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012940 isolate->heap()->CollectAllGarbage(true, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012941 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012942}
12943
12944
12945// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012946RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012947 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012948 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012949 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012950 }
12951 return Smi::FromInt(usage);
12952}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012953
12954
12955// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012956RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012957#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012958 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012959#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012960 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012961#endif
12962}
12963
12964
12965// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012966RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012967#ifdef LIVE_OBJECT_LIST
12968 return LiveObjectList::Capture();
12969#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012970 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012971#endif
12972}
12973
12974
12975// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012976RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012977#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012978 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012979 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012980 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012981#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012982 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012983#endif
12984}
12985
12986
12987// Generates the response to a debugger request for a dump of the objects
12988// contained in the difference between the captured live object lists
12989// specified by id1 and id2.
12990// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12991// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012992RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012993#ifdef LIVE_OBJECT_LIST
12994 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012995 CONVERT_SMI_ARG_CHECKED(id1, 0);
12996 CONVERT_SMI_ARG_CHECKED(id2, 1);
12997 CONVERT_SMI_ARG_CHECKED(start, 2);
12998 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012999 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
13000 EnterDebugger enter_debugger;
13001 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
13002#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013003 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013004#endif
13005}
13006
13007
13008// Gets the specified object as requested by the debugger.
13009// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013010RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013011#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013012 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013013 Object* result = LiveObjectList::GetObj(obj_id);
13014 return result;
13015#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013016 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013017#endif
13018}
13019
13020
13021// Gets the obj id for the specified address if valid.
13022// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013023RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013024#ifdef LIVE_OBJECT_LIST
13025 HandleScope scope;
13026 CONVERT_ARG_CHECKED(String, address, 0);
13027 Object* result = LiveObjectList::GetObjId(address);
13028 return result;
13029#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013030 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013031#endif
13032}
13033
13034
13035// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013036RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013037#ifdef LIVE_OBJECT_LIST
13038 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013039 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013040 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13041 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13042 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13043 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
13044 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
13045
13046 Handle<JSObject> instance_filter;
13047 if (args[1]->IsJSObject()) {
13048 instance_filter = args.at<JSObject>(1);
13049 }
13050 bool verbose = false;
13051 if (args[2]->IsBoolean()) {
13052 verbose = args[2]->IsTrue();
13053 }
13054 int start = 0;
13055 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013056 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013057 }
13058 int limit = Smi::kMaxValue;
13059 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013060 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013061 }
13062
13063 return LiveObjectList::GetObjRetainers(obj_id,
13064 instance_filter,
13065 verbose,
13066 start,
13067 limit,
13068 filter_obj);
13069#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013070 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013071#endif
13072}
13073
13074
13075// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013076RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013077#ifdef LIVE_OBJECT_LIST
13078 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013079 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13080 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013081 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13082
13083 Handle<JSObject> instance_filter;
13084 if (args[2]->IsJSObject()) {
13085 instance_filter = args.at<JSObject>(2);
13086 }
13087
13088 Object* result =
13089 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13090 return result;
13091#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013092 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013093#endif
13094}
13095
13096
13097// Generates the response to a debugger request for a list of all
13098// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013099RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013100#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013101 CONVERT_SMI_ARG_CHECKED(start, 0);
13102 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013103 return LiveObjectList::Info(start, count);
13104#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013105 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013106#endif
13107}
13108
13109
13110// Gets a dump of the specified object as requested by the debugger.
13111// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013112RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013113#ifdef LIVE_OBJECT_LIST
13114 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013115 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013116 Object* result = LiveObjectList::PrintObj(obj_id);
13117 return result;
13118#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013119 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013120#endif
13121}
13122
13123
13124// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013125RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013126#ifdef LIVE_OBJECT_LIST
13127 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013128 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013129#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013130 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013131#endif
13132}
13133
13134
13135// Generates the response to a debugger request for a summary of the types
13136// of objects in the difference between the captured live object lists
13137// specified by id1 and id2.
13138// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13139// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013140RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013141#ifdef LIVE_OBJECT_LIST
13142 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013143 CONVERT_SMI_ARG_CHECKED(id1, 0);
13144 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013145 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13146
13147 EnterDebugger enter_debugger;
13148 return LiveObjectList::Summarize(id1, id2, filter_obj);
13149#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013150 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013151#endif
13152}
13153
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013154#endif // ENABLE_DEBUGGER_SUPPORT
13155
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013157RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013158 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013159 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013160 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013161}
13162
13163
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013164RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013165 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013166 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013167 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013168}
13169
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013170
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013171// Finds the script object from the script data. NOTE: This operation uses
13172// heap traversal to find the function generated for the source position
13173// for the requested break point. For lazily compiled functions several heap
13174// traversals might be required rendering this operation as a rather slow
13175// operation. However for setting break points which is normally done through
13176// some kind of user interaction the performance is not crucial.
13177static Handle<Object> Runtime_GetScriptFromScriptName(
13178 Handle<String> script_name) {
13179 // Scan the heap for Script objects to find the script with the requested
13180 // script data.
13181 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013182 script_name->GetHeap()->EnsureHeapIsIterable();
13183 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013184 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013185 HeapObject* obj = NULL;
13186 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013187 // If a script is found check if it has the script data requested.
13188 if (obj->IsScript()) {
13189 if (Script::cast(obj)->name()->IsString()) {
13190 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13191 script = Handle<Script>(Script::cast(obj));
13192 }
13193 }
13194 }
13195 }
13196
13197 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013198 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013199
13200 // Return the script found.
13201 return GetScriptWrapper(script);
13202}
13203
13204
13205// Get the script object from script data. NOTE: Regarding performance
13206// see the NOTE for GetScriptFromScriptData.
13207// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013208RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013209 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013210
13211 ASSERT(args.length() == 1);
13212
13213 CONVERT_CHECKED(String, script_name, args[0]);
13214
13215 // Find the requested script.
13216 Handle<Object> result =
13217 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13218 return *result;
13219}
13220
13221
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013222// Determines whether the given stack frame should be displayed in
13223// a stack trace. The caller is the error constructor that asked
13224// for the stack trace to be collected. The first time a construct
13225// call to this function is encountered it is skipped. The seen_caller
13226// in/out parameter is used to remember if the caller has been seen
13227// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013228static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13229 Object* caller,
13230 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013231 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013232 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013233 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013234 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013235 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13236 Object* raw_fun = frame->function();
13237 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013238 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013239 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013240 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013241 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013242 *seen_caller = true;
13243 return false;
13244 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013245 // Skip all frames until we've seen the caller.
13246 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013247 // Also, skip non-visible built-in functions and any call with the builtins
13248 // object as receiver, so as to not reveal either the builtins object or
13249 // an internal function.
13250 // The --builtins-in-stack-traces command line flag allows including
13251 // internal call sites in the stack trace for debugging purposes.
13252 if (!FLAG_builtins_in_stack_traces) {
13253 JSFunction* fun = JSFunction::cast(raw_fun);
13254 if (frame->receiver()->IsJSBuiltinsObject() ||
13255 (fun->IsBuiltin() && !fun->shared()->native())) {
13256 return false;
13257 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013258 }
13259 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013260}
13261
13262
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013263// Collect the raw data for a stack trace. Returns an array of 4
13264// element segments each containing a receiver, function, code and
13265// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013266RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013267 ASSERT_EQ(args.length(), 3);
13268 CONVERT_ARG_CHECKED(JSObject, error_object, 0);
13269 Handle<Object> caller = args.at<Object>(1);
13270 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013271
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013272 HandleScope scope(isolate);
13273 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013274
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013275 limit = Max(limit, 0); // Ensure that limit is not negative.
13276 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013277 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013278 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013279
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013280 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013281 // If the caller parameter is a function we skip frames until we're
13282 // under it before starting to collect.
13283 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013284 int cursor = 0;
13285 int frames_seen = 0;
13286 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013287 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013288 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013289 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013290 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013291 // Set initial size to the maximum inlining level + 1 for the outermost
13292 // function.
13293 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013294 frame->Summarize(&frames);
13295 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013296 if (cursor + 4 > elements->length()) {
13297 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13298 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013299 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013300 for (int i = 0; i < cursor; i++) {
13301 new_elements->set(i, elements->get(i));
13302 }
13303 elements = new_elements;
13304 }
13305 ASSERT(cursor + 4 <= elements->length());
13306
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013307 Handle<Object> recv = frames[i].receiver();
13308 Handle<JSFunction> fun = frames[i].function();
13309 Handle<Code> code = frames[i].code();
13310 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013311 elements->set(cursor++, *recv);
13312 elements->set(cursor++, *fun);
13313 elements->set(cursor++, *code);
13314 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013315 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013316 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013317 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013318 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013319 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013320 // Capture and attach a more detailed stack trace if necessary.
13321 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013322 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013323 return *result;
13324}
13325
13326
ager@chromium.org3811b432009-10-28 14:53:37 +000013327// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013328RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013329 ASSERT_EQ(args.length(), 0);
13330
13331 NoHandleAllocation ha;
13332
13333 const char* version_string = v8::V8::GetVersion();
13334
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013335 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13336 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013337}
13338
13339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013340RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013341 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013342 OS::PrintError("abort: %s\n",
13343 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013344 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013345 OS::Abort();
13346 UNREACHABLE();
13347 return NULL;
13348}
13349
13350
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013351RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013352 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013353 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013354 Object* key = args[1];
13355
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013356 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013357 Object* o = cache->get(finger_index);
13358 if (o == key) {
13359 // The fastest case: hit the same place again.
13360 return cache->get(finger_index + 1);
13361 }
13362
13363 for (int i = finger_index - 2;
13364 i >= JSFunctionResultCache::kEntriesIndex;
13365 i -= 2) {
13366 o = cache->get(i);
13367 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013368 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013369 return cache->get(i + 1);
13370 }
13371 }
13372
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013373 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013374 ASSERT(size <= cache->length());
13375
13376 for (int i = size - 2; i > finger_index; i -= 2) {
13377 o = cache->get(i);
13378 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013379 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013380 return cache->get(i + 1);
13381 }
13382 }
13383
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013384 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013385 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013386
13387 Handle<JSFunctionResultCache> cache_handle(cache);
13388 Handle<Object> key_handle(key);
13389 Handle<Object> value;
13390 {
13391 Handle<JSFunction> factory(JSFunction::cast(
13392 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13393 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013394 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013395 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013396 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013397 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013398 value = Execution::Call(factory,
13399 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013400 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013401 argv,
13402 &pending_exception);
13403 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013404 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013405
13406#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013407 if (FLAG_verify_heap) {
13408 cache_handle->JSFunctionResultCacheVerify();
13409 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013410#endif
13411
13412 // Function invocation may have cleared the cache. Reread all the data.
13413 finger_index = cache_handle->finger_index();
13414 size = cache_handle->size();
13415
13416 // If we have spare room, put new data into it, otherwise evict post finger
13417 // entry which is likely to be the least recently used.
13418 int index = -1;
13419 if (size < cache_handle->length()) {
13420 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13421 index = size;
13422 } else {
13423 index = finger_index + JSFunctionResultCache::kEntrySize;
13424 if (index == cache_handle->length()) {
13425 index = JSFunctionResultCache::kEntriesIndex;
13426 }
13427 }
13428
13429 ASSERT(index % 2 == 0);
13430 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13431 ASSERT(index < cache_handle->length());
13432
13433 cache_handle->set(index, *key_handle);
13434 cache_handle->set(index + 1, *value);
13435 cache_handle->set_finger_index(index);
13436
13437#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013438 if (FLAG_verify_heap) {
13439 cache_handle->JSFunctionResultCacheVerify();
13440 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013441#endif
13442
13443 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013444}
13445
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013447RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013448 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013449 CONVERT_ARG_CHECKED(String, type, 0);
13450 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013451 return *isolate->factory()->NewJSMessageObject(
13452 type,
13453 arguments,
13454 0,
13455 0,
13456 isolate->factory()->undefined_value(),
13457 isolate->factory()->undefined_value(),
13458 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013459}
13460
13461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013462RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013463 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13464 return message->type();
13465}
13466
13467
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013468RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013469 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13470 return message->arguments();
13471}
13472
13473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013474RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013475 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13476 return Smi::FromInt(message->start_position());
13477}
13478
13479
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013480RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013481 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13482 return message->script();
13483}
13484
13485
kasper.lund44510672008-07-25 07:37:58 +000013486#ifdef DEBUG
13487// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13488// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013489RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013490 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013491 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013492#define COUNT_ENTRY(Name, argc, ressize) + 1
13493 int entry_count = 0
13494 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13495 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13496 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13497#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013498 Factory* factory = isolate->factory();
13499 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013500 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013501 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013502#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013503 { \
13504 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013505 Handle<String> name; \
13506 /* Inline runtime functions have an underscore in front of the name. */ \
13507 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013508 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013509 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13510 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013511 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013512 Vector<const char>(#Name, StrLength(#Name))); \
13513 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013514 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013515 pair_elements->set(0, *name); \
13516 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013517 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013518 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013519 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013520 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013521 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013522 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013523 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013524 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013525#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013526 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013527 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013528 return *result;
13529}
kasper.lund44510672008-07-25 07:37:58 +000013530#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013531
13532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013533RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013534 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013535 CONVERT_CHECKED(String, format, args[0]);
13536 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013537 String::FlatContent format_content = format->GetFlatContent();
13538 RUNTIME_ASSERT(format_content.IsAscii());
13539 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013540 LOGGER->LogRuntime(chars, elms);
13541 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013542}
13543
13544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013545RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013546 UNREACHABLE(); // implemented as macro in the parser
13547 return NULL;
13548}
13549
13550
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013551#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13552 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13553 CONVERT_CHECKED(JSObject, obj, args[0]); \
13554 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13555 }
13556
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013557ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013558ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13559ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13560ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13561ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13562ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13563ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13564ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13565ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13566ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13567ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13568ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13569ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13570ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13571
13572#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13573
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013574
13575RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13576 ASSERT(args.length() == 2);
13577 CONVERT_CHECKED(JSObject, obj1, args[0]);
13578 CONVERT_CHECKED(JSObject, obj2, args[1]);
13579 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13580}
13581
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013582// ----------------------------------------------------------------------------
13583// Implementation of Runtime
13584
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013585#define F(name, number_of_args, result_size) \
13586 { Runtime::k##name, Runtime::RUNTIME, #name, \
13587 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013588
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013589
13590#define I(name, number_of_args, result_size) \
13591 { Runtime::kInline##name, Runtime::INLINE, \
13592 "_" #name, NULL, number_of_args, result_size },
13593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013594static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013595 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013596 INLINE_FUNCTION_LIST(I)
13597 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013598};
13599
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013600
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013601MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13602 Object* dictionary) {
13603 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013604 ASSERT(dictionary != NULL);
13605 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13606 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013607 Object* name_symbol;
13608 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013609 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013610 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13611 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013612 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013613 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13614 String::cast(name_symbol),
13615 Smi::FromInt(i),
13616 PropertyDetails(NONE, NORMAL));
13617 if (!maybe_dictionary->ToObject(&dictionary)) {
13618 // Non-recoverable failure. Calling code must restart heap
13619 // initialization.
13620 return maybe_dictionary;
13621 }
13622 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013623 }
13624 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013625}
13626
13627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013628const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13629 Heap* heap = name->GetHeap();
13630 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013631 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013632 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013633 int function_index = Smi::cast(smi_index)->value();
13634 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013635 }
13636 return NULL;
13637}
13638
13639
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013640const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013641 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13642}
13643
13644
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013645void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013646 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013647 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013648 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013649 if (isolate->heap()->new_space()->AddFreshPage()) {
13650 return;
13651 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013652 // Try to do a garbage collection; ignore it if it fails. The C
13653 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013654 isolate->heap()->CollectGarbage(failure->allocation_space(),
13655 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013656 } else {
13657 // Handle last resort GC and make sure to allow future allocations
13658 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013659 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013660 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13661 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013662 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013663}
13664
13665
13666} } // namespace v8::internal