blob: 4fc724b707f38e8045a2d50e02ae8861ced7c419 [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 }
yangguo@chromium.org56454712012-02-16 15:33:53 +00008714 Handle<Code> check_code;
8715#ifdef V8_TARGET_ARCH_IA32
8716 if (FLAG_count_based_interrupts) {
8717 InterruptStub interrupt_stub;
8718 check_code = interrupt_stub.GetCode();
8719 } else // NOLINT
8720#endif
8721 { // NOLINT
8722 StackCheckStub check_stub;
8723 check_code = check_stub.GetCode();
8724 }
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008725 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008726 Deoptimizer::RevertStackCheckCode(*unoptimized,
8727 *check_code,
8728 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008729
8730 // Allow OSR only at nesting level zero again.
8731 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8732
8733 // If the optimization attempt succeeded, return the AST id tagged as a
8734 // smi. This tells the builtin that we need to translate the unoptimized
8735 // frame to an optimized one.
8736 if (succeeded) {
8737 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8738 return Smi::FromInt(ast_id);
8739 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008740 if (function->IsMarkedForLazyRecompilation()) {
8741 function->ReplaceCode(function->shared()->code());
8742 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008743 return Smi::FromInt(-1);
8744 }
8745}
8746
8747
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008748RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8749 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8750 return isolate->heap()->undefined_value();
8751}
8752
8753
danno@chromium.orgc612e022011-11-10 11:38:15 +00008754RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8755 HandleScope scope(isolate);
8756 ASSERT(args.length() >= 2);
8757 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8758 Object* receiver = args[0];
8759 int argc = args.length() - 2;
8760
8761 // If there are too many arguments, allocate argv via malloc.
8762 const int argv_small_size = 10;
8763 Handle<Object> argv_small_buffer[argv_small_size];
8764 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8765 Handle<Object>* argv = argv_small_buffer;
8766 if (argc > argv_small_size) {
8767 argv = new Handle<Object>[argc];
8768 if (argv == NULL) return isolate->StackOverflow();
8769 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8770 }
8771
8772 for (int i = 0; i < argc; ++i) {
8773 MaybeObject* maybe = args[1 + i];
8774 Object* object;
8775 if (!maybe->To<Object>(&object)) return maybe;
8776 argv[i] = Handle<Object>(object);
8777 }
8778
8779 bool threw;
8780 Handle<JSReceiver> hfun(fun);
8781 Handle<Object> hreceiver(receiver);
8782 Handle<Object> result =
8783 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8784
8785 if (threw) return Failure::Exception();
8786 return *result;
8787}
8788
8789
lrn@chromium.org34e60782011-09-15 07:25:40 +00008790RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8791 HandleScope scope(isolate);
8792 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008793 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8794 Handle<Object> receiver = args.at<Object>(1);
8795 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8796 CONVERT_SMI_ARG_CHECKED(offset, 3);
8797 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008798 ASSERT(offset >= 0);
8799 ASSERT(argc >= 0);
8800
8801 // If there are too many arguments, allocate argv via malloc.
8802 const int argv_small_size = 10;
8803 Handle<Object> argv_small_buffer[argv_small_size];
8804 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8805 Handle<Object>* argv = argv_small_buffer;
8806 if (argc > argv_small_size) {
8807 argv = new Handle<Object>[argc];
8808 if (argv == NULL) return isolate->StackOverflow();
8809 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8810 }
8811
8812 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008813 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008814 }
8815
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008816 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008817 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008818 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008819
8820 if (threw) return Failure::Exception();
8821 return *result;
8822}
8823
8824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008825RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008826 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008827 ASSERT(args.length() == 1);
8828 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8829 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8830}
8831
8832
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008833RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008834 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008835 ASSERT(args.length() == 1);
8836 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8837 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8838}
8839
8840
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008841RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008842 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008843 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008844
kasper.lund7276f142008-07-30 08:49:36 +00008845 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008846 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008847 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008848 { MaybeObject* maybe_result =
8849 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008850 if (!maybe_result->ToObject(&result)) return maybe_result;
8851 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008852
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008853 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008854
kasper.lund7276f142008-07-30 08:49:36 +00008855 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008856}
8857
lrn@chromium.org303ada72010-10-27 09:33:13 +00008858
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008859RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8860 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008861 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008862 JSObject* extension_object;
8863 if (args[0]->IsJSObject()) {
8864 extension_object = JSObject::cast(args[0]);
8865 } else {
8866 // Convert the object to a proper JavaScript object.
8867 MaybeObject* maybe_js_object = args[0]->ToObject();
8868 if (!maybe_js_object->To(&extension_object)) {
8869 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8870 HandleScope scope(isolate);
8871 Handle<Object> handle = args.at<Object>(0);
8872 Handle<Object> result =
8873 isolate->factory()->NewTypeError("with_expression",
8874 HandleVector(&handle, 1));
8875 return isolate->Throw(*result);
8876 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008877 return maybe_js_object;
8878 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008879 }
8880 }
8881
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008882 JSFunction* function;
8883 if (args[1]->IsSmi()) {
8884 // A smi sentinel indicates a context nested inside global code rather
8885 // than some function. There is a canonical empty function that can be
8886 // gotten from the global context.
8887 function = isolate->context()->global_context()->closure();
8888 } else {
8889 function = JSFunction::cast(args[1]);
8890 }
8891
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008892 Context* context;
8893 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008894 isolate->heap()->AllocateWithContext(function,
8895 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008896 extension_object);
8897 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008898 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008899 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008900}
8901
8902
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008903RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008904 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008905 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008906 String* name = String::cast(args[0]);
8907 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008908 JSFunction* function;
8909 if (args[2]->IsSmi()) {
8910 // A smi sentinel indicates a context nested inside global code rather
8911 // than some function. There is a canonical empty function that can be
8912 // gotten from the global context.
8913 function = isolate->context()->global_context()->closure();
8914 } else {
8915 function = JSFunction::cast(args[2]);
8916 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008917 Context* context;
8918 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008919 isolate->heap()->AllocateCatchContext(function,
8920 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008921 name,
8922 thrown_object);
8923 if (!maybe_context->To(&context)) return maybe_context;
8924 isolate->set_context(context);
8925 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008926}
8927
8928
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008929RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8930 NoHandleAllocation ha;
8931 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008932 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008933 JSFunction* function;
8934 if (args[1]->IsSmi()) {
8935 // A smi sentinel indicates a context nested inside global code rather
8936 // than some function. There is a canonical empty function that can be
8937 // gotten from the global context.
8938 function = isolate->context()->global_context()->closure();
8939 } else {
8940 function = JSFunction::cast(args[1]);
8941 }
8942 Context* context;
8943 MaybeObject* maybe_context =
8944 isolate->heap()->AllocateBlockContext(function,
8945 isolate->context(),
8946 scope_info);
8947 if (!maybe_context->To(&context)) return maybe_context;
8948 isolate->set_context(context);
8949 return context;
8950}
8951
8952
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008953RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008954 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008955 ASSERT(args.length() == 2);
8956
8957 CONVERT_ARG_CHECKED(Context, context, 0);
8958 CONVERT_ARG_CHECKED(String, name, 1);
8959
8960 int index;
8961 PropertyAttributes attributes;
8962 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008963 BindingFlags binding_flags;
8964 Handle<Object> holder = context->Lookup(name,
8965 flags,
8966 &index,
8967 &attributes,
8968 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008969
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008970 // If the slot was not found the result is true.
8971 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008972 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008973 }
8974
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008975 // If the slot was found in a context, it should be DONT_DELETE.
8976 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008977 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008978 }
8979
8980 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008981 // the global object, or the subject of a with. Try to delete it
8982 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008983 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008984 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008985}
8986
8987
ager@chromium.orga1645e22009-09-09 19:27:10 +00008988// A mechanism to return a pair of Object pointers in registers (if possible).
8989// How this is achieved is calling convention-dependent.
8990// All currently supported x86 compiles uses calling conventions that are cdecl
8991// variants where a 64-bit value is returned in two 32-bit registers
8992// (edx:eax on ia32, r1:r0 on ARM).
8993// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8994// In Win64 calling convention, a struct of two pointers is returned in memory,
8995// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008996#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008997struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008998 MaybeObject* x;
8999 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009000};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009001
lrn@chromium.org303ada72010-10-27 09:33:13 +00009002static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009003 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00009004 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
9005 // In Win64 they are assigned to a hidden first argument.
9006 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009007}
9008#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009009typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00009010static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009011 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009012 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009013}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00009014#endif
9015
9016
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009017static inline MaybeObject* Unhole(Heap* heap,
9018 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00009019 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009020 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
9021 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009022 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023}
9024
9025
danno@chromium.org40cb8782011-05-25 07:58:50 +00009026static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
9027 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009028 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009029 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009030 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009031 JSFunction* context_extension_function =
9032 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009033 // If the holder isn't a context extension object, we just return it
9034 // as the receiver. This allows arguments objects to be used as
9035 // receivers, but only if they are put in the context scope chain
9036 // explicitly via a with-statement.
9037 Object* constructor = holder->map()->constructor();
9038 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00009039 // Fall back to using the global object as the implicit receiver if
9040 // the property turns out to be a local variable allocated in a
9041 // context extension object - introduced via eval. Implicit global
9042 // receivers are indicated with the hole value.
9043 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009044}
9045
9046
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009047static ObjectPair LoadContextSlotHelper(Arguments args,
9048 Isolate* isolate,
9049 bool throw_error) {
9050 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00009051 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009053 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009054 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009055 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009056 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009057 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009058
9059 int index;
9060 PropertyAttributes attributes;
9061 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009062 BindingFlags binding_flags;
9063 Handle<Object> holder = context->Lookup(name,
9064 flags,
9065 &index,
9066 &attributes,
9067 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009068
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009069 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009070 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009071 ASSERT(holder->IsContext());
9072 // If the "property" we were looking for is a local variable, the
9073 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00009074 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009075 // Use the hole as the receiver to signal that the receiver is implicit
9076 // and that the global receiver should be used (as distinguished from an
9077 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00009078 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009079 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009080 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009081 switch (binding_flags) {
9082 case MUTABLE_CHECK_INITIALIZED:
9083 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
9084 if (value->IsTheHole()) {
9085 Handle<Object> reference_error =
9086 isolate->factory()->NewReferenceError("not_defined",
9087 HandleVector(&name, 1));
9088 return MakePair(isolate->Throw(*reference_error), NULL);
9089 }
9090 // FALLTHROUGH
9091 case MUTABLE_IS_INITIALIZED:
9092 case IMMUTABLE_IS_INITIALIZED:
9093 case IMMUTABLE_IS_INITIALIZED_HARMONY:
9094 ASSERT(!value->IsTheHole());
9095 return MakePair(value, *receiver);
9096 case IMMUTABLE_CHECK_INITIALIZED:
9097 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9098 case MISSING_BINDING:
9099 UNREACHABLE();
9100 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009101 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 }
9103
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009104 // Otherwise, if the slot was found the holder is a context extension
9105 // object, subject of a with, or a global object. We read the named
9106 // property from it.
9107 if (!holder.is_null()) {
9108 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9109 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009110 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009111 Handle<Object> receiver_handle(object->IsGlobalObject()
9112 ? GlobalObject::cast(*object)->global_receiver()
9113 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009114
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009115 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009116 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009117 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009118 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009119 }
9120
9121 if (throw_error) {
9122 // The property doesn't exist - throw exception.
9123 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009124 isolate->factory()->NewReferenceError("not_defined",
9125 HandleVector(&name, 1));
9126 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009127 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009128 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009129 return MakePair(isolate->heap()->undefined_value(),
9130 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009131 }
9132}
9133
9134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009135RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137}
9138
9139
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009140RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009141 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009142}
9143
9144
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009145RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009146 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009147 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009149 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009150 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009151 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009152 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9153 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9154 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009155
9156 int index;
9157 PropertyAttributes attributes;
9158 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009159 BindingFlags binding_flags;
9160 Handle<Object> holder = context->Lookup(name,
9161 flags,
9162 &index,
9163 &attributes,
9164 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009165
9166 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009167 // The property was found in a context slot.
9168 Handle<Context> context = Handle<Context>::cast(holder);
9169 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9170 context->get(index)->IsTheHole()) {
9171 Handle<Object> error =
9172 isolate->factory()->NewReferenceError("not_defined",
9173 HandleVector(&name, 1));
9174 return isolate->Throw(*error);
9175 }
9176 // Ignore if read_only variable.
9177 if ((attributes & READ_ONLY) == 0) {
9178 // Context is a fixed array and set cannot fail.
9179 context->set(index, *value);
9180 } else if (strict_mode == kStrictMode) {
9181 // Setting read only property in strict mode.
9182 Handle<Object> error =
9183 isolate->factory()->NewTypeError("strict_cannot_assign",
9184 HandleVector(&name, 1));
9185 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009186 }
9187 return *value;
9188 }
9189
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009190 // Slow case: The property is not in a context slot. It is either in a
9191 // context extension object, a property of the subject of a with, or a
9192 // property of the global object.
9193 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009194
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009195 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009196 // The property exists on the holder.
9197 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009198 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009199 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009200 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009201
9202 if (strict_mode == kStrictMode) {
9203 // Throw in strict mode (assignment to undefined variable).
9204 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009205 isolate->factory()->NewReferenceError(
9206 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009207 return isolate->Throw(*error);
9208 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009209 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009210 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009211 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009212 }
9213
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009214 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009215 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009216 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009217 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009218 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009219 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009220 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009221 // Setting read only property in strict mode.
9222 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009223 isolate->factory()->NewTypeError(
9224 "strict_cannot_assign", HandleVector(&name, 1));
9225 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009226 }
9227 return *value;
9228}
9229
9230
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009231RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009232 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009233 ASSERT(args.length() == 1);
9234
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009235 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009236}
9237
9238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009239RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009240 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009241 ASSERT(args.length() == 1);
9242
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009243 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009244}
9245
9246
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009247RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009248 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009249 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009250}
9251
9252
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009253RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009254 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009255 ASSERT(args.length() == 1);
9256
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009257 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009258 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009259 isolate->factory()->NewReferenceError("not_defined",
9260 HandleVector(&name, 1));
9261 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262}
9263
9264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009265RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009266 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009267
9268 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009269 if (isolate->stack_guard()->IsStackOverflow()) {
9270 NoHandleAllocation na;
9271 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009272 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009273
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009274 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275}
9276
9277
yangguo@chromium.org56454712012-02-16 15:33:53 +00009278RUNTIME_FUNCTION(MaybeObject*, Runtime_Interrupt) {
9279 ASSERT(args.length() == 0);
9280 return Execution::HandleStackGuardInterrupt();
9281}
9282
9283
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284static int StackSize() {
9285 int n = 0;
9286 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9287 return n;
9288}
9289
9290
9291static void PrintTransition(Object* result) {
9292 // indentation
9293 { const int nmax = 80;
9294 int n = StackSize();
9295 if (n <= nmax)
9296 PrintF("%4d:%*s", n, n, "");
9297 else
9298 PrintF("%4d:%*s", n, nmax, "...");
9299 }
9300
9301 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009302 JavaScriptFrame::PrintTop(stdout, true, false);
9303 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009304 } else {
9305 // function result
9306 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009307 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009308 PrintF("\n");
9309 }
9310}
9311
9312
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009313RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009314 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009315 NoHandleAllocation ha;
9316 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009317 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009318}
9319
9320
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009321RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009322 NoHandleAllocation ha;
9323 PrintTransition(args[0]);
9324 return args[0]; // return TOS
9325}
9326
9327
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009328RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009329 NoHandleAllocation ha;
9330 ASSERT(args.length() == 1);
9331
9332#ifdef DEBUG
9333 if (args[0]->IsString()) {
9334 // If we have a string, assume it's a code "marker"
9335 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009336 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009337 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009338 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9339 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009340 } else {
9341 PrintF("DebugPrint: ");
9342 }
9343 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009344 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009345 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009346 HeapObject::cast(args[0])->map()->Print();
9347 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009348#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009349 // ShortPrint is available in release mode. Print is not.
9350 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009351#endif
9352 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009353 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009354
9355 return args[0]; // return TOS
9356}
9357
9358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009359RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009360 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009361 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009362 isolate->PrintStack();
9363 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009364}
9365
9366
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009367RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009368 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009369 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009370
9371 // According to ECMA-262, section 15.9.1, page 117, the precision of
9372 // the number in a Date object representing a particular instant in
9373 // time is milliseconds. Therefore, we floor the result of getting
9374 // the OS time.
9375 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009376 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009377}
9378
9379
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009380RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009381 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009382 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009383
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009384 CONVERT_ARG_CHECKED(String, str, 0);
9385 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009386
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009387 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009388
9389 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009390 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009391 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009392 RUNTIME_ASSERT(output->HasFastElements());
9393
9394 AssertNoAllocation no_allocation;
9395
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009396 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009397 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9398 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009399 String::FlatContent str_content = str->GetFlatContent();
9400 if (str_content.IsAscii()) {
9401 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009402 output_array,
9403 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009404 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009405 ASSERT(str_content.IsTwoByte());
9406 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009407 output_array,
9408 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009409 }
9410
9411 if (result) {
9412 return *output;
9413 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009414 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009415 }
9416}
9417
9418
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009419RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009420 NoHandleAllocation ha;
9421 ASSERT(args.length() == 1);
9422
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009423 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009424 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009425 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009426}
9427
9428
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009429RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009430 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009431 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009432
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009433 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009434}
9435
9436
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009437RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009438 NoHandleAllocation ha;
9439 ASSERT(args.length() == 1);
9440
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009441 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009442 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009443}
9444
9445
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009446RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009447 ASSERT(args.length() == 1);
9448 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009449 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009450 return JSGlobalObject::cast(global)->global_receiver();
9451}
9452
9453
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009454RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009455 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009456 ASSERT_EQ(1, args.length());
9457 CONVERT_ARG_CHECKED(String, source, 0);
9458
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009459 source = Handle<String>(source->TryFlattenGetString());
ulan@chromium.org2efb9002012-01-19 15:36:35 +00009460 // Optimized fast case where we only have ASCII characters.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009461 Handle<Object> result;
9462 if (source->IsSeqAsciiString()) {
9463 result = JsonParser<true>::Parse(source);
9464 } else {
9465 result = JsonParser<false>::Parse(source);
9466 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009467 if (result.is_null()) {
9468 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009469 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009470 return Failure::Exception();
9471 }
9472 return *result;
9473}
9474
9475
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009476bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9477 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009478 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9479 // Check with callback if set.
9480 AllowCodeGenerationFromStringsCallback callback =
9481 isolate->allow_code_gen_callback();
9482 if (callback == NULL) {
9483 // No callback set and code generation disallowed.
9484 return false;
9485 } else {
9486 // Callback set. Let it decide if code generation is allowed.
9487 VMState state(isolate, EXTERNAL);
9488 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009489 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009490}
9491
9492
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009493RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009494 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009495 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009496 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009497
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009498 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009499 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009500
9501 // Check if global context allows code generation from
9502 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009503 if (context->allow_code_gen_from_strings()->IsFalse() &&
9504 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009505 return isolate->Throw(*isolate->factory()->NewError(
9506 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9507 }
9508
9509 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009510 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009511 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009512 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009513 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009514 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9515 context,
9516 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009517 return *fun;
9518}
9519
9520
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009521static ObjectPair CompileGlobalEval(Isolate* isolate,
9522 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009523 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009524 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009525 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009526 Handle<Context> context = Handle<Context>(isolate->context());
9527 Handle<Context> global_context = Handle<Context>(context->global_context());
9528
9529 // Check if global context allows code generation from
9530 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009531 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9532 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009533 isolate->Throw(*isolate->factory()->NewError(
9534 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9535 return MakePair(Failure::Exception(), NULL);
9536 }
9537
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009538 // Deal with a normal eval call with a string argument. Compile it
9539 // and return the compiled function bound in the local context.
9540 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9541 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009542 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009543 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009544 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009545 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009546 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009547 Handle<JSFunction> compiled =
9548 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009549 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009550 return MakePair(*compiled, *receiver);
9551}
9552
9553
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009554RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009555 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009556
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009557 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009558 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009559
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009560 // If "eval" didn't refer to the original GlobalEval, it's not a
9561 // direct call to eval.
9562 // (And even if it is, but the first argument isn't a string, just let
9563 // execution default to an indirect call to eval, which will also return
9564 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009565 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009566 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009567 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009568 }
9569
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009570 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009571 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009572 return CompileGlobalEval(isolate,
9573 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009574 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009575 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009576 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009577}
9578
9579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009580RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009581 // This utility adjusts the property attributes for newly created Function
9582 // object ("new Function(...)") by changing the map.
9583 // All it does is changing the prototype property to enumerable
9584 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009585 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009586 ASSERT(args.length() == 1);
9587 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009588
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009589 Handle<Map> map = func->shared()->is_classic_mode()
9590 ? isolate->function_instance_map()
9591 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009592
9593 ASSERT(func->map()->instance_type() == map->instance_type());
9594 ASSERT(func->map()->instance_size() == map->instance_size());
9595 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009596 return *func;
9597}
9598
9599
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009600RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009601 // Allocate a block of memory in NewSpace (filled with a filler).
9602 // Use as fallback for allocation in generated code when NewSpace
9603 // is full.
9604 ASSERT(args.length() == 1);
9605 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9606 int size = size_smi->value();
9607 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9608 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009609 Heap* heap = isolate->heap();
9610 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009611 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009612 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009613 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009614 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009615 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009616 }
9617 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009618 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009619}
9620
9621
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009622// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009623// array. Returns true if the element was pushed on the stack and
9624// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009625RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009626 ASSERT(args.length() == 2);
9627 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009628 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009629 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009630 int length = Smi::cast(array->length())->value();
9631 FixedArray* elements = FixedArray::cast(array->elements());
9632 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009633 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009634 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009635 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009636 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009637 { MaybeObject* maybe_obj =
9638 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009639 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9640 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009641 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009642}
9643
9644
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009645/**
9646 * A simple visitor visits every element of Array's.
9647 * The backend storage can be a fixed array for fast elements case,
9648 * or a dictionary for sparse array. Since Dictionary is a subtype
9649 * of FixedArray, the class can be used by both fast and slow cases.
9650 * The second parameter of the constructor, fast_elements, specifies
9651 * whether the storage is a FixedArray or Dictionary.
9652 *
9653 * An index limit is used to deal with the situation that a result array
9654 * length overflows 32-bit non-negative integer.
9655 */
9656class ArrayConcatVisitor {
9657 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 ArrayConcatVisitor(Isolate* isolate,
9659 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009660 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009661 isolate_(isolate),
9662 storage_(Handle<FixedArray>::cast(
9663 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009664 index_offset_(0u),
9665 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009666
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009667 ~ArrayConcatVisitor() {
9668 clear_storage();
9669 }
9670
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009671 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009672 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009673 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009674
9675 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009676 if (index < static_cast<uint32_t>(storage_->length())) {
9677 storage_->set(index, *elm);
9678 return;
9679 }
9680 // Our initial estimate of length was foiled, possibly by
9681 // getters on the arrays increasing the length of later arrays
9682 // during iteration.
9683 // This shouldn't happen in anything but pathological cases.
9684 SetDictionaryMode(index);
9685 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009686 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009687 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009688 Handle<SeededNumberDictionary> dict(
9689 SeededNumberDictionary::cast(*storage_));
9690 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009691 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009692 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009693 // Dictionary needed to grow.
9694 clear_storage();
9695 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009696 }
9697}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009698
9699 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009700 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9701 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009702 } else {
9703 index_offset_ += delta;
9704 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009705 }
9706
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009707 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009708 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009709 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009710 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009711 Handle<Map> map;
9712 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009713 map = isolate_->factory()->GetElementsTransitionMap(array,
9714 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009715 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009716 map = isolate_->factory()->GetElementsTransitionMap(array,
9717 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009718 }
9719 array->set_map(*map);
9720 array->set_length(*length);
9721 array->set_elements(*storage_);
9722 return array;
9723 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009724
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009725 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009726 // Convert storage to dictionary mode.
9727 void SetDictionaryMode(uint32_t index) {
9728 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009729 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009730 Handle<SeededNumberDictionary> slow_storage(
9731 isolate_->factory()->NewSeededNumberDictionary(
9732 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009733 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9734 for (uint32_t i = 0; i < current_length; i++) {
9735 HandleScope loop_scope;
9736 Handle<Object> element(current_storage->get(i));
9737 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009738 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009739 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009740 if (!new_storage.is_identical_to(slow_storage)) {
9741 slow_storage = loop_scope.CloseAndEscape(new_storage);
9742 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009743 }
9744 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009745 clear_storage();
9746 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009747 fast_elements_ = false;
9748 }
9749
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009750 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009751 isolate_->global_handles()->Destroy(
9752 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009753 }
9754
9755 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009756 storage_ = Handle<FixedArray>::cast(
9757 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009758 }
9759
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009760 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009761 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009762 // Index after last seen index. Always less than or equal to
9763 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009764 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009765 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009766};
9767
9768
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009769static uint32_t EstimateElementCount(Handle<JSArray> array) {
9770 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9771 int element_count = 0;
9772 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009773 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009774 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009775 // Fast elements can't have lengths that are not representable by
9776 // a 32-bit signed integer.
9777 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9778 int fast_length = static_cast<int>(length);
9779 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9780 for (int i = 0; i < fast_length; i++) {
9781 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009782 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009783 break;
9784 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009785 case FAST_DOUBLE_ELEMENTS:
9786 // TODO(1810): Decide if it's worthwhile to implement this.
9787 UNREACHABLE();
9788 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009789 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009790 Handle<SeededNumberDictionary> dictionary(
9791 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009792 int capacity = dictionary->Capacity();
9793 for (int i = 0; i < capacity; i++) {
9794 Handle<Object> key(dictionary->KeyAt(i));
9795 if (dictionary->IsKey(*key)) {
9796 element_count++;
9797 }
9798 }
9799 break;
9800 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009801 case NON_STRICT_ARGUMENTS_ELEMENTS:
9802 case EXTERNAL_BYTE_ELEMENTS:
9803 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9804 case EXTERNAL_SHORT_ELEMENTS:
9805 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9806 case EXTERNAL_INT_ELEMENTS:
9807 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9808 case EXTERNAL_FLOAT_ELEMENTS:
9809 case EXTERNAL_DOUBLE_ELEMENTS:
9810 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009811 // External arrays are always dense.
9812 return length;
9813 }
9814 // As an estimate, we assume that the prototype doesn't contain any
9815 // inherited elements.
9816 return element_count;
9817}
9818
9819
9820
9821template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009822static void IterateExternalArrayElements(Isolate* isolate,
9823 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009824 bool elements_are_ints,
9825 bool elements_are_guaranteed_smis,
9826 ArrayConcatVisitor* visitor) {
9827 Handle<ExternalArrayClass> array(
9828 ExternalArrayClass::cast(receiver->elements()));
9829 uint32_t len = static_cast<uint32_t>(array->length());
9830
9831 ASSERT(visitor != NULL);
9832 if (elements_are_ints) {
9833 if (elements_are_guaranteed_smis) {
9834 for (uint32_t j = 0; j < len; j++) {
9835 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009836 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009837 visitor->visit(j, e);
9838 }
9839 } else {
9840 for (uint32_t j = 0; j < len; j++) {
9841 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009842 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009843 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9844 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9845 visitor->visit(j, e);
9846 } else {
9847 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009848 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009849 visitor->visit(j, e);
9850 }
9851 }
9852 }
9853 } else {
9854 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009855 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009856 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009857 visitor->visit(j, e);
9858 }
9859 }
9860}
9861
9862
9863// Used for sorting indices in a List<uint32_t>.
9864static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9865 uint32_t a = *ap;
9866 uint32_t b = *bp;
9867 return (a == b) ? 0 : (a < b) ? -1 : 1;
9868}
9869
9870
9871static void CollectElementIndices(Handle<JSObject> object,
9872 uint32_t range,
9873 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009874 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009875 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009876 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009877 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009878 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9879 uint32_t length = static_cast<uint32_t>(elements->length());
9880 if (range < length) length = range;
9881 for (uint32_t i = 0; i < length; i++) {
9882 if (!elements->get(i)->IsTheHole()) {
9883 indices->Add(i);
9884 }
9885 }
9886 break;
9887 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009888 case FAST_DOUBLE_ELEMENTS: {
9889 // TODO(1810): Decide if it's worthwhile to implement this.
9890 UNREACHABLE();
9891 break;
9892 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009893 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009894 Handle<SeededNumberDictionary> dict(
9895 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009896 uint32_t capacity = dict->Capacity();
9897 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009898 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009899 Handle<Object> k(dict->KeyAt(j));
9900 if (dict->IsKey(*k)) {
9901 ASSERT(k->IsNumber());
9902 uint32_t index = static_cast<uint32_t>(k->Number());
9903 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009904 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009905 }
9906 }
9907 }
9908 break;
9909 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009910 default: {
9911 int dense_elements_length;
9912 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009913 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009914 dense_elements_length =
9915 ExternalPixelArray::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_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009919 dense_elements_length =
9920 ExternalByteArray::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_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009924 dense_elements_length =
9925 ExternalUnsignedByteArray::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_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009929 dense_elements_length =
9930 ExternalShortArray::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_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009934 dense_elements_length =
9935 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009936 break;
9937 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009938 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009939 dense_elements_length =
9940 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009941 break;
9942 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009943 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009944 dense_elements_length =
9945 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009946 break;
9947 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009948 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009949 dense_elements_length =
9950 ExternalFloatArray::cast(object->elements())->length();
9951 break;
9952 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009953 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009954 dense_elements_length =
9955 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009956 break;
9957 }
9958 default:
9959 UNREACHABLE();
9960 dense_elements_length = 0;
9961 break;
9962 }
9963 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9964 if (range <= length) {
9965 length = range;
9966 // We will add all indices, so we might as well clear it first
9967 // and avoid duplicates.
9968 indices->Clear();
9969 }
9970 for (uint32_t i = 0; i < length; i++) {
9971 indices->Add(i);
9972 }
9973 if (length == range) return; // All indices accounted for already.
9974 break;
9975 }
9976 }
9977
9978 Handle<Object> prototype(object->GetPrototype());
9979 if (prototype->IsJSObject()) {
9980 // The prototype will usually have no inherited element indices,
9981 // but we have to check.
9982 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9983 }
9984}
9985
9986
9987/**
9988 * A helper function that visits elements of a JSArray in numerical
9989 * order.
9990 *
9991 * The visitor argument called for each existing element in the array
9992 * with the element index and the element's value.
9993 * Afterwards it increments the base-index of the visitor by the array
9994 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009995 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009996 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009997static bool IterateElements(Isolate* isolate,
9998 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009999 ArrayConcatVisitor* visitor) {
10000 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
10001 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010002 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010003 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010004 // Run through the elements FixedArray and use HasElement and GetElement
10005 // to check the prototype for missing elements.
10006 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
10007 int fast_length = static_cast<int>(length);
10008 ASSERT(fast_length <= elements->length());
10009 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010010 HandleScope loop_scope(isolate);
10011 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010012 if (!element_value->IsTheHole()) {
10013 visitor->visit(j, element_value);
10014 } else if (receiver->HasElement(j)) {
10015 // Call GetElement on receiver, not its prototype, or getters won't
10016 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010017 element_value = Object::GetElement(receiver, j);
10018 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010019 visitor->visit(j, element_value);
10020 }
10021 }
10022 break;
10023 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010024 case FAST_DOUBLE_ELEMENTS: {
10025 // TODO(1810): Decide if it's worthwhile to implement this.
10026 UNREACHABLE();
10027 break;
10028 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010029 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010030 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010031 List<uint32_t> indices(dict->Capacity() / 2);
10032 // Collect all indices in the object and the prototypes less
10033 // than length. This might introduce duplicates in the indices list.
10034 CollectElementIndices(receiver, length, &indices);
10035 indices.Sort(&compareUInt32);
10036 int j = 0;
10037 int n = indices.length();
10038 while (j < n) {
10039 HandleScope loop_scope;
10040 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010041 Handle<Object> element = Object::GetElement(receiver, index);
10042 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010043 visitor->visit(index, element);
10044 // Skip to next different index (i.e., omit duplicates).
10045 do {
10046 j++;
10047 } while (j < n && indices[j] == index);
10048 }
10049 break;
10050 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010051 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +000010052 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
10053 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010054 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010055 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010056 visitor->visit(j, e);
10057 }
10058 break;
10059 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010060 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010061 IterateExternalArrayElements<ExternalByteArray, int8_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_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010066 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010067 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010068 break;
10069 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010070 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010071 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010072 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010073 break;
10074 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010075 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010076 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010077 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010078 break;
10079 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010080 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010081 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010082 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010083 break;
10084 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010085 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010086 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010087 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010088 break;
10089 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010090 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010091 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010092 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010093 break;
10094 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010095 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +000010096 IterateExternalArrayElements<ExternalDoubleArray, double>(
10097 isolate, receiver, false, false, visitor);
10098 break;
10099 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000010100 default:
10101 UNREACHABLE();
10102 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010103 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010104 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010105 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010106}
10107
10108
10109/**
10110 * Array::concat implementation.
10111 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010112 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010113 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010114 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010115RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010116 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010117 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010118
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010119 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10120 int argument_count = static_cast<int>(arguments->length()->Number());
10121 RUNTIME_ASSERT(arguments->HasFastElements());
10122 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010123
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010124 // Pass 1: estimate the length and number of elements of the result.
10125 // The actual length can be larger if any of the arguments have getters
10126 // that mutate other arguments (but will otherwise be precise).
10127 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010128
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010129 uint32_t estimate_result_length = 0;
10130 uint32_t estimate_nof_elements = 0;
10131 {
10132 for (int i = 0; i < argument_count; i++) {
10133 HandleScope loop_scope;
10134 Handle<Object> obj(elements->get(i));
10135 uint32_t length_estimate;
10136 uint32_t element_estimate;
10137 if (obj->IsJSArray()) {
10138 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010139 // TODO(1810): Find out if it's worthwhile to properly support
10140 // arbitrary ElementsKinds. For now, pessimistically transition to
10141 // FAST_ELEMENTS.
10142 if (array->HasFastDoubleElements()) {
10143 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010144 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010145 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010146 length_estimate =
10147 static_cast<uint32_t>(array->length()->Number());
10148 element_estimate =
10149 EstimateElementCount(array);
10150 } else {
10151 length_estimate = 1;
10152 element_estimate = 1;
10153 }
10154 // Avoid overflows by capping at kMaxElementCount.
10155 if (JSObject::kMaxElementCount - estimate_result_length <
10156 length_estimate) {
10157 estimate_result_length = JSObject::kMaxElementCount;
10158 } else {
10159 estimate_result_length += length_estimate;
10160 }
10161 if (JSObject::kMaxElementCount - estimate_nof_elements <
10162 element_estimate) {
10163 estimate_nof_elements = JSObject::kMaxElementCount;
10164 } else {
10165 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010166 }
10167 }
10168 }
10169
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010170 // If estimated number of elements is more than half of length, a
10171 // fixed array (fast case) is more time and space-efficient than a
10172 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010173 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010174
10175 Handle<FixedArray> storage;
10176 if (fast_case) {
10177 // The backing storage array must have non-existing elements to
10178 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010179 storage = isolate->factory()->NewFixedArrayWithHoles(
10180 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010181 } else {
10182 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10183 uint32_t at_least_space_for = estimate_nof_elements +
10184 (estimate_nof_elements >> 2);
10185 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010186 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010187 }
10188
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010189 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010190
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010191 for (int i = 0; i < argument_count; i++) {
10192 Handle<Object> obj(elements->get(i));
10193 if (obj->IsJSArray()) {
10194 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010195 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010196 return Failure::Exception();
10197 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010198 } else {
10199 visitor.visit(0, obj);
10200 visitor.increase_index_offset(1);
10201 }
10202 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010203
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010204 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010205}
10206
10207
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010208// This will not allocate (flatten the string), but it may run
10209// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010210RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010211 NoHandleAllocation ha;
10212 ASSERT(args.length() == 1);
10213
10214 CONVERT_CHECKED(String, string, args[0]);
10215 StringInputBuffer buffer(string);
10216 while (buffer.has_more()) {
10217 uint16_t character = buffer.GetNext();
10218 PrintF("%c", character);
10219 }
10220 return string;
10221}
10222
ager@chromium.org5ec48922009-05-05 07:25:34 +000010223// Moves all own elements of an object, that are below a limit, to positions
10224// starting at zero. All undefined values are placed after non-undefined values,
10225// and are followed by non-existing element. Does not change the length
10226// property.
10227// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010228RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010229 ASSERT(args.length() == 2);
10230 CONVERT_CHECKED(JSObject, object, args[0]);
10231 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10232 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010233}
10234
10235
10236// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010237RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010238 ASSERT(args.length() == 2);
10239 CONVERT_CHECKED(JSArray, from, args[0]);
10240 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010241 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010242 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010243 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10245 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010246 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010247 } else if (new_elements->map() ==
10248 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010249 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010250 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010251 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010252 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010253 maybe_new_map = to->GetElementsTransitionMap(isolate, elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010254 Object* new_map;
10255 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010256 to->set_map(Map::cast(new_map));
10257 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010258 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010259 Object* obj;
10260 { MaybeObject* maybe_obj = from->ResetElements();
10261 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10262 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010263 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010264 return to;
10265}
10266
10267
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010268// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010269RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010270 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010271 CONVERT_CHECKED(JSObject, object, args[0]);
10272 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010273 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010274 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10275 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010276 } else if (object->IsJSArray()) {
10277 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010278 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010279 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010280 }
10281}
10282
10283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010284RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010285 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010286
10287 ASSERT_EQ(3, args.length());
10288
ager@chromium.orgac091b72010-05-05 07:34:42 +000010289 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010290 Handle<Object> key1 = args.at<Object>(1);
10291 Handle<Object> key2 = args.at<Object>(2);
10292
10293 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010294 if (!key1->ToArrayIndex(&index1)
10295 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010296 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010297 }
10298
ager@chromium.orgac091b72010-05-05 07:34:42 +000010299 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010300 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010301 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010302 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010303 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010304
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010305 RETURN_IF_EMPTY_HANDLE(
10306 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10307 RETURN_IF_EMPTY_HANDLE(
10308 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010309
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010310 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010311}
10312
10313
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010314// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010315// might have elements. Can either return keys (positive integers) or
10316// intervals (pair of a negative integer (-start-1) followed by a
10317// positive (length)) or undefined values.
10318// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010319RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010320 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010321 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010322 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010323 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010324 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010325 // Create an array and get all the keys into it, then remove all the
10326 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010327 bool threw = false;
10328 Handle<FixedArray> keys =
10329 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10330 if (threw) return Failure::Exception();
10331
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010332 int keys_length = keys->length();
10333 for (int i = 0; i < keys_length; i++) {
10334 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010335 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010336 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010337 // Zap invalid keys.
10338 keys->set_undefined(i);
10339 }
10340 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010341 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010343 ASSERT(array->HasFastElements() ||
10344 array->HasFastSmiOnlyElements() ||
10345 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010346 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010348 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010349 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010350 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010351 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010352 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010353 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010354 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010355 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010356 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010357 }
10358}
10359
10360
10361// DefineAccessor takes an optional final argument which is the
ulan@chromium.org2efb9002012-01-19 15:36:35 +000010362// property attributes (e.g. DONT_ENUM, DONT_DELETE). IMPORTANT: due
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010363// to the way accessors are implemented, it is set for both the getter
10364// and setter on the first call to DefineAccessor and ignored on
10365// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010366RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010367 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10368 // Compute attributes.
10369 PropertyAttributes attributes = NONE;
10370 if (args.length() == 5) {
10371 CONVERT_CHECKED(Smi, attrs, args[4]);
10372 int value = attrs->value();
10373 // Only attribute bits should be set.
10374 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10375 attributes = static_cast<PropertyAttributes>(value);
10376 }
10377
10378 CONVERT_CHECKED(JSObject, obj, args[0]);
10379 CONVERT_CHECKED(String, name, args[1]);
10380 CONVERT_CHECKED(Smi, flag, args[2]);
10381 CONVERT_CHECKED(JSFunction, fun, args[3]);
10382 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10383}
10384
10385
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010386RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010387 ASSERT(args.length() == 3);
10388 CONVERT_CHECKED(JSObject, obj, args[0]);
10389 CONVERT_CHECKED(String, name, args[1]);
10390 CONVERT_CHECKED(Smi, flag, args[2]);
10391 return obj->LookupAccessor(name, flag->value() == 0);
10392}
10393
10394
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010395#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010396RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010397 ASSERT(args.length() == 0);
10398 return Execution::DebugBreakHelper();
10399}
10400
10401
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010402// Helper functions for wrapping and unwrapping stack frame ids.
10403static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010404 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010405 return Smi::FromInt(id >> 2);
10406}
10407
10408
10409static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10410 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10411}
10412
10413
10414// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010415// args[0]: debug event listener function to set or null or undefined for
10416// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010417// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010418RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010419 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010420 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10421 args[0]->IsUndefined() ||
10422 args[0]->IsNull());
10423 Handle<Object> callback = args.at<Object>(0);
10424 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010425 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010426
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010427 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010428}
10429
10430
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010431RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010432 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010433 isolate->stack_guard()->DebugBreak();
10434 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010435}
10436
10437
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010438static MaybeObject* DebugLookupResultValue(Heap* heap,
10439 Object* receiver,
10440 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010441 LookupResult* result,
10442 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010443 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010444 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010445 case NORMAL:
10446 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010447 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010448 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010449 }
10450 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010451 case FIELD:
10452 value =
10453 JSObject::cast(
10454 result->holder())->FastPropertyAt(result->GetFieldIndex());
10455 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010456 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010457 }
10458 return value;
10459 case CONSTANT_FUNCTION:
10460 return result->GetConstantFunction();
10461 case CALLBACKS: {
10462 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010463 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010464 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10465 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010466 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010467 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010468 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010469 maybe_value = heap->isolate()->pending_exception();
10470 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010471 if (caught_exception != NULL) {
10472 *caught_exception = true;
10473 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010474 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010475 }
10476 return value;
10477 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010478 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010479 }
10480 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010481 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010482 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010483 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010484 case CONSTANT_TRANSITION:
10485 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010486 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010487 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010488 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010489 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010490 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010491 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010492 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010493}
10494
10495
ager@chromium.org32912102009-01-16 10:38:43 +000010496// Get debugger related details for an object property.
10497// args[0]: object holding property
10498// args[1]: name of the property
10499//
10500// The array returned contains the following information:
10501// 0: Property value
10502// 1: Property details
10503// 2: Property value is exception
10504// 3: Getter function if defined
10505// 4: Setter function if defined
10506// Items 2-4 are only filled if the property has either a getter or a setter
10507// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010508RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010509 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010510
10511 ASSERT(args.length() == 2);
10512
10513 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10514 CONVERT_ARG_CHECKED(String, name, 1);
10515
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010516 // Make sure to set the current context to the context before the debugger was
10517 // entered (if the debugger is entered). The reason for switching context here
10518 // is that for some property lookups (accessors and interceptors) callbacks
10519 // into the embedding application can occour, and the embedding application
10520 // could have the assumption that its own global context is the current
10521 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010522 SaveContext save(isolate);
10523 if (isolate->debug()->InDebugger()) {
10524 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010525 }
10526
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010527 // Skip the global proxy as it has no properties and always delegates to the
10528 // real global object.
10529 if (obj->IsJSGlobalProxy()) {
10530 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10531 }
10532
10533
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 // Check if the name is trivially convertible to an index and get the element
10535 // if so.
10536 uint32_t index;
10537 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010538 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010539 Object* element_or_char;
10540 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010541 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010542 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10543 return maybe_element_or_char;
10544 }
10545 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010546 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010547 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010548 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010549 }
10550
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010551 // Find the number of objects making up this.
10552 int length = LocalPrototypeChainLength(*obj);
10553
10554 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010555 Handle<JSObject> jsproto = obj;
10556 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010557 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010558 jsproto->LocalLookup(*name, &result);
10559 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010560 // LookupResult is not GC safe as it holds raw object pointers.
10561 // GC can happen later in this code so put the required fields into
10562 // local variables using handles when required for later use.
10563 PropertyType result_type = result.type();
10564 Handle<Object> result_callback_obj;
10565 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010566 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10567 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010568 }
10569 Smi* property_details = result.GetPropertyDetails().AsSmi();
10570 // DebugLookupResultValue can cause GC so details from LookupResult needs
10571 // to be copied to handles before this.
10572 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010573 Object* raw_value;
10574 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010575 DebugLookupResultValue(isolate->heap(), *obj, *name,
10576 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010577 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10578 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010579 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010580
10581 // If the callback object is a fixed array then it contains JavaScript
10582 // getter and/or setter.
10583 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010584 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010585 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010586 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010587 details->set(0, *value);
10588 details->set(1, property_details);
10589 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010590 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010591 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10592 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010593 }
10594
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010596 }
10597 if (i < length - 1) {
10598 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10599 }
10600 }
10601
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010602 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010603}
10604
10605
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010606RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010608
10609 ASSERT(args.length() == 2);
10610
10611 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10612 CONVERT_ARG_CHECKED(String, name, 1);
10613
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010614 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010615 obj->Lookup(*name, &result);
10616 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010617 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010618 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010619 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010620}
10621
10622
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010623// Return the property type calculated from the property details.
10624// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010625RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010626 ASSERT(args.length() == 1);
10627 CONVERT_CHECKED(Smi, details, args[0]);
10628 PropertyType type = PropertyDetails(details).type();
10629 return Smi::FromInt(static_cast<int>(type));
10630}
10631
10632
10633// Return the property attribute calculated from the property details.
10634// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010635RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010636 ASSERT(args.length() == 1);
10637 CONVERT_CHECKED(Smi, details, args[0]);
10638 PropertyAttributes attributes = PropertyDetails(details).attributes();
10639 return Smi::FromInt(static_cast<int>(attributes));
10640}
10641
10642
10643// Return the property insertion index calculated from the property details.
10644// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010645RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010646 ASSERT(args.length() == 1);
10647 CONVERT_CHECKED(Smi, details, args[0]);
10648 int index = PropertyDetails(details).index();
10649 return Smi::FromInt(index);
10650}
10651
10652
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010653// Return property value from named interceptor.
10654// args[0]: object
10655// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010656RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
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->HasNamedInterceptor());
10661 CONVERT_ARG_CHECKED(String, name, 1);
10662
10663 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010664 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010665}
10666
10667
10668// Return element value from indexed interceptor.
10669// args[0]: object
10670// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010671RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010672 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010673 ASSERT(args.length() == 2);
10674 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10675 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10676 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10677
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010678 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010679}
10680
10681
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010682RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010683 ASSERT(args.length() >= 1);
10684 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010685 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010686 if (isolate->debug()->break_id() == 0 ||
10687 break_id != isolate->debug()->break_id()) {
10688 return isolate->Throw(
10689 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010690 }
10691
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010692 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010693}
10694
10695
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010696RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010697 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010698 ASSERT(args.length() == 1);
10699
10700 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010701 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010702 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10703 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010704 if (!maybe_result->ToObject(&result)) return maybe_result;
10705 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010706
10707 // Count all frames which are relevant to debugging stack trace.
10708 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010709 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010710 if (id == StackFrame::NO_ID) {
10711 // If there is no JavaScript stack frame count is 0.
10712 return Smi::FromInt(0);
10713 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010714
10715 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10716 n += it.frame()->GetInlineCount();
10717 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010718 return Smi::FromInt(n);
10719}
10720
10721
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010722class FrameInspector {
10723 public:
10724 FrameInspector(JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010725 int inlined_jsframe_index,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010726 Isolate* isolate)
10727 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10728 // Calculate the deoptimized frame.
10729 if (frame->is_optimized()) {
10730 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010731 frame, inlined_jsframe_index, isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010732 }
10733 has_adapted_arguments_ = frame_->has_adapted_arguments();
10734 is_optimized_ = frame_->is_optimized();
10735 }
10736
10737 ~FrameInspector() {
10738 // Get rid of the calculated deoptimized frame if any.
10739 if (deoptimized_frame_ != NULL) {
10740 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10741 isolate_);
10742 }
10743 }
10744
10745 int GetParametersCount() {
10746 return is_optimized_
10747 ? deoptimized_frame_->parameters_count()
10748 : frame_->ComputeParametersCount();
10749 }
10750 int expression_count() { return deoptimized_frame_->expression_count(); }
10751 Object* GetFunction() {
10752 return is_optimized_
10753 ? deoptimized_frame_->GetFunction()
10754 : frame_->function();
10755 }
10756 Object* GetParameter(int index) {
10757 return is_optimized_
10758 ? deoptimized_frame_->GetParameter(index)
10759 : frame_->GetParameter(index);
10760 }
10761 Object* GetExpression(int index) {
10762 return is_optimized_
10763 ? deoptimized_frame_->GetExpression(index)
10764 : frame_->GetExpression(index);
10765 }
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010766 int GetSourcePosition() {
10767 return is_optimized_
10768 ? deoptimized_frame_->GetSourcePosition()
10769 : frame_->LookupCode()->SourcePosition(frame_->pc());
10770 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010771
10772 // To inspect all the provided arguments the frame might need to be
10773 // replaced with the arguments frame.
10774 void SetArgumentsFrame(JavaScriptFrame* frame) {
10775 ASSERT(has_adapted_arguments_);
10776 frame_ = frame;
10777 is_optimized_ = frame_->is_optimized();
10778 ASSERT(!is_optimized_);
10779 }
10780
10781 private:
10782 JavaScriptFrame* frame_;
10783 DeoptimizedFrameInfo* deoptimized_frame_;
10784 Isolate* isolate_;
10785 bool is_optimized_;
10786 bool has_adapted_arguments_;
10787
10788 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10789};
10790
10791
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010792static const int kFrameDetailsFrameIdIndex = 0;
10793static const int kFrameDetailsReceiverIndex = 1;
10794static const int kFrameDetailsFunctionIndex = 2;
10795static const int kFrameDetailsArgumentCountIndex = 3;
10796static const int kFrameDetailsLocalCountIndex = 4;
10797static const int kFrameDetailsSourcePositionIndex = 5;
10798static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010799static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010800static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010801static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010802
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010803
10804static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10805 JavaScriptFrame* frame) {
10806 SaveContext* save = isolate->save_context();
10807 while (save != NULL && !save->IsBelowFrame(frame)) {
10808 save = save->prev();
10809 }
10810 ASSERT(save != NULL);
10811 return save;
10812}
10813
10814
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010815// Return an array with frame details
10816// args[0]: number: break id
10817// args[1]: number: frame index
10818//
10819// The array returned contains the following information:
10820// 0: Frame id
10821// 1: Receiver
10822// 2: Function
10823// 3: Argument count
10824// 4: Local count
10825// 5: Source position
10826// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010827// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010828// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010829// Arguments name, value
10830// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010831// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010832RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010833 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010834 ASSERT(args.length() == 2);
10835
10836 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010837 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010838 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10839 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010840 if (!maybe_check->ToObject(&check)) return maybe_check;
10841 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010842 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010843 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010844
10845 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010846 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010847 if (id == StackFrame::NO_ID) {
10848 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010849 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010850 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010851
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010852 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010853 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010854 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010855 if (index < count + it.frame()->GetInlineCount()) break;
10856 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010857 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010858 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010860 bool is_optimized = it.frame()->is_optimized();
10861
10862 int inlined_jsframe_index = 0; // Inlined frame index in optimized frame.
10863 if (is_optimized) {
10864 inlined_jsframe_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010865 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010866 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010867 FrameInspector frame_inspector(it.frame(), inlined_jsframe_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010868
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010869 // Traverse the saved contexts chain to find the active context for the
10870 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010871 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010872
10873 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010874 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010875
danno@chromium.orgfa458e42012-02-01 10:48:36 +000010876 // Find source position in unoptimized code.
10877 int position = frame_inspector.GetSourcePosition();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010878
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010879 // Check for constructor frame. Inlined frames cannot be construct calls.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010880 bool inlined_frame = is_optimized && inlined_jsframe_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010881 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010882
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010883 // Get scope info and read from it for local variable information.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010884 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010885 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010886 Handle<ScopeInfo> scope_info(shared->scope_info());
10887 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010888
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010889 // Get the locals names and values into a temporary array.
10890 //
10891 // TODO(1240907): Hide compiler-introduced stack variables
10892 // (e.g. .result)? For users of the debugger, they will probably be
10893 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010894 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010895 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010897 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010898 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010899 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010900 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010901 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010902 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010903 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010904 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010905 // Get the context containing declarations.
10906 Handle<Context> context(
10907 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010908 for (; i < scope_info->LocalCount(); ++i) {
10909 Handle<String> name(scope_info->LocalName(i));
10910 VariableMode mode;
10911 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010912 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010913 locals->set(i * 2 + 1, context->get(
10914 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010915 }
10916 }
10917
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010918 // Check whether this frame is positioned at return. If not top
10919 // frame or if the frame is optimized it cannot be at a return.
10920 bool at_return = false;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010921 if (!is_optimized && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010922 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010923 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010924
10925 // If positioned just before return find the value to be returned and add it
10926 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010927 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010928 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010929 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010930 Address internal_frame_sp = NULL;
10931 while (!it2.done()) {
10932 if (it2.frame()->is_internal()) {
10933 internal_frame_sp = it2.frame()->sp();
10934 } else {
10935 if (it2.frame()->is_java_script()) {
10936 if (it2.frame()->id() == it.frame()->id()) {
10937 // The internal frame just before the JavaScript frame contains the
10938 // value to return on top. A debug break at return will create an
10939 // internal frame to store the return value (eax/rax/r0) before
10940 // entering the debug break exit frame.
10941 if (internal_frame_sp != NULL) {
10942 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010943 Handle<Object>(Memory::Object_at(internal_frame_sp),
10944 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010945 break;
10946 }
10947 }
10948 }
10949
10950 // Indicate that the previous frame was not an internal frame.
10951 internal_frame_sp = NULL;
10952 }
10953 it2.Advance();
10954 }
10955 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010956
10957 // Now advance to the arguments adapter frame (if any). It contains all
10958 // the provided parameters whereas the function frame always have the number
10959 // of arguments matching the functions parameters. The rest of the
10960 // information (except for what is collected above) is the same.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000010961 if ((inlined_jsframe_index == 0) && it.frame()->has_adapted_arguments()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010962 it.AdvanceToArgumentsFrame();
10963 frame_inspector.SetArgumentsFrame(it.frame());
10964 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010965
10966 // Find the number of arguments to fill. At least fill the number of
10967 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010968 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010969 if (argument_count < frame_inspector.GetParametersCount()) {
10970 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010971 }
10972
10973 // Calculate the size of the result.
10974 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010975 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010976 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010977 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010978
10979 // Add the frame id.
10980 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10981
10982 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010983 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010984
10985 // Add the arguments count.
10986 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10987
10988 // Add the locals count
10989 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010990 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010991
10992 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010993 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010994 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10995 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010996 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010997 }
10998
10999 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011000 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011001
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011002 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011003 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011004
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011005 // Add flags to indicate information on whether this frame is
11006 // bit 0: invoked in the debugger context.
11007 // bit 1: optimized frame.
11008 // bit 2: inlined in optimized frame
11009 int flags = 0;
11010 if (*save->context() == *isolate->debug()->debug_context()) {
11011 flags |= 1 << 0;
11012 }
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011013 if (is_optimized) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011014 flags |= 1 << 1;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011015 flags |= inlined_jsframe_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011016 }
11017 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011018
11019 // Fill the dynamic part.
11020 int details_index = kFrameDetailsFirstDynamicIndex;
11021
11022 // Add arguments name and value.
11023 for (int i = 0; i < argument_count; i++) {
11024 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011025 if (i < scope_info->ParameterCount()) {
11026 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011027 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011028 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011029 }
11030
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000011031 // Parameter value.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011032 if (i < frame_inspector.GetParametersCount()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011033 // Get the value from the stack.
11034 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011035 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011036 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011037 }
11038 }
11039
11040 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011041 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011042 details->set(details_index++, locals->get(i));
11043 }
11044
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000011045 // Add the value being returned.
11046 if (at_return) {
11047 details->set(details_index++, *return_value);
11048 }
11049
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011050 // Add the receiver (same as in function frame).
11051 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
11052 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011053 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011054 if (!receiver->IsJSObject() &&
11055 shared->is_classic_mode() &&
11056 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000011057 // If the receiver is not a JSObject and the function is not a
11058 // builtin or strict-mode we have hit an optimization where a
11059 // value object is not converted into a wrapped JS objects. To
11060 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011061 // by creating correct wrapper object based on the calling frame's
11062 // global context.
11063 it.Advance();
11064 Handle<Context> calling_frames_global_context(
11065 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011066 receiver =
11067 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011068 }
11069 details->set(kFrameDetailsReceiverIndex, *receiver);
11070
11071 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011072 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011073}
11074
11075
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011076// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011077static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011078 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011079 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000011080 Handle<Context> context,
11081 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011082 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011083 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
11084 VariableMode mode;
11085 InitializationFlag init_flag;
11086 int context_index = scope_info->ContextSlotIndex(
11087 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088
whesse@chromium.org7b260152011-06-20 15:33:18 +000011089 RETURN_IF_EMPTY_HANDLE_VALUE(
11090 isolate,
11091 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011092 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000011093 Handle<Object>(context->get(context_index), isolate),
11094 NONE,
11095 kNonStrictMode),
11096 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011097 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011098
11099 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011100}
11101
11102
11103// Create a plain JSObject which materializes the local scope for the specified
11104// frame.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011105static Handle<JSObject> MaterializeLocalScopeWithFrameInspector(
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011106 Isolate* isolate,
11107 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011108 FrameInspector* frame_inspector) {
11109 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011110 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011111 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112
11113 // Allocate and initialize a JSObject with all the arguments, stack locals
11114 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011115 Handle<JSObject> local_scope =
11116 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011117
11118 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011119 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011120 Handle<Object> value(
11121 i < frame_inspector->GetParametersCount() ?
11122 frame_inspector->GetParameter(i) : isolate->heap()->undefined_value());
11123
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011124 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011125 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011126 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011127 Handle<String>(scope_info->ParameterName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011128 value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011129 NONE,
11130 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011131 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011132 }
11133
11134 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011135 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011136 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011137 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011138 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011139 Handle<String>(scope_info->StackLocalName(i)),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011140 Handle<Object>(frame_inspector->GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011141 NONE,
11142 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011143 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011144 }
11145
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011146 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011147 // Third fill all context locals.
11148 Handle<Context> frame_context(Context::cast(frame->context()));
11149 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011150 if (!CopyContextLocalsToScopeObject(
11151 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011152 return Handle<JSObject>();
11153 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011154
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011155 // Finally copy any properties from the function context extension.
11156 // These will be variables introduced by eval.
11157 if (function_context->closure() == *function) {
11158 if (function_context->has_extension() &&
11159 !function_context->IsGlobalContext()) {
11160 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011161 bool threw = false;
11162 Handle<FixedArray> keys =
11163 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11164 if (threw) return Handle<JSObject>();
11165
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011166 for (int i = 0; i < keys->length(); i++) {
11167 // Names of variables introduced by eval are strings.
11168 ASSERT(keys->get(i)->IsString());
11169 Handle<String> key(String::cast(keys->get(i)));
11170 RETURN_IF_EMPTY_HANDLE_VALUE(
11171 isolate,
11172 SetProperty(local_scope,
11173 key,
11174 GetProperty(ext, key),
11175 NONE,
11176 kNonStrictMode),
11177 Handle<JSObject>());
11178 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011179 }
11180 }
11181 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011182
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011183 return local_scope;
11184}
11185
11186
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011187static Handle<JSObject> MaterializeLocalScope(
11188 Isolate* isolate,
11189 JavaScriptFrame* frame,
11190 int inlined_jsframe_index) {
11191 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
11192 return MaterializeLocalScopeWithFrameInspector(isolate,
11193 frame,
11194 &frame_inspector);
11195}
11196
11197
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011198// Create a plain JSObject which materializes the closure content for the
11199// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011200static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11201 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011202 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011203
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011204 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011205 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011206
ulan@chromium.org2efb9002012-01-19 15:36:35 +000011207 // Allocate and initialize a JSObject with all the content of this function
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011208 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011209 Handle<JSObject> closure_scope =
11210 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011211
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011212 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011213 if (!CopyContextLocalsToScopeObject(
11214 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011215 return Handle<JSObject>();
11216 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011217
11218 // Finally copy any properties from the function context extension. This will
11219 // be variables introduced by eval.
11220 if (context->has_extension()) {
11221 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011222 bool threw = false;
11223 Handle<FixedArray> keys =
11224 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11225 if (threw) return Handle<JSObject>();
11226
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011227 for (int i = 0; i < keys->length(); i++) {
11228 // Names of variables introduced by eval are strings.
11229 ASSERT(keys->get(i)->IsString());
11230 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011231 RETURN_IF_EMPTY_HANDLE_VALUE(
11232 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011233 SetProperty(closure_scope,
11234 key,
11235 GetProperty(ext, key),
11236 NONE,
11237 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011238 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011239 }
11240 }
11241
11242 return closure_scope;
11243}
11244
11245
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011246// Create a plain JSObject which materializes the scope for the specified
11247// catch context.
11248static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11249 Handle<Context> context) {
11250 ASSERT(context->IsCatchContext());
11251 Handle<String> name(String::cast(context->extension()));
11252 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11253 Handle<JSObject> catch_scope =
11254 isolate->factory()->NewJSObject(isolate->object_function());
11255 RETURN_IF_EMPTY_HANDLE_VALUE(
11256 isolate,
11257 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11258 Handle<JSObject>());
11259 return catch_scope;
11260}
11261
11262
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011263// Create a plain JSObject which materializes the block scope for the specified
11264// block context.
11265static Handle<JSObject> MaterializeBlockScope(
11266 Isolate* isolate,
11267 Handle<Context> context) {
11268 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011269 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011270
11271 // Allocate and initialize a JSObject with all the arguments, stack locals
11272 // heap locals and extension properties of the debugged function.
11273 Handle<JSObject> block_scope =
11274 isolate->factory()->NewJSObject(isolate->object_function());
11275
11276 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011277 if (!CopyContextLocalsToScopeObject(
11278 isolate, scope_info, context, block_scope)) {
11279 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011280 }
11281
11282 return block_scope;
11283}
11284
11285
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011286// Iterate over the actual scopes visible from a stack frame. The iteration
11287// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011288// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011289// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011290class ScopeIterator {
11291 public:
11292 enum ScopeType {
11293 ScopeTypeGlobal = 0,
11294 ScopeTypeLocal,
11295 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011296 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011297 ScopeTypeCatch,
11298 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011299 };
11300
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011301 ScopeIterator(Isolate* isolate,
11302 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011303 int inlined_jsframe_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011304 : isolate_(isolate),
11305 frame_(frame),
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011306 inlined_jsframe_index_(inlined_jsframe_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011307 function_(JSFunction::cast(frame->function())),
11308 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011309 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011310
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011311 // Catch the case when the debugger stops in an internal function.
11312 Handle<SharedFunctionInfo> shared_info(function_->shared());
11313 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11314 if (shared_info->script() == isolate->heap()->undefined_value()) {
11315 while (context_->closure() == *function_) {
11316 context_ = Handle<Context>(context_->previous(), isolate_);
11317 }
11318 return;
11319 }
11320
11321 // Get the debug info (create it if it does not exist).
11322 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11323 // Return if ensuring debug info failed.
11324 return;
11325 }
11326 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11327
11328 // Find the break point where execution has stopped.
11329 BreakLocationIterator break_location_iterator(debug_info,
11330 ALL_BREAK_LOCATIONS);
11331 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11332 if (break_location_iterator.IsExit()) {
11333 // We are within the return sequence. At the momemt it is not possible to
11334 // get a source position which is consistent with the current scope chain.
11335 // Thus all nested with, catch and block contexts are skipped and we only
11336 // provide the function scope.
11337 if (scope_info->HasContext()) {
11338 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11339 } else {
11340 while (context_->closure() == *function_) {
11341 context_ = Handle<Context>(context_->previous(), isolate_);
11342 }
11343 }
11344 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11345 } else {
11346 // Reparse the code and analyze the scopes.
11347 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11348 Handle<Script> script(Script::cast(shared_info->script()));
11349 Scope* scope = NULL;
11350
11351 // Check whether we are in global, eval or function code.
11352 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11353 if (scope_info->Type() != FUNCTION_SCOPE) {
11354 // Global or eval code.
11355 CompilationInfo info(script);
11356 if (scope_info->Type() == GLOBAL_SCOPE) {
11357 info.MarkAsGlobal();
11358 } else {
11359 ASSERT(scope_info->Type() == EVAL_SCOPE);
11360 info.MarkAsEval();
11361 info.SetCallingContext(Handle<Context>(function_->context()));
11362 }
11363 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11364 scope = info.function()->scope();
11365 }
11366 } else {
11367 // Function code
11368 CompilationInfo info(shared_info);
11369 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11370 scope = info.function()->scope();
11371 }
11372 }
11373
11374 // Retrieve the scope chain for the current position.
11375 if (scope != NULL) {
11376 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11377 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11378 } else {
11379 // A failed reparse indicates that the preparser has diverged from the
11380 // parser or that the preparse data given to the initial parse has been
11381 // faulty. We fail in debug mode but in release mode we only provide the
11382 // information we get from the context chain but nothing about
11383 // completely stack allocated scopes or stack allocated locals.
11384 UNREACHABLE();
11385 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011386 }
11387 }
11388
11389 // More scopes?
11390 bool Done() { return context_.is_null(); }
11391
11392 // Move to the next scope.
11393 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011394 ScopeType scope_type = Type();
11395 if (scope_type == ScopeTypeGlobal) {
11396 // The global scope is always the last in the chain.
11397 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011398 context_ = Handle<Context>();
11399 return;
11400 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011401 if (nested_scope_chain_.is_empty()) {
11402 context_ = Handle<Context>(context_->previous(), isolate_);
11403 } else {
11404 if (nested_scope_chain_.last()->HasContext()) {
11405 ASSERT(context_->previous() != NULL);
11406 context_ = Handle<Context>(context_->previous(), isolate_);
11407 }
11408 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011409 }
11410 }
11411
11412 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011413 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011414 if (!nested_scope_chain_.is_empty()) {
11415 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11416 switch (scope_info->Type()) {
11417 case FUNCTION_SCOPE:
11418 ASSERT(context_->IsFunctionContext() ||
11419 !scope_info->HasContext());
11420 return ScopeTypeLocal;
11421 case GLOBAL_SCOPE:
11422 ASSERT(context_->IsGlobalContext());
11423 return ScopeTypeGlobal;
11424 case WITH_SCOPE:
11425 ASSERT(context_->IsWithContext());
11426 return ScopeTypeWith;
11427 case CATCH_SCOPE:
11428 ASSERT(context_->IsCatchContext());
11429 return ScopeTypeCatch;
11430 case BLOCK_SCOPE:
11431 ASSERT(!scope_info->HasContext() ||
11432 context_->IsBlockContext());
11433 return ScopeTypeBlock;
11434 case EVAL_SCOPE:
11435 UNREACHABLE();
11436 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011437 }
11438 if (context_->IsGlobalContext()) {
11439 ASSERT(context_->global()->IsGlobalObject());
11440 return ScopeTypeGlobal;
11441 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011442 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011443 return ScopeTypeClosure;
11444 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011445 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011446 return ScopeTypeCatch;
11447 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011448 if (context_->IsBlockContext()) {
11449 return ScopeTypeBlock;
11450 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011451 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011452 return ScopeTypeWith;
11453 }
11454
11455 // Return the JavaScript object with the content of the current scope.
11456 Handle<JSObject> ScopeObject() {
11457 switch (Type()) {
11458 case ScopeIterator::ScopeTypeGlobal:
11459 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011460 case ScopeIterator::ScopeTypeLocal:
11461 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011462 ASSERT(nested_scope_chain_.length() == 1);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011463 return MaterializeLocalScope(isolate_, frame_, inlined_jsframe_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011464 case ScopeIterator::ScopeTypeWith:
11465 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011466 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11467 case ScopeIterator::ScopeTypeCatch:
11468 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011469 case ScopeIterator::ScopeTypeClosure:
11470 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011471 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011472 case ScopeIterator::ScopeTypeBlock:
11473 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011474 }
11475 UNREACHABLE();
11476 return Handle<JSObject>();
11477 }
11478
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011479 Handle<ScopeInfo> CurrentScopeInfo() {
11480 if (!nested_scope_chain_.is_empty()) {
11481 return nested_scope_chain_.last();
11482 } else if (context_->IsBlockContext()) {
11483 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11484 } else if (context_->IsFunctionContext()) {
11485 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11486 }
11487 return Handle<ScopeInfo>::null();
11488 }
11489
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011490 // Return the context for this scope. For the local context there might not
11491 // be an actual context.
11492 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011493 if (Type() == ScopeTypeGlobal ||
11494 nested_scope_chain_.is_empty()) {
11495 return context_;
11496 } else if (nested_scope_chain_.last()->HasContext()) {
11497 return context_;
11498 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011499 return Handle<Context>();
11500 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011501 }
11502
11503#ifdef DEBUG
11504 // Debug print of the content of the current scope.
11505 void DebugPrint() {
11506 switch (Type()) {
11507 case ScopeIterator::ScopeTypeGlobal:
11508 PrintF("Global:\n");
11509 CurrentContext()->Print();
11510 break;
11511
11512 case ScopeIterator::ScopeTypeLocal: {
11513 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011514 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011515 if (!CurrentContext().is_null()) {
11516 CurrentContext()->Print();
11517 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011518 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011519 if (extension->IsJSContextExtensionObject()) {
11520 extension->Print();
11521 }
11522 }
11523 }
11524 break;
11525 }
11526
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011527 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011528 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011529 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011530 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011531
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011532 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011533 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011534 CurrentContext()->extension()->Print();
11535 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011536 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011537
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011538 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011539 PrintF("Closure:\n");
11540 CurrentContext()->Print();
11541 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011542 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011543 if (extension->IsJSContextExtensionObject()) {
11544 extension->Print();
11545 }
11546 }
11547 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011548
11549 default:
11550 UNREACHABLE();
11551 }
11552 PrintF("\n");
11553 }
11554#endif
11555
11556 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011558 JavaScriptFrame* frame_;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011559 int inlined_jsframe_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011560 Handle<JSFunction> function_;
11561 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011562 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011563
11564 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11565};
11566
11567
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011568RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011570 ASSERT(args.length() == 2);
11571
11572 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011573 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011574 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11575 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011576 if (!maybe_check->ToObject(&check)) return maybe_check;
11577 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011578 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11579
11580 // Get the frame where the debugging is performed.
11581 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011582 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011583 JavaScriptFrame* frame = it.frame();
11584
11585 // Count the visible scopes.
11586 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011587 for (ScopeIterator it(isolate, frame, 0);
11588 !it.Done();
11589 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011590 n++;
11591 }
11592
11593 return Smi::FromInt(n);
11594}
11595
11596
11597static const int kScopeDetailsTypeIndex = 0;
11598static const int kScopeDetailsObjectIndex = 1;
11599static const int kScopeDetailsSize = 2;
11600
11601// Return an array with scope details
11602// args[0]: number: break id
11603// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011604// args[2]: number: inlined frame index
11605// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011606//
11607// The array returned contains the following information:
11608// 0: Scope type
11609// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011610RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011611 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011612 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011613
11614 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011615 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011616 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11617 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011618 if (!maybe_check->ToObject(&check)) return maybe_check;
11619 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011620 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011621 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011622 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011623
11624 // Get the frame where the debugging is performed.
11625 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011626 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011627 JavaScriptFrame* frame = frame_it.frame();
11628
11629 // Find the requested scope.
11630 int n = 0;
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000011631 ScopeIterator it(isolate, frame, inlined_jsframe_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011632 for (; !it.Done() && n < index; it.Next()) {
11633 n++;
11634 }
11635 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011637 }
11638
11639 // Calculate the size of the result.
11640 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011641 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011642
11643 // Fill in scope details.
11644 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011645 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011647 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011648
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011649 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011650}
11651
11652
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011653RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011654 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011655 ASSERT(args.length() == 0);
11656
11657#ifdef DEBUG
11658 // Print the scopes for the top frame.
11659 StackFrameLocator locator;
11660 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011661 for (ScopeIterator it(isolate, frame, 0);
11662 !it.Done();
11663 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011664 it.DebugPrint();
11665 }
11666#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011667 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011668}
11669
11670
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011671RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011672 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011673 ASSERT(args.length() == 1);
11674
11675 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011676 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011677 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11678 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011679 if (!maybe_result->ToObject(&result)) return maybe_result;
11680 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011681
11682 // Count all archived V8 threads.
11683 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011684 for (ThreadState* thread =
11685 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011686 thread != NULL;
11687 thread = thread->Next()) {
11688 n++;
11689 }
11690
11691 // Total number of threads is current thread and archived threads.
11692 return Smi::FromInt(n + 1);
11693}
11694
11695
11696static const int kThreadDetailsCurrentThreadIndex = 0;
11697static const int kThreadDetailsThreadIdIndex = 1;
11698static const int kThreadDetailsSize = 2;
11699
11700// Return an array with thread details
11701// args[0]: number: break id
11702// args[1]: number: thread index
11703//
11704// The array returned contains the following information:
11705// 0: Is current thread?
11706// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011707RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011708 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011709 ASSERT(args.length() == 2);
11710
11711 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011712 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011713 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11714 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011715 if (!maybe_check->ToObject(&check)) return maybe_check;
11716 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011717 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11718
11719 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011720 Handle<FixedArray> details =
11721 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011722
11723 // Thread index 0 is current thread.
11724 if (index == 0) {
11725 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011726 details->set(kThreadDetailsCurrentThreadIndex,
11727 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011728 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011729 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011730 } else {
11731 // Find the thread with the requested index.
11732 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011733 ThreadState* thread =
11734 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011735 while (index != n && thread != NULL) {
11736 thread = thread->Next();
11737 n++;
11738 }
11739 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011740 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011741 }
11742
11743 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011744 details->set(kThreadDetailsCurrentThreadIndex,
11745 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011746 details->set(kThreadDetailsThreadIdIndex,
11747 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011748 }
11749
11750 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011751 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011752}
11753
11754
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011755// Sets the disable break state
11756// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011757RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011758 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011759 ASSERT(args.length() == 1);
11760 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011761 isolate->debug()->set_disable_break(disable_break);
11762 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011763}
11764
11765
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011766RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011767 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011768 ASSERT(args.length() == 1);
11769
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011770 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11771 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011772 // Find the number of break points
11773 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011774 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011775 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011776 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011777 Handle<FixedArray>::cast(break_locations));
11778}
11779
11780
11781// Set a break point in a function
11782// args[0]: function
11783// args[1]: number: break source position (within the function source)
11784// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011785RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011786 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011787 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011788 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11789 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11791 RUNTIME_ASSERT(source_position >= 0);
11792 Handle<Object> break_point_object_arg = args.at<Object>(2);
11793
11794 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011795 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11796 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011797
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011798 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011799}
11800
11801
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011802Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11803 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011804 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011805 // Iterate the heap looking for SharedFunctionInfo generated from the
11806 // script. The inner most SharedFunctionInfo containing the source position
11807 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011808 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011809 // which is found is not compiled it is compiled and the heap is iterated
11810 // again as the compilation might create inner functions from the newly
11811 // compiled function and the actual requested break point might be in one of
11812 // these functions.
11813 bool done = false;
11814 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011815 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011816 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011818 { // Extra scope for iterator and no-allocation.
11819 isolate->heap()->EnsureHeapIsIterable();
11820 AssertNoAllocation no_alloc_during_heap_iteration;
11821 HeapIterator iterator;
11822 for (HeapObject* obj = iterator.next();
11823 obj != NULL; obj = iterator.next()) {
11824 if (obj->IsSharedFunctionInfo()) {
11825 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11826 if (shared->script() == *script) {
11827 // If the SharedFunctionInfo found has the requested script data and
11828 // contains the source position it is a candidate.
11829 int start_position = shared->function_token_position();
11830 if (start_position == RelocInfo::kNoPosition) {
11831 start_position = shared->start_position();
11832 }
11833 if (start_position <= position &&
11834 position <= shared->end_position()) {
11835 // If there is no candidate or this function is within the current
11836 // candidate this is the new candidate.
11837 if (target.is_null()) {
11838 target_start_position = start_position;
11839 target = shared;
11840 } else {
11841 if (target_start_position == start_position &&
11842 shared->end_position() == target->end_position()) {
11843 // If a top-level function contain only one function
11844 // declartion the source for the top-level and the
11845 // function is the same. In that case prefer the non
11846 // top-level function.
11847 if (!shared->is_toplevel()) {
11848 target_start_position = start_position;
11849 target = shared;
11850 }
11851 } else if (target_start_position <= start_position &&
11852 shared->end_position() <= target->end_position()) {
11853 // This containment check includes equality as a function
11854 // inside a top-level function can share either start or end
11855 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011856 target_start_position = start_position;
11857 target = shared;
11858 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011859 }
11860 }
11861 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011863 } // End for loop.
11864 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011865
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011866 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011867 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011868 }
11869
11870 // If the candidate found is compiled we are done. NOTE: when lazy
11871 // compilation of inner functions is introduced some additional checking
11872 // needs to be done here to compile inner functions.
11873 done = target->is_compiled();
11874 if (!done) {
11875 // If the candidate is not compiled compile it to reveal any inner
11876 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011877 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011878 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011879 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011880
11881 return *target;
11882}
11883
11884
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011885// Changes the state of a break point in a script and returns source position
11886// where break point was set. NOTE: Regarding performance see the NOTE for
11887// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011888// args[0]: script to set break point in
11889// args[1]: number: break source position (within the script source)
11890// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011891RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011892 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011893 ASSERT(args.length() == 3);
11894 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11895 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11896 RUNTIME_ASSERT(source_position >= 0);
11897 Handle<Object> break_point_object_arg = args.at<Object>(2);
11898
11899 // Get the script from the script wrapper.
11900 RUNTIME_ASSERT(wrapper->value()->IsScript());
11901 Handle<Script> script(Script::cast(wrapper->value()));
11902
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011903 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011904 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905 if (!result->IsUndefined()) {
11906 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11907 // Find position within function. The script position might be before the
11908 // source position of the first function.
11909 int position;
11910 if (shared->start_position() > source_position) {
11911 position = 0;
11912 } else {
11913 position = source_position - shared->start_position();
11914 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011915 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011916 position += shared->start_position();
11917 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011918 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011919 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011920}
11921
11922
11923// Clear a break point
11924// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011925RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011926 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011927 ASSERT(args.length() == 1);
11928 Handle<Object> break_point_object_arg = args.at<Object>(0);
11929
11930 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011931 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011932
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011933 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011934}
11935
11936
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011937// Change the state of break on exceptions.
11938// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11939// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011940RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011941 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011942 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011943 RUNTIME_ASSERT(args[0]->IsNumber());
11944 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011945
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011946 // If the number doesn't match an enum value, the ChangeBreakOnException
11947 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011948 ExceptionBreakType type =
11949 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011950 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011951 isolate->debug()->ChangeBreakOnException(type, enable);
11952 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011953}
11954
11955
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011956// Returns the state of break on exceptions
11957// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011958RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011959 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011960 ASSERT(args.length() == 1);
11961 RUNTIME_ASSERT(args[0]->IsNumber());
11962
11963 ExceptionBreakType type =
11964 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011965 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011966 return Smi::FromInt(result);
11967}
11968
11969
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011970// Prepare for stepping
11971// args[0]: break id for checking execution state
11972// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011973// args[2]: number of times to perform the step, for step out it is the number
11974// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011975RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011976 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011977 ASSERT(args.length() == 3);
11978 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011979 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011980 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11981 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011982 if (!maybe_check->ToObject(&check)) return maybe_check;
11983 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011984 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986 }
11987
11988 // Get the step action and check validity.
11989 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11990 if (step_action != StepIn &&
11991 step_action != StepNext &&
11992 step_action != StepOut &&
11993 step_action != StepInMin &&
11994 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011995 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996 }
11997
11998 // Get the number of steps.
11999 int step_count = NumberToInt32(args[2]);
12000 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012001 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012002 }
12003
ager@chromium.orga1645e22009-09-09 19:27:10 +000012004 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012005 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000012006
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012007 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012008 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
12009 step_count);
12010 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012011}
12012
12013
12014// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012015RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012016 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012017 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018 isolate->debug()->ClearStepping();
12019 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012020}
12021
12022
12023// Creates a copy of the with context chain. The copy of the context chain is
12024// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012025static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
12026 Handle<JSFunction> function,
12027 Handle<Context> base,
12028 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012029 int inlined_jsframe_index) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012030 HandleScope scope(isolate);
12031 List<Handle<ScopeInfo> > scope_chain;
12032 List<Handle<Context> > context_chain;
12033
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012034 ScopeIterator it(isolate, frame, inlined_jsframe_index);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012035 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
12036 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
12037 ASSERT(!it.Done());
12038 scope_chain.Add(it.CurrentScopeInfo());
12039 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012040 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012041
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012042 // At the end of the chain. Return the base context to link to.
12043 Handle<Context> context = base;
12044
12045 // Iteratively copy and or materialize the nested contexts.
12046 while (!scope_chain.is_empty()) {
12047 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
12048 Handle<Context> current = context_chain.RemoveLast();
12049 ASSERT(!(scope_info->HasContext() & current.is_null()));
12050
12051 if (scope_info->Type() == CATCH_SCOPE) {
12052 Handle<String> name(String::cast(current->extension()));
12053 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
12054 context =
12055 isolate->factory()->NewCatchContext(function,
12056 context,
12057 name,
12058 thrown_object);
12059 } else if (scope_info->Type() == BLOCK_SCOPE) {
12060 // Materialize the contents of the block scope into a JSObject.
12061 Handle<JSObject> block_scope_object =
12062 MaterializeBlockScope(isolate, current);
12063 if (block_scope_object.is_null()) {
12064 return Handle<Context>::null();
12065 }
12066 // Allocate a new function context for the debug evaluation and set the
12067 // extension object.
12068 Handle<Context> new_context =
12069 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12070 function);
12071 new_context->set_extension(*block_scope_object);
12072 new_context->set_previous(*context);
12073 context = new_context;
12074 } else {
12075 ASSERT(scope_info->Type() == WITH_SCOPE);
12076 ASSERT(current->IsWithContext());
12077 Handle<JSObject> extension(JSObject::cast(current->extension()));
12078 context =
12079 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000012080 }
erikcorry0ad885c2011-11-21 13:51:57 +000012081 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012082
12083 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012084}
12085
12086
12087// Helper function to find or create the arguments object for
12088// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012089static Handle<Object> GetArgumentsObject(Isolate* isolate,
12090 JavaScriptFrame* frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012091 FrameInspector* frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012092 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012093 Handle<Context> function_context) {
12094 // Try to find the value of 'arguments' to pass as parameter. If it is not
12095 // found (that is the debugged function does not reference 'arguments' and
12096 // does not support eval) then create an 'arguments' object.
12097 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012098 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012099 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012100 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012101 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012102 }
12103 }
12104
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012105 if (scope_info->HasHeapAllocatedLocals()) {
12106 VariableMode mode;
12107 InitializationFlag init_flag;
12108 index = scope_info->ContextSlotIndex(
12109 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012110 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012111 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012112 }
12113 }
12114
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012115 Handle<JSFunction> function(JSFunction::cast(frame_inspector->GetFunction()));
12116 int length = frame_inspector->GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012117 Handle<JSObject> arguments =
12118 isolate->factory()->NewArgumentsObject(function, length);
12119 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012120
12121 AssertNoAllocation no_gc;
12122 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012123 for (int i = 0; i < length; i++) {
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012124 array->set(i, frame_inspector->GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012125 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012126 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012127 return arguments;
12128}
12129
12130
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012131static const char kSourceStr[] =
12132 "(function(arguments,__source__){return eval(__source__);})";
12133
12134
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012135// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012136// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012137// extension part has all the parameters and locals of the function on the
12138// stack frame. A function which calls eval with the code to evaluate is then
12139// compiled in this context and called in this context. As this context
12140// replaces the context of the function on the stack frame a new (empty)
12141// function is created as well to be used as the closure for the context.
12142// This function and the context acts as replacements for the function on the
12143// stack frame presenting the same view of the values of parameters and
12144// local variables as if the piece of JavaScript was evaluated at the point
12145// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012146RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012147 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012148
12149 // Check the execution state and decode arguments frame and source to be
12150 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012151 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012152 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012153 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12154 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012155 if (!maybe_check_result->ToObject(&check_result)) {
12156 return maybe_check_result;
12157 }
12158 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012159 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012160 CONVERT_NUMBER_CHECKED(int, inlined_jsframe_index, Int32, args[2]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012161 CONVERT_ARG_CHECKED(String, source, 3);
12162 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12163 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012164
12165 // Handle the processing of break.
12166 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012167
12168 // Get the frame where the debugging is performed.
12169 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012170 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012171 JavaScriptFrame* frame = it.frame();
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012172 FrameInspector frame_inspector(frame, inlined_jsframe_index, isolate);
12173 Handle<JSFunction> function(JSFunction::cast(frame_inspector.GetFunction()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012174 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012175
12176 // Traverse the saved contexts chain to find the active context for the
12177 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012178 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12179
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012180 SaveContext savex(isolate);
12181 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012182
12183 // Create the (empty) function replacing the function on the stack frame for
12184 // the purpose of evaluating in the context created below. It is important
12185 // that this function does not describe any parameters and local variables
12186 // in the context. If it does then this will cause problems with the lookup
12187 // in Context::Lookup, where context slots for parameters and local variables
12188 // are looked at before the extension object.
12189 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012190 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12191 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012192 go_between->set_context(function->context());
12193#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012194 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12195 ASSERT(go_between_scope_info->ParameterCount() == 0);
12196 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012197#endif
12198
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012199 // Materialize the content of the local scope into a JSObject.
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012200 Handle<JSObject> local_scope = MaterializeLocalScopeWithFrameInspector(
12201 isolate, frame, &frame_inspector);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012202 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012203
12204 // Allocate a new context for the debug evaluation and set the extension
12205 // object build.
12206 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012207 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12208 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012209 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012210 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012211 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012212 Handle<Context> function_context;
12213 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012214 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012215 function_context = Handle<Context>(frame_context->declaration_context());
12216 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012217 context = CopyNestedScopeContextChain(isolate,
12218 go_between,
12219 context,
12220 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012221 inlined_jsframe_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012222
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012223 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012224 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012225 context =
12226 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012227 }
12228
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012229 // Wrap the evaluation statement in a new function compiled in the newly
12230 // created context. The function has one parameter which has to be called
12231 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012232 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012233 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012234
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012235 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012236 isolate->factory()->NewStringFromAscii(
12237 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012238
12239 // Currently, the eval code will be executed in non-strict mode,
12240 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012241 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012242 Compiler::CompileEval(function_source,
12243 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012244 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012245 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012246 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012247 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012248 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012249 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250
12251 // Invoke the result of the compilation to get the evaluation function.
12252 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012253 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012254 Handle<Object> evaluation_function =
12255 Execution::Call(compiled_function, receiver, 0, NULL,
12256 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012257 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012258
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012259 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012260 frame,
yangguo@chromium.org659ceec2012-01-26 07:37:54 +000012261 &frame_inspector,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012262 scope_info,
12263 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012264
12265 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012266 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012267 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012268 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12269 receiver,
12270 ARRAY_SIZE(argv),
12271 argv,
12272 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012273 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012274
12275 // Skip the global proxy as it has no properties and always delegates to the
12276 // real global object.
12277 if (result->IsJSGlobalProxy()) {
12278 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12279 }
12280
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012281 return *result;
12282}
12283
12284
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012285RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012286 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012287
12288 // Check the execution state and decode arguments frame and source to be
12289 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012290 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012291 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012292 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12293 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012294 if (!maybe_check_result->ToObject(&check_result)) {
12295 return maybe_check_result;
12296 }
12297 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012298 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012299 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012300 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012301
12302 // Handle the processing of break.
12303 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012304
12305 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012306 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012307 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012308 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012309 top = top->prev();
12310 }
12311 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012312 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012313 }
12314
12315 // Get the global context now set to the top context from before the
12316 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012317 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012318
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012319 bool is_global = true;
12320
12321 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012322 // Create a new with context with the additional context information between
12323 // the context of the debugged function and the eval code to be executed.
12324 context = isolate->factory()->NewWithContext(
12325 Handle<JSFunction>(context->closure()),
12326 context,
12327 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012328 is_global = false;
12329 }
12330
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012331 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012332 // Currently, the eval code will be executed in non-strict mode,
12333 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012334 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012335 Compiler::CompileEval(source,
12336 context,
12337 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012338 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012339 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012340 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012341 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012342 Handle<JSFunction>(
12343 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12344 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012345
12346 // Invoke the result of the compilation to get the evaluation function.
12347 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012348 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012349 Handle<Object> result =
12350 Execution::Call(compiled_function, receiver, 0, NULL,
12351 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012352 // Clear the oneshot breakpoints so that the debugger does not step further.
12353 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012354 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012355 return *result;
12356}
12357
12358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012359RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012360 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012361 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012362
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012363 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012364 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012365
12366 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012367 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012368 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12369 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12370 // because using
12371 // instances->set(i, *GetScriptWrapper(script))
12372 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
ulan@chromium.org2efb9002012-01-19 15:36:35 +000012373 // already have dereferenced the instances handle.
ager@chromium.org7c537e22008-10-16 08:43:32 +000012374 Handle<JSValue> wrapper = GetScriptWrapper(script);
12375 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012376 }
12377
12378 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012379 Handle<JSObject> result =
12380 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012381 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012382 return *result;
12383}
12384
12385
12386// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012387static int DebugReferencedBy(HeapIterator* iterator,
12388 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012389 Object* instance_filter, int max_references,
12390 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012391 JSFunction* arguments_function) {
12392 NoHandleAllocation ha;
12393 AssertNoAllocation no_alloc;
12394
12395 // Iterate the heap.
12396 int count = 0;
12397 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012398 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012399 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012400 (max_references == 0 || count < max_references)) {
12401 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012402 if (heap_obj->IsJSObject()) {
12403 // Skip context extension objects and argument arrays as these are
12404 // checked in the context of functions using them.
12405 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012406 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012407 obj->map()->constructor() == arguments_function) {
12408 continue;
12409 }
12410
12411 // Check if the JS object has a reference to the object looked for.
12412 if (obj->ReferencesObject(target)) {
12413 // Check instance filter if supplied. This is normally used to avoid
12414 // references from mirror objects (see Runtime_IsInPrototypeChain).
12415 if (!instance_filter->IsUndefined()) {
12416 Object* V = obj;
12417 while (true) {
12418 Object* prototype = V->GetPrototype();
12419 if (prototype->IsNull()) {
12420 break;
12421 }
12422 if (instance_filter == prototype) {
12423 obj = NULL; // Don't add this object.
12424 break;
12425 }
12426 V = prototype;
12427 }
12428 }
12429
12430 if (obj != NULL) {
12431 // Valid reference found add to instance array if supplied an update
12432 // count.
12433 if (instances != NULL && count < instances_size) {
12434 instances->set(count, obj);
12435 }
12436 last = obj;
12437 count++;
12438 }
12439 }
12440 }
12441 }
12442
12443 // Check for circular reference only. This can happen when the object is only
12444 // referenced from mirrors and has a circular reference in which case the
12445 // object is not really alive and would have been garbage collected if not
12446 // referenced from the mirror.
12447 if (count == 1 && last == target) {
12448 count = 0;
12449 }
12450
12451 // Return the number of referencing objects found.
12452 return count;
12453}
12454
12455
12456// Scan the heap for objects with direct references to an object
12457// args[0]: the object to find references to
12458// args[1]: constructor function for instances to exclude (Mirror)
12459// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012460RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012461 ASSERT(args.length() == 3);
12462
12463 // First perform a full GC in order to avoid references from dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012464 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12465 "%DebugReferencedBy");
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012466 // The heap iterator reserves the right to do a GC to make the heap iterable.
12467 // Due to the GC above we know it won't need to do that, but it seems cleaner
12468 // to get the heap iterator constructed before we start having unprotected
12469 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012470
12471 // Check parameters.
12472 CONVERT_CHECKED(JSObject, target, args[0]);
12473 Object* instance_filter = args[1];
12474 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12475 instance_filter->IsJSObject());
12476 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12477 RUNTIME_ASSERT(max_references >= 0);
12478
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012479
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012480 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012481 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012482 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012483 JSFunction* arguments_function =
12484 JSFunction::cast(arguments_boilerplate->map()->constructor());
12485
12486 // Get the number of referencing objects.
12487 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012488 HeapIterator heap_iterator;
12489 count = DebugReferencedBy(&heap_iterator,
12490 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012491 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012492
12493 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012494 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012495 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012496 if (!maybe_object->ToObject(&object)) return maybe_object;
12497 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012498 FixedArray* instances = FixedArray::cast(object);
12499
12500 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012501 // AllocateFixedArray above does not make the heap non-iterable.
12502 ASSERT(HEAP->IsHeapIterable());
12503 HeapIterator heap_iterator2;
12504 count = DebugReferencedBy(&heap_iterator2,
12505 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012506 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012507
12508 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012509 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012510 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012511 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012512 if (!maybe_result->ToObject(&result)) return maybe_result;
12513 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012514}
12515
12516
12517// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012518static int DebugConstructedBy(HeapIterator* iterator,
12519 JSFunction* constructor,
12520 int max_references,
12521 FixedArray* instances,
12522 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012523 AssertNoAllocation no_alloc;
12524
12525 // Iterate the heap.
12526 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012527 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012528 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012529 (max_references == 0 || count < max_references)) {
12530 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012531 if (heap_obj->IsJSObject()) {
12532 JSObject* obj = JSObject::cast(heap_obj);
12533 if (obj->map()->constructor() == constructor) {
12534 // Valid reference found add to instance array if supplied an update
12535 // count.
12536 if (instances != NULL && count < instances_size) {
12537 instances->set(count, obj);
12538 }
12539 count++;
12540 }
12541 }
12542 }
12543
12544 // Return the number of referencing objects found.
12545 return count;
12546}
12547
12548
12549// Scan the heap for objects constructed by a specific function.
12550// args[0]: the constructor to find instances of
12551// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012552RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012553 ASSERT(args.length() == 2);
12554
12555 // First perform a full GC in order to avoid dead objects.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012556 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask,
12557 "%DebugConstructedBy");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012558
12559 // Check parameters.
12560 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12561 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12562 RUNTIME_ASSERT(max_references >= 0);
12563
12564 // Get the number of referencing objects.
12565 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012566 HeapIterator heap_iterator;
12567 count = DebugConstructedBy(&heap_iterator,
12568 constructor,
12569 max_references,
12570 NULL,
12571 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012572
12573 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012574 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012575 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012576 if (!maybe_object->ToObject(&object)) return maybe_object;
12577 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012578 FixedArray* instances = FixedArray::cast(object);
12579
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012580 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012581 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012582 HeapIterator heap_iterator2;
12583 count = DebugConstructedBy(&heap_iterator2,
12584 constructor,
12585 max_references,
12586 instances,
12587 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012588
12589 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012590 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012591 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12592 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012593 if (!maybe_result->ToObject(&result)) return maybe_result;
12594 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012595 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012596}
12597
12598
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012599// Find the effective prototype object as returned by __proto__.
12600// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012601RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012602 ASSERT(args.length() == 1);
12603
12604 CONVERT_CHECKED(JSObject, obj, args[0]);
12605
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012606 // Use the __proto__ accessor.
12607 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012608}
12609
12610
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012611RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012612 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012613 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012614 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012615}
12616
12617
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012618RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012619#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012620 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012621 ASSERT(args.length() == 1);
12622 // Get the function and make sure it is compiled.
12623 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012624 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012625 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012626 return Failure::Exception();
12627 }
12628 func->code()->PrintLn();
12629#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012630 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012631}
ager@chromium.org9085a012009-05-11 19:22:57 +000012632
12633
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012634RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012635#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012636 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012637 ASSERT(args.length() == 1);
12638 // Get the function and make sure it is compiled.
12639 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012640 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012641 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012642 return Failure::Exception();
12643 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012644 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012645#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012646 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012647}
12648
12649
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012650RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012651 NoHandleAllocation ha;
12652 ASSERT(args.length() == 1);
12653
12654 CONVERT_CHECKED(JSFunction, f, args[0]);
12655 return f->shared()->inferred_name();
12656}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012657
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012658
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012659static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12660 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012661 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012662 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012663 int counter = 0;
12664 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012665 for (HeapObject* obj = iterator->next();
12666 obj != NULL;
12667 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012668 ASSERT(obj != NULL);
12669 if (!obj->IsSharedFunctionInfo()) {
12670 continue;
12671 }
12672 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12673 if (shared->script() != script) {
12674 continue;
12675 }
12676 if (counter < buffer_size) {
12677 buffer->set(counter, shared);
12678 }
12679 counter++;
12680 }
12681 return counter;
12682}
12683
12684// For a script finds all SharedFunctionInfo's in the heap that points
12685// to this script. Returns JSArray of SharedFunctionInfo wrapped
12686// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012687RUNTIME_FUNCTION(MaybeObject*,
12688 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012689 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012690 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012691 CONVERT_CHECKED(JSValue, script_value, args[0]);
12692
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012693
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012694 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12695
12696 const int kBufferSize = 32;
12697
12698 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012699 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012700 int number;
12701 {
12702 isolate->heap()->EnsureHeapIsIterable();
12703 AssertNoAllocation no_allocations;
12704 HeapIterator heap_iterator;
12705 Script* scr = *script;
12706 FixedArray* arr = *array;
12707 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12708 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012709 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012710 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012711 isolate->heap()->EnsureHeapIsIterable();
12712 AssertNoAllocation no_allocations;
12713 HeapIterator heap_iterator;
12714 Script* scr = *script;
12715 FixedArray* arr = *array;
12716 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012717 }
12718
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012719 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012720 result->set_length(Smi::FromInt(number));
12721
12722 LiveEdit::WrapSharedFunctionInfos(result);
12723
12724 return *result;
12725}
12726
12727// For a script calculates compilation information about all its functions.
12728// The script source is explicitly specified by the second argument.
12729// The source of the actual script is not used, however it is important that
12730// all generated code keeps references to this particular instance of script.
12731// Returns a JSArray of compilation infos. The array is ordered so that
12732// each function with all its descendant is always stored in a continues range
12733// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012734RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012735 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012736 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012737 CONVERT_CHECKED(JSValue, script, args[0]);
12738 CONVERT_ARG_CHECKED(String, source, 1);
12739 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12740
12741 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12742
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012743 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012744 return Failure::Exception();
12745 }
12746
12747 return result;
12748}
12749
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012750// Changes the source of the script to a new_source.
12751// If old_script_name is provided (i.e. is a String), also creates a copy of
12752// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012753RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012754 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012755 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012756 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12757 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012758 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012759
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012760 CONVERT_CHECKED(Script, original_script_pointer,
12761 original_script_value->value());
12762 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012763
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012764 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12765 new_source,
12766 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012767
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012768 if (old_script->IsScript()) {
12769 Handle<Script> script_handle(Script::cast(old_script));
12770 return *(GetScriptWrapper(script_handle));
12771 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012772 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012773 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012774}
12775
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012776
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012777RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012778 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012779 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012780 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12781 return LiveEdit::FunctionSourceUpdated(shared_info);
12782}
12783
12784
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012785// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012786RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012787 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012788 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012789 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12790 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12791
ager@chromium.orgac091b72010-05-05 07:34:42 +000012792 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012793}
12794
12795// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012796RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012797 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012798 HandleScope scope(isolate);
12799 Handle<Object> function_object(args[0], isolate);
12800 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012801
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012802 if (function_object->IsJSValue()) {
12803 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12804 if (script_object->IsJSValue()) {
12805 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012806 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012807 }
12808
12809 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12810 } else {
12811 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12812 // and we check it in this function.
12813 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012814
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012816}
12817
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012818
12819// In a code of a parent function replaces original function as embedded object
12820// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012821RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012822 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012823 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012824
12825 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12826 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12827 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12828
12829 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12830 subst_wrapper);
12831
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012832 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012833}
12834
12835
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012836// Updates positions of a shared function info (first parameter) according
12837// to script source change. Text change is described in second parameter as
12838// array of groups of 3 numbers:
12839// (change_begin, change_end, change_end_new_position).
12840// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012841RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012842 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012843 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012844 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12845 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12846
ager@chromium.orgac091b72010-05-05 07:34:42 +000012847 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012848}
12849
12850
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012851// For array of SharedFunctionInfo's (each wrapped in JSValue)
12852// checks that none of them have activations on stacks (of any thread).
12853// Returns array of the same length with corresponding results of
12854// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012855RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012856 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012857 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012858 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012859 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012860
ager@chromium.org357bf652010-04-12 11:30:10 +000012861 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012862}
12863
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012864// Compares 2 strings line-by-line, then token-wise and returns diff in form
12865// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12866// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012867RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012868 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012869 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012870 CONVERT_ARG_CHECKED(String, s1, 0);
12871 CONVERT_ARG_CHECKED(String, s2, 1);
12872
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012873 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012874}
12875
12876
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012877// A testing entry. Returns statement position which is the closest to
12878// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012879RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012880 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012881 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012882 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12883 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12884
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012885 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012886
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012887 if (code->kind() != Code::FUNCTION &&
12888 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012889 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012890 }
12891
12892 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012893 int closest_pc = 0;
12894 int distance = kMaxInt;
12895 while (!it.done()) {
12896 int statement_position = static_cast<int>(it.rinfo()->data());
12897 // Check if this break point is closer that what was previously found.
12898 if (source_position <= statement_position &&
12899 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012900 closest_pc =
12901 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012902 distance = statement_position - source_position;
12903 // Check whether we can't get any closer.
12904 if (distance == 0) break;
12905 }
12906 it.next();
12907 }
12908
12909 return Smi::FromInt(closest_pc);
12910}
12911
12912
ager@chromium.org357bf652010-04-12 11:30:10 +000012913// Calls specified function with or without entering the debugger.
12914// This is used in unit tests to run code as if debugger is entered or simply
12915// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012916RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012917 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012918 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012919 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12920 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12921
12922 Handle<Object> result;
12923 bool pending_exception;
12924 {
12925 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012926 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012927 &pending_exception);
12928 } else {
12929 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012930 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012931 &pending_exception);
12932 }
12933 }
12934 if (!pending_exception) {
12935 return *result;
12936 } else {
12937 return Failure::Exception();
12938 }
12939}
12940
12941
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012942// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012943RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012944 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012945 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012946 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12947 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012948 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012949}
12950
12951
12952// Performs a GC.
12953// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012954RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
rossberg@chromium.org994edf62012-02-06 10:12:55 +000012955 isolate->heap()->CollectAllGarbage(true, "%CollectGarbage");
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012956 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012957}
12958
12959
12960// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012961RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012962 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012963 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012964 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012965 }
12966 return Smi::FromInt(usage);
12967}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012968
12969
12970// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012971RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012972#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012973 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012974#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012975 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012976#endif
12977}
12978
12979
12980// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012981RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012982#ifdef LIVE_OBJECT_LIST
12983 return LiveObjectList::Capture();
12984#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012985 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012986#endif
12987}
12988
12989
12990// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012991RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012992#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012993 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012994 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012995 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012996#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012997 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012998#endif
12999}
13000
13001
13002// Generates the response to a debugger request for a dump of the objects
13003// contained in the difference between the captured live object lists
13004// specified by id1 and id2.
13005// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13006// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013007RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013008#ifdef LIVE_OBJECT_LIST
13009 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013010 CONVERT_SMI_ARG_CHECKED(id1, 0);
13011 CONVERT_SMI_ARG_CHECKED(id2, 1);
13012 CONVERT_SMI_ARG_CHECKED(start, 2);
13013 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013014 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
13015 EnterDebugger enter_debugger;
13016 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
13017#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013018 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013019#endif
13020}
13021
13022
13023// Gets the specified object as requested by the debugger.
13024// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013025RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013026#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013027 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013028 Object* result = LiveObjectList::GetObj(obj_id);
13029 return result;
13030#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013031 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013032#endif
13033}
13034
13035
13036// Gets the obj id for the specified address if valid.
13037// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013038RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013039#ifdef LIVE_OBJECT_LIST
13040 HandleScope scope;
13041 CONVERT_ARG_CHECKED(String, address, 0);
13042 Object* result = LiveObjectList::GetObjId(address);
13043 return result;
13044#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013045 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013046#endif
13047}
13048
13049
13050// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013051RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013052#ifdef LIVE_OBJECT_LIST
13053 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013054 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013055 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
13056 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
13057 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
13058 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
13059 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
13060
13061 Handle<JSObject> instance_filter;
13062 if (args[1]->IsJSObject()) {
13063 instance_filter = args.at<JSObject>(1);
13064 }
13065 bool verbose = false;
13066 if (args[2]->IsBoolean()) {
13067 verbose = args[2]->IsTrue();
13068 }
13069 int start = 0;
13070 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013071 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013072 }
13073 int limit = Smi::kMaxValue;
13074 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013075 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013076 }
13077
13078 return LiveObjectList::GetObjRetainers(obj_id,
13079 instance_filter,
13080 verbose,
13081 start,
13082 limit,
13083 filter_obj);
13084#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013085 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013086#endif
13087}
13088
13089
13090// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013091RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013092#ifdef LIVE_OBJECT_LIST
13093 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013094 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
13095 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013096 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
13097
13098 Handle<JSObject> instance_filter;
13099 if (args[2]->IsJSObject()) {
13100 instance_filter = args.at<JSObject>(2);
13101 }
13102
13103 Object* result =
13104 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
13105 return result;
13106#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013107 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013108#endif
13109}
13110
13111
13112// Generates the response to a debugger request for a list of all
13113// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013114RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013115#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013116 CONVERT_SMI_ARG_CHECKED(start, 0);
13117 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013118 return LiveObjectList::Info(start, count);
13119#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013120 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013121#endif
13122}
13123
13124
13125// Gets a dump of the specified object as requested by the debugger.
13126// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013127RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013128#ifdef LIVE_OBJECT_LIST
13129 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013130 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013131 Object* result = LiveObjectList::PrintObj(obj_id);
13132 return result;
13133#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013134 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013135#endif
13136}
13137
13138
13139// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013140RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013141#ifdef LIVE_OBJECT_LIST
13142 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013143 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013144#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013145 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013146#endif
13147}
13148
13149
13150// Generates the response to a debugger request for a summary of the types
13151// of objects in the difference between the captured live object lists
13152// specified by id1 and id2.
13153// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13154// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013155RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013156#ifdef LIVE_OBJECT_LIST
13157 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013158 CONVERT_SMI_ARG_CHECKED(id1, 0);
13159 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013160 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13161
13162 EnterDebugger enter_debugger;
13163 return LiveObjectList::Summarize(id1, id2, filter_obj);
13164#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013165 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013166#endif
13167}
13168
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013169#endif // ENABLE_DEBUGGER_SUPPORT
13170
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013172RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013173 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013174 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013175 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013176}
13177
13178
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013179RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013180 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013181 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013182 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013183}
13184
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013185
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013186// Finds the script object from the script data. NOTE: This operation uses
13187// heap traversal to find the function generated for the source position
13188// for the requested break point. For lazily compiled functions several heap
13189// traversals might be required rendering this operation as a rather slow
13190// operation. However for setting break points which is normally done through
13191// some kind of user interaction the performance is not crucial.
13192static Handle<Object> Runtime_GetScriptFromScriptName(
13193 Handle<String> script_name) {
13194 // Scan the heap for Script objects to find the script with the requested
13195 // script data.
13196 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013197 script_name->GetHeap()->EnsureHeapIsIterable();
13198 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013199 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013200 HeapObject* obj = NULL;
13201 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013202 // If a script is found check if it has the script data requested.
13203 if (obj->IsScript()) {
13204 if (Script::cast(obj)->name()->IsString()) {
13205 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13206 script = Handle<Script>(Script::cast(obj));
13207 }
13208 }
13209 }
13210 }
13211
13212 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013213 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013214
13215 // Return the script found.
13216 return GetScriptWrapper(script);
13217}
13218
13219
13220// Get the script object from script data. NOTE: Regarding performance
13221// see the NOTE for GetScriptFromScriptData.
13222// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013223RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013224 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013225
13226 ASSERT(args.length() == 1);
13227
13228 CONVERT_CHECKED(String, script_name, args[0]);
13229
13230 // Find the requested script.
13231 Handle<Object> result =
13232 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13233 return *result;
13234}
13235
13236
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013237// Determines whether the given stack frame should be displayed in
13238// a stack trace. The caller is the error constructor that asked
13239// for the stack trace to be collected. The first time a construct
13240// call to this function is encountered it is skipped. The seen_caller
13241// in/out parameter is used to remember if the caller has been seen
13242// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013243static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13244 Object* caller,
13245 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013246 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013247 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013248 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013249 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013250 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13251 Object* raw_fun = frame->function();
13252 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013253 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013254 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013255 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013256 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013257 *seen_caller = true;
13258 return false;
13259 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013260 // Skip all frames until we've seen the caller.
13261 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013262 // Also, skip non-visible built-in functions and any call with the builtins
13263 // object as receiver, so as to not reveal either the builtins object or
13264 // an internal function.
13265 // The --builtins-in-stack-traces command line flag allows including
13266 // internal call sites in the stack trace for debugging purposes.
13267 if (!FLAG_builtins_in_stack_traces) {
13268 JSFunction* fun = JSFunction::cast(raw_fun);
13269 if (frame->receiver()->IsJSBuiltinsObject() ||
13270 (fun->IsBuiltin() && !fun->shared()->native())) {
13271 return false;
13272 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013273 }
13274 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013275}
13276
13277
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013278// Collect the raw data for a stack trace. Returns an array of 4
13279// element segments each containing a receiver, function, code and
13280// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013281RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013282 ASSERT_EQ(args.length(), 3);
13283 CONVERT_ARG_CHECKED(JSObject, error_object, 0);
13284 Handle<Object> caller = args.at<Object>(1);
13285 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[2]);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013286
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013287 HandleScope scope(isolate);
13288 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013289
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013290 limit = Max(limit, 0); // Ensure that limit is not negative.
13291 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013292 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013293 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013294
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013295 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013296 // If the caller parameter is a function we skip frames until we're
13297 // under it before starting to collect.
13298 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013299 int cursor = 0;
13300 int frames_seen = 0;
13301 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013302 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013303 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013304 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013305 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013306 // Set initial size to the maximum inlining level + 1 for the outermost
13307 // function.
13308 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013309 frame->Summarize(&frames);
13310 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013311 if (cursor + 4 > elements->length()) {
13312 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13313 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013314 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013315 for (int i = 0; i < cursor; i++) {
13316 new_elements->set(i, elements->get(i));
13317 }
13318 elements = new_elements;
13319 }
13320 ASSERT(cursor + 4 <= elements->length());
13321
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013322 Handle<Object> recv = frames[i].receiver();
13323 Handle<JSFunction> fun = frames[i].function();
13324 Handle<Code> code = frames[i].code();
13325 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013326 elements->set(cursor++, *recv);
13327 elements->set(cursor++, *fun);
13328 elements->set(cursor++, *code);
13329 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013330 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013331 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013332 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013333 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013334 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
jkummerow@chromium.orgab7dad42012-02-07 12:07:34 +000013335 // Capture and attach a more detailed stack trace if necessary.
13336 isolate->CaptureAndSetCurrentStackTraceFor(error_object);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013337 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013338 return *result;
13339}
13340
13341
ager@chromium.org3811b432009-10-28 14:53:37 +000013342// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013343RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013344 ASSERT_EQ(args.length(), 0);
13345
13346 NoHandleAllocation ha;
13347
13348 const char* version_string = v8::V8::GetVersion();
13349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013350 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13351 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013352}
13353
13354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013355RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013356 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013357 OS::PrintError("abort: %s\n",
13358 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013359 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013360 OS::Abort();
13361 UNREACHABLE();
13362 return NULL;
13363}
13364
13365
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013366RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013367 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013368 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013369 Object* key = args[1];
13370
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013371 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013372 Object* o = cache->get(finger_index);
13373 if (o == key) {
13374 // The fastest case: hit the same place again.
13375 return cache->get(finger_index + 1);
13376 }
13377
13378 for (int i = finger_index - 2;
13379 i >= JSFunctionResultCache::kEntriesIndex;
13380 i -= 2) {
13381 o = cache->get(i);
13382 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013383 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013384 return cache->get(i + 1);
13385 }
13386 }
13387
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013388 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013389 ASSERT(size <= cache->length());
13390
13391 for (int i = size - 2; i > finger_index; i -= 2) {
13392 o = cache->get(i);
13393 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013394 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013395 return cache->get(i + 1);
13396 }
13397 }
13398
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013399 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013400 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013401
13402 Handle<JSFunctionResultCache> cache_handle(cache);
13403 Handle<Object> key_handle(key);
13404 Handle<Object> value;
13405 {
13406 Handle<JSFunction> factory(JSFunction::cast(
13407 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13408 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013409 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013410 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013411 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013412 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013413 value = Execution::Call(factory,
13414 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013415 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013416 argv,
13417 &pending_exception);
13418 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013419 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013420
13421#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013422 if (FLAG_verify_heap) {
13423 cache_handle->JSFunctionResultCacheVerify();
13424 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013425#endif
13426
13427 // Function invocation may have cleared the cache. Reread all the data.
13428 finger_index = cache_handle->finger_index();
13429 size = cache_handle->size();
13430
13431 // If we have spare room, put new data into it, otherwise evict post finger
13432 // entry which is likely to be the least recently used.
13433 int index = -1;
13434 if (size < cache_handle->length()) {
13435 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13436 index = size;
13437 } else {
13438 index = finger_index + JSFunctionResultCache::kEntrySize;
13439 if (index == cache_handle->length()) {
13440 index = JSFunctionResultCache::kEntriesIndex;
13441 }
13442 }
13443
13444 ASSERT(index % 2 == 0);
13445 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13446 ASSERT(index < cache_handle->length());
13447
13448 cache_handle->set(index, *key_handle);
13449 cache_handle->set(index + 1, *value);
13450 cache_handle->set_finger_index(index);
13451
13452#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013453 if (FLAG_verify_heap) {
13454 cache_handle->JSFunctionResultCacheVerify();
13455 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013456#endif
13457
13458 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013459}
13460
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013461
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013462RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013463 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013464 CONVERT_ARG_CHECKED(String, type, 0);
13465 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013466 return *isolate->factory()->NewJSMessageObject(
13467 type,
13468 arguments,
13469 0,
13470 0,
13471 isolate->factory()->undefined_value(),
13472 isolate->factory()->undefined_value(),
13473 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013474}
13475
13476
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013477RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013478 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13479 return message->type();
13480}
13481
13482
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013483RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013484 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13485 return message->arguments();
13486}
13487
13488
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013489RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013490 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13491 return Smi::FromInt(message->start_position());
13492}
13493
13494
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013495RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013496 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13497 return message->script();
13498}
13499
13500
kasper.lund44510672008-07-25 07:37:58 +000013501#ifdef DEBUG
13502// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13503// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013504RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013505 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013506 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013507#define COUNT_ENTRY(Name, argc, ressize) + 1
13508 int entry_count = 0
13509 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13510 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13511 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13512#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013513 Factory* factory = isolate->factory();
13514 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013515 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013516 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013517#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013518 { \
13519 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013520 Handle<String> name; \
13521 /* Inline runtime functions have an underscore in front of the name. */ \
13522 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013523 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013524 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13525 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013526 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013527 Vector<const char>(#Name, StrLength(#Name))); \
13528 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013529 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013530 pair_elements->set(0, *name); \
13531 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013532 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013533 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013534 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013535 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013536 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013537 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013538 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013539 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013540#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013541 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013542 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013543 return *result;
13544}
kasper.lund44510672008-07-25 07:37:58 +000013545#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013546
13547
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013548RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013549 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013550 CONVERT_CHECKED(String, format, args[0]);
13551 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013552 String::FlatContent format_content = format->GetFlatContent();
13553 RUNTIME_ASSERT(format_content.IsAscii());
13554 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013555 LOGGER->LogRuntime(chars, elms);
13556 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013557}
13558
13559
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013560RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013561 UNREACHABLE(); // implemented as macro in the parser
13562 return NULL;
13563}
13564
13565
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013566#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13567 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13568 CONVERT_CHECKED(JSObject, obj, args[0]); \
13569 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13570 }
13571
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013572ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013573ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13574ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13575ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13576ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13577ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13578ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13579ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13580ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13581ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13582ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13583ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13584ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13585ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13586
13587#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13588
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013589
13590RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13591 ASSERT(args.length() == 2);
13592 CONVERT_CHECKED(JSObject, obj1, args[0]);
13593 CONVERT_CHECKED(JSObject, obj2, args[1]);
13594 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13595}
13596
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013597// ----------------------------------------------------------------------------
13598// Implementation of Runtime
13599
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013600#define F(name, number_of_args, result_size) \
13601 { Runtime::k##name, Runtime::RUNTIME, #name, \
13602 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013603
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013604
13605#define I(name, number_of_args, result_size) \
13606 { Runtime::kInline##name, Runtime::INLINE, \
13607 "_" #name, NULL, number_of_args, result_size },
13608
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013609static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013610 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013611 INLINE_FUNCTION_LIST(I)
13612 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013613};
13614
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013615
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013616MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13617 Object* dictionary) {
13618 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013619 ASSERT(dictionary != NULL);
13620 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13621 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013622 Object* name_symbol;
13623 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013624 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013625 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13626 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013627 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013628 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13629 String::cast(name_symbol),
13630 Smi::FromInt(i),
13631 PropertyDetails(NONE, NORMAL));
13632 if (!maybe_dictionary->ToObject(&dictionary)) {
13633 // Non-recoverable failure. Calling code must restart heap
13634 // initialization.
13635 return maybe_dictionary;
13636 }
13637 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013638 }
13639 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013640}
13641
13642
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013643const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13644 Heap* heap = name->GetHeap();
13645 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013646 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013647 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013648 int function_index = Smi::cast(smi_index)->value();
13649 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013650 }
13651 return NULL;
13652}
13653
13654
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013655const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013656 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13657}
13658
13659
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013660void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013661 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013662 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013663 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013664 if (isolate->heap()->new_space()->AddFreshPage()) {
13665 return;
13666 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013667 // Try to do a garbage collection; ignore it if it fails. The C
13668 // entry stub will throw an out-of-memory exception in that case.
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013669 isolate->heap()->CollectGarbage(failure->allocation_space(),
13670 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013671 } else {
13672 // Handle last resort GC and make sure to allow future allocations
13673 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013674 isolate->counters()->gc_last_resort_from_js()->Increment();
rossberg@chromium.org994edf62012-02-06 10:12:55 +000013675 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
13676 "Runtime::PerformGC");
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013677 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013678}
13679
13680
13681} } // namespace v8::internal