blob: fb3621341abb48e5bc35abb230891f9ea3061b89 [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 =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000168 heap->AllocateFixedArray(copy->NumberOfLocalProperties(NONE));
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;
ager@chromium.org236ad962008-09-25 09:45:57 +0000276 if (FLAG_canonicalize_object_literal_maps) {
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000277 // Check that there are only symbols and array indices among keys.
ager@chromium.org236ad962008-09-25 09:45:57 +0000278 int number_of_symbol_keys = 0;
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000279 for (int p = 0; p != properties_length; p += 2) {
280 Object* key = constant_properties->get(p);
281 uint32_t element_index = 0;
282 if (key->IsSymbol()) {
283 number_of_symbol_keys++;
284 } else if (key->ToArrayIndex(&element_index)) {
285 // An index key does not require space in the property backing store.
286 number_of_properties--;
287 } else {
288 // Bail out as a non-symbol non-index key makes caching impossible.
289 // ASSERT to make sure that the if condition after the loop is false.
290 ASSERT(number_of_symbol_keys != number_of_properties);
291 break;
292 }
ager@chromium.org236ad962008-09-25 09:45:57 +0000293 }
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000294 // If we only have symbols and array indices among keys then we can
295 // use the map cache in the global context.
ager@chromium.org236ad962008-09-25 09:45:57 +0000296 const int kMaxKeys = 10;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000297 if ((number_of_symbol_keys == number_of_properties) &&
298 (number_of_symbol_keys < kMaxKeys)) {
ager@chromium.org236ad962008-09-25 09:45:57 +0000299 // Create the fixed array with the key.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000300 Handle<FixedArray> keys =
301 isolate->factory()->NewFixedArray(number_of_symbol_keys);
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +0000302 if (number_of_symbol_keys > 0) {
303 int index = 0;
304 for (int p = 0; p < properties_length; p += 2) {
305 Object* key = constant_properties->get(p);
306 if (key->IsSymbol()) {
307 keys->set(index++, key);
308 }
309 }
310 ASSERT(index == number_of_symbol_keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000311 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000312 *is_result_from_cache = true;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000313 return isolate->factory()->ObjectLiteralMapFromCache(context, keys);
ager@chromium.org236ad962008-09-25 09:45:57 +0000314 }
315 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +0000316 *is_result_from_cache = false;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000317 return isolate->factory()->CopyMap(
ager@chromium.org32912102009-01-16 10:38:43 +0000318 Handle<Map>(context->object_function()->initial_map()),
319 number_of_properties);
ager@chromium.org236ad962008-09-25 09:45:57 +0000320}
321
322
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000323static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000324 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000325 Handle<FixedArray> literals,
326 Handle<FixedArray> constant_properties);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000327
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000328
329static Handle<Object> CreateObjectLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000330 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000331 Handle<FixedArray> literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000332 Handle<FixedArray> constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000333 bool should_have_fast_elements,
334 bool has_function_literal) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +0000335 // Get the global context from the literals array. This is the
336 // context in which the function was created and we use the object
337 // function from this context to create the object literal. We do
338 // not use the object function from the current global context
339 // because this might be the object function from another context
340 // which we should not have access to.
ager@chromium.org236ad962008-09-25 09:45:57 +0000341 Handle<Context> context =
342 Handle<Context>(JSFunction::GlobalContextFromLiterals(*literals));
343
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000344 // In case we have function literals, we want the object to be in
345 // slow properties mode for now. We don't go in the map cache because
346 // maps with constant functions can't be shared if the functions are
347 // not the same (which is the common case).
348 bool is_result_from_cache = false;
349 Handle<Map> map = has_function_literal
350 ? Handle<Map>(context->object_function()->initial_map())
351 : ComputeObjectLiteralMap(context,
352 constant_properties,
353 &is_result_from_cache);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000354
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000355 Handle<JSObject> boilerplate = isolate->factory()->NewJSObjectFromMap(map);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000356
357 // Normalize the elements of the boilerplate to save space if needed.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000358 if (!should_have_fast_elements) JSObject::NormalizeElements(boilerplate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000359
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000360 // Add the constant properties to the boilerplate.
361 int length = constant_properties->length();
362 bool should_transform =
363 !is_result_from_cache && boilerplate->HasFastProperties();
364 if (should_transform || has_function_literal) {
365 // Normalize the properties of object to avoid n^2 behavior
366 // when extending the object multiple properties. Indicate the number of
367 // properties to be added.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000368 JSObject::NormalizeProperties(
369 boilerplate, KEEP_INOBJECT_PROPERTIES, length / 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000370 }
371
372 for (int index = 0; index < length; index +=2) {
373 Handle<Object> key(constant_properties->get(index+0), isolate);
374 Handle<Object> value(constant_properties->get(index+1), isolate);
375 if (value->IsFixedArray()) {
376 // The value contains the constant_properties of a
377 // simple object or array literal.
378 Handle<FixedArray> array = Handle<FixedArray>::cast(value);
379 value = CreateLiteralBoilerplate(isolate, literals, array);
380 if (value.is_null()) return value;
381 }
382 Handle<Object> result;
383 uint32_t element_index = 0;
384 if (key->IsSymbol()) {
385 if (Handle<String>::cast(key)->AsArrayIndex(&element_index)) {
386 // Array index as string (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000387 result = JSObject::SetOwnElement(
388 boilerplate, element_index, value, kNonStrictMode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000389 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000390 Handle<String> name(String::cast(*key));
391 ASSERT(!name->AsArrayIndex(&element_index));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000392 result = JSObject::SetLocalPropertyIgnoreAttributes(
393 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000394 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000395 } else if (key->ToArrayIndex(&element_index)) {
396 // Array index (uint32).
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000397 result = JSObject::SetOwnElement(
398 boilerplate, element_index, value, kNonStrictMode);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000399 } else {
400 // Non-uint32 number.
401 ASSERT(key->IsNumber());
402 double num = key->Number();
403 char arr[100];
404 Vector<char> buffer(arr, ARRAY_SIZE(arr));
405 const char* str = DoubleToCString(num, buffer);
406 Handle<String> name =
407 isolate->factory()->NewStringFromAscii(CStrVector(str));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000408 result = JSObject::SetLocalPropertyIgnoreAttributes(
409 boilerplate, name, value, NONE);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000410 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000411 // If setting the property on the boilerplate throws an
412 // exception, the exception is converted to an empty handle in
413 // the handle based operations. In that case, we need to
414 // convert back to an exception.
415 if (result.is_null()) return result;
416 }
417
418 // Transform to fast properties if necessary. For object literals with
419 // containing function literals we defer this operation until after all
420 // computed properties have been assigned so that we can generate
421 // constant function properties.
422 if (should_transform && !has_function_literal) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +0000423 JSObject::TransformToFastProperties(
424 boilerplate, boilerplate->map()->unused_property_fields());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000425 }
426
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000427 return boilerplate;
kasperl@chromium.org7be3c992009-03-12 07:19:55 +0000428}
429
430
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000431static const int kSmiOnlyLiteralMinimumLength = 1024;
432
433
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000434Handle<Object> Runtime::CreateArrayLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000435 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000436 Handle<FixedArray> literals,
437 Handle<FixedArray> elements) {
438 // Create the JSArray.
439 Handle<JSFunction> constructor(
440 JSFunction::GlobalContextFromLiterals(*literals)->array_function());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000441 Handle<JSArray> object =
442 Handle<JSArray>::cast(isolate->factory()->NewJSObject(constructor));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000443
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000444 ElementsKind constant_elements_kind =
445 static_cast<ElementsKind>(Smi::cast(elements->get(0))->value());
446 Handle<FixedArrayBase> constant_elements_values(
447 FixedArrayBase::cast(elements->get(1)));
448
449 ASSERT(FLAG_smi_only_arrays || constant_elements_kind == FAST_ELEMENTS ||
450 constant_elements_kind == FAST_SMI_ONLY_ELEMENTS);
451 bool allow_literal_kind_transition = FLAG_smi_only_arrays &&
452 constant_elements_kind > object->GetElementsKind();
453
454 if (!FLAG_smi_only_arrays &&
455 constant_elements_values->length() > kSmiOnlyLiteralMinimumLength &&
456 constant_elements_kind != object->GetElementsKind()) {
457 allow_literal_kind_transition = true;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +0000458 }
459
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000460 // If the ElementsKind of the constant values of the array literal are less
461 // specific than the ElementsKind of the boilerplate array object, change the
462 // boilerplate array object's map to reflect that kind.
463 if (allow_literal_kind_transition) {
464 Handle<Map> transitioned_array_map =
465 isolate->factory()->GetElementsTransitionMap(object,
466 constant_elements_kind);
467 object->set_map(*transitioned_array_map);
468 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000469
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000470 Handle<FixedArrayBase> copied_elements_values;
471 if (constant_elements_kind == FAST_DOUBLE_ELEMENTS) {
472 ASSERT(FLAG_smi_only_arrays);
473 copied_elements_values = isolate->factory()->CopyFixedDoubleArray(
474 Handle<FixedDoubleArray>::cast(constant_elements_values));
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000475 } else {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000476 ASSERT(constant_elements_kind == FAST_SMI_ONLY_ELEMENTS ||
477 constant_elements_kind == FAST_ELEMENTS);
478 const bool is_cow =
479 (constant_elements_values->map() ==
480 isolate->heap()->fixed_cow_array_map());
481 if (is_cow) {
482 copied_elements_values = constant_elements_values;
483#if DEBUG
484 Handle<FixedArray> fixed_array_values =
485 Handle<FixedArray>::cast(copied_elements_values);
486 for (int i = 0; i < fixed_array_values->length(); i++) {
487 ASSERT(!fixed_array_values->get(i)->IsFixedArray());
488 }
489#endif
490 } else {
491 Handle<FixedArray> fixed_array_values =
492 Handle<FixedArray>::cast(constant_elements_values);
493 Handle<FixedArray> fixed_array_values_copy =
494 isolate->factory()->CopyFixedArray(fixed_array_values);
495 copied_elements_values = fixed_array_values_copy;
496 for (int i = 0; i < fixed_array_values->length(); i++) {
497 Object* current = fixed_array_values->get(i);
498 if (current->IsFixedArray()) {
499 // The value contains the constant_properties of a
500 // simple object or array literal.
501 Handle<FixedArray> fa(FixedArray::cast(fixed_array_values->get(i)));
502 Handle<Object> result =
503 CreateLiteralBoilerplate(isolate, literals, fa);
504 if (result.is_null()) return result;
505 fixed_array_values_copy->set(i, *result);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000506 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000507 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000508 }
509 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000510 object->set_elements(*copied_elements_values);
511 object->set_length(Smi::FromInt(copied_elements_values->length()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000512 return object;
513}
514
515
516static Handle<Object> CreateLiteralBoilerplate(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000517 Isolate* isolate,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000518 Handle<FixedArray> literals,
519 Handle<FixedArray> array) {
520 Handle<FixedArray> elements = CompileTimeValue::GetElements(array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000521 const bool kHasNoFunctionLiteral = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000522 switch (CompileTimeValue::GetType(array)) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000523 case CompileTimeValue::OBJECT_LITERAL_FAST_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000524 return CreateObjectLiteralBoilerplate(isolate,
525 literals,
526 elements,
527 true,
528 kHasNoFunctionLiteral);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000529 case CompileTimeValue::OBJECT_LITERAL_SLOW_ELEMENTS:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000530 return CreateObjectLiteralBoilerplate(isolate,
531 literals,
532 elements,
533 false,
534 kHasNoFunctionLiteral);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000535 case CompileTimeValue::ARRAY_LITERAL:
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000536 return Runtime::CreateArrayLiteralBoilerplate(
537 isolate, literals, elements);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +0000538 default:
539 UNREACHABLE();
540 return Handle<Object>::null();
541 }
542}
543
544
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000545RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000546 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000547 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000548 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000549 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000550 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000551 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000552 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
553 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000554
555 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000556 Handle<Object> boilerplate(literals->get(literals_index), isolate);
557 if (*boilerplate == isolate->heap()->undefined_value()) {
558 boilerplate = CreateObjectLiteralBoilerplate(isolate,
559 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000560 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000561 should_have_fast_elements,
562 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000563 if (boilerplate.is_null()) return Failure::Exception();
564 // Update the functions literal and return the boilerplate.
565 literals->set(literals_index, *boilerplate);
566 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000567 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000568}
569
570
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000571RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateObjectLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000572 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000573 ASSERT(args.length() == 4);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000574 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000575 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000576 CONVERT_ARG_CHECKED(FixedArray, constant_properties, 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000577 CONVERT_SMI_ARG_CHECKED(flags, 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000578 bool should_have_fast_elements = (flags & ObjectLiteral::kFastElements) != 0;
579 bool has_function_literal = (flags & ObjectLiteral::kHasFunction) != 0;
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000580
581 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000582 Handle<Object> boilerplate(literals->get(literals_index), isolate);
583 if (*boilerplate == isolate->heap()->undefined_value()) {
584 boilerplate = CreateObjectLiteralBoilerplate(isolate,
585 literals,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +0000586 constant_properties,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000587 should_have_fast_elements,
588 has_function_literal);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000589 if (boilerplate.is_null()) return Failure::Exception();
590 // Update the functions literal and return the boilerplate.
591 literals->set(literals_index, *boilerplate);
592 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000593 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000594}
595
596
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000597RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000598 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000599 ASSERT(args.length() == 3);
600 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000601 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000602 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
603
604 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000605 Handle<Object> boilerplate(literals->get(literals_index), isolate);
606 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000607 boilerplate =
608 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000609 if (boilerplate.is_null()) return Failure::Exception();
610 // Update the functions literal and return the boilerplate.
611 literals->set(literals_index, *boilerplate);
612 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000613 return DeepCopyBoilerplate(isolate, JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000614}
615
616
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000617RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateArrayLiteralShallow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000618 HandleScope scope(isolate);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000619 ASSERT(args.length() == 3);
620 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +0000621 CONVERT_SMI_ARG_CHECKED(literals_index, 1);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000622 CONVERT_ARG_CHECKED(FixedArray, elements, 2);
623
624 // Check if boilerplate exists. If not, create it first.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000625 Handle<Object> boilerplate(literals->get(literals_index), isolate);
626 if (*boilerplate == isolate->heap()->undefined_value()) {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +0000627 ASSERT(*elements != isolate->heap()->empty_fixed_array());
ricow@chromium.org7ad65222011-12-19 12:13:11 +0000628 boilerplate =
629 Runtime::CreateArrayLiteralBoilerplate(isolate, literals, elements);
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000630 if (boilerplate.is_null()) return Failure::Exception();
631 // Update the functions literal and return the boilerplate.
632 literals->set(literals_index, *boilerplate);
633 }
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000634 if (JSObject::cast(*boilerplate)->elements()->map() ==
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000635 isolate->heap()->fixed_cow_array_map()) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +0000636 isolate->counters()->cow_arrays_created_runtime()->Increment();
ricow@chromium.org0b9f8502010-08-18 07:45:01 +0000637 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000638 return isolate->heap()->CopyJSObject(JSObject::cast(*boilerplate));
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +0000639}
640
641
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000642RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSProxy) {
643 ASSERT(args.length() == 2);
644 Object* handler = args[0];
645 Object* prototype = args[1];
646 Object* used_prototype =
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000647 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +0000648 return isolate->heap()->AllocateJSProxy(handler, used_prototype);
649}
650
651
lrn@chromium.org34e60782011-09-15 07:25:40 +0000652RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateJSFunctionProxy) {
653 ASSERT(args.length() == 4);
654 Object* handler = args[0];
655 Object* call_trap = args[1];
656 Object* construct_trap = args[2];
657 Object* prototype = args[3];
658 Object* used_prototype =
659 prototype->IsJSReceiver() ? prototype : isolate->heap()->null_value();
660 return isolate->heap()->AllocateJSFunctionProxy(
661 handler, call_trap, construct_trap, used_prototype);
662}
663
664
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000665RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSProxy) {
666 ASSERT(args.length() == 1);
667 Object* obj = args[0];
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000668 return isolate->heap()->ToBoolean(obj->IsJSProxy());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000669}
670
671
lrn@chromium.org34e60782011-09-15 07:25:40 +0000672RUNTIME_FUNCTION(MaybeObject*, Runtime_IsJSFunctionProxy) {
673 ASSERT(args.length() == 1);
674 Object* obj = args[0];
675 return isolate->heap()->ToBoolean(obj->IsJSFunctionProxy());
676}
677
678
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000679RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHandler) {
680 ASSERT(args.length() == 1);
681 CONVERT_CHECKED(JSProxy, proxy, args[0]);
682 return proxy->handler();
683}
684
685
lrn@chromium.org34e60782011-09-15 07:25:40 +0000686RUNTIME_FUNCTION(MaybeObject*, Runtime_GetCallTrap) {
687 ASSERT(args.length() == 1);
688 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
689 return proxy->call_trap();
690}
691
692
693RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructTrap) {
694 ASSERT(args.length() == 1);
695 CONVERT_CHECKED(JSFunctionProxy, proxy, args[0]);
696 return proxy->construct_trap();
697}
698
699
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000700RUNTIME_FUNCTION(MaybeObject*, Runtime_Fix) {
701 ASSERT(args.length() == 1);
702 CONVERT_CHECKED(JSProxy, proxy, args[0]);
703 proxy->Fix();
ricow@chromium.org9fa09672011-07-25 11:05:35 +0000704 return isolate->heap()->undefined_value();
rossberg@chromium.org717967f2011-07-20 13:44:42 +0000705}
706
707
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000708RUNTIME_FUNCTION(MaybeObject*, Runtime_SetInitialize) {
709 HandleScope scope(isolate);
710 ASSERT(args.length() == 1);
711 CONVERT_ARG_CHECKED(JSSet, holder, 0);
712 Handle<ObjectHashSet> table = isolate->factory()->NewObjectHashSet(0);
713 holder->set_table(*table);
714 return *holder;
715}
716
717
718RUNTIME_FUNCTION(MaybeObject*, Runtime_SetAdd) {
719 HandleScope scope(isolate);
720 ASSERT(args.length() == 2);
721 CONVERT_ARG_CHECKED(JSSet, holder, 0);
722 Handle<Object> key(args[1]);
723 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
724 table = ObjectHashSetAdd(table, key);
725 holder->set_table(*table);
726 return isolate->heap()->undefined_symbol();
727}
728
729
730RUNTIME_FUNCTION(MaybeObject*, Runtime_SetHas) {
731 HandleScope scope(isolate);
732 ASSERT(args.length() == 2);
733 CONVERT_ARG_CHECKED(JSSet, holder, 0);
734 Handle<Object> key(args[1]);
735 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
736 return isolate->heap()->ToBoolean(table->Contains(*key));
737}
738
739
740RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDelete) {
741 HandleScope scope(isolate);
742 ASSERT(args.length() == 2);
743 CONVERT_ARG_CHECKED(JSSet, holder, 0);
744 Handle<Object> key(args[1]);
745 Handle<ObjectHashSet> table(ObjectHashSet::cast(holder->table()));
746 table = ObjectHashSetRemove(table, key);
747 holder->set_table(*table);
748 return isolate->heap()->undefined_symbol();
749}
750
751
752RUNTIME_FUNCTION(MaybeObject*, Runtime_MapInitialize) {
753 HandleScope scope(isolate);
754 ASSERT(args.length() == 1);
755 CONVERT_ARG_CHECKED(JSMap, holder, 0);
756 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
757 holder->set_table(*table);
758 return *holder;
759}
760
761
762RUNTIME_FUNCTION(MaybeObject*, Runtime_MapGet) {
763 HandleScope scope(isolate);
764 ASSERT(args.length() == 2);
765 CONVERT_ARG_CHECKED(JSMap, holder, 0);
766 Handle<Object> key(args[1]);
767 return ObjectHashTable::cast(holder->table())->Lookup(*key);
768}
769
770
771RUNTIME_FUNCTION(MaybeObject*, Runtime_MapSet) {
772 HandleScope scope(isolate);
773 ASSERT(args.length() == 3);
774 CONVERT_ARG_CHECKED(JSMap, holder, 0);
775 Handle<Object> key(args[1]);
776 Handle<Object> value(args[2]);
777 Handle<ObjectHashTable> table(ObjectHashTable::cast(holder->table()));
778 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
779 holder->set_table(*new_table);
780 return *value;
781}
782
783
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000784RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapInitialize) {
785 HandleScope scope(isolate);
786 ASSERT(args.length() == 1);
787 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
788 ASSERT(weakmap->map()->inobject_properties() == 0);
789 Handle<ObjectHashTable> table = isolate->factory()->NewObjectHashTable(0);
790 weakmap->set_table(*table);
791 weakmap->set_next(Smi::FromInt(0));
792 return *weakmap;
793}
794
795
796RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapGet) {
797 NoHandleAllocation ha;
798 ASSERT(args.length() == 2);
799 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000800 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
801 return ObjectHashTable::cast(weakmap->table())->Lookup(*key);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000802}
803
804
805RUNTIME_FUNCTION(MaybeObject*, Runtime_WeakMapSet) {
806 HandleScope scope(isolate);
807 ASSERT(args.length() == 3);
808 CONVERT_ARG_CHECKED(JSWeakMap, weakmap, 0);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000809 CONVERT_ARG_CHECKED(JSReceiver, key, 1);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000810 Handle<Object> value(args[2]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +0000811 Handle<ObjectHashTable> table(ObjectHashTable::cast(weakmap->table()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +0000812 Handle<ObjectHashTable> new_table = PutIntoObjectHashTable(table, key, value);
813 weakmap->set_table(*new_table);
814 return *value;
815}
816
817
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000818RUNTIME_FUNCTION(MaybeObject*, Runtime_ClassOf) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000819 NoHandleAllocation ha;
820 ASSERT(args.length() == 1);
821 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000822 if (!obj->IsJSObject()) return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000823 return JSObject::cast(obj)->class_name();
824}
825
ager@chromium.org7c537e22008-10-16 08:43:32 +0000826
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000827RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPrototype) {
828 NoHandleAllocation ha;
829 ASSERT(args.length() == 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000830 CONVERT_CHECKED(JSReceiver, input_obj, args[0]);
831 Object* obj = input_obj;
832 // We don't expect access checks to be needed on JSProxy objects.
833 ASSERT(!obj->IsAccessCheckNeeded() || obj->IsJSObject());
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000834 do {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +0000835 if (obj->IsAccessCheckNeeded() &&
836 !isolate->MayNamedAccess(JSObject::cast(obj),
837 isolate->heap()->Proto_symbol(),
838 v8::ACCESS_GET)) {
839 isolate->ReportFailedAccessCheck(JSObject::cast(obj), v8::ACCESS_GET);
840 return isolate->heap()->undefined_value();
841 }
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000842 obj = obj->GetPrototype();
sgjesse@chromium.org6db88712011-07-11 11:41:22 +0000843 } while (obj->IsJSObject() &&
844 JSObject::cast(obj)->map()->is_hidden_prototype());
erik.corry@gmail.comd6076d92011-06-06 09:39:18 +0000845 return obj;
846}
847
848
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000849RUNTIME_FUNCTION(MaybeObject*, Runtime_IsInPrototypeChain) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000850 NoHandleAllocation ha;
851 ASSERT(args.length() == 2);
852 // See ECMA-262, section 15.3.5.3, page 88 (steps 5 - 8).
853 Object* O = args[0];
854 Object* V = args[1];
855 while (true) {
856 Object* prototype = V->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000857 if (prototype->IsNull()) return isolate->heap()->false_value();
858 if (O == prototype) return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000859 V = prototype;
860 }
861}
862
863
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000864RUNTIME_FUNCTION(MaybeObject*, Runtime_IsConstructCall) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000865 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +0000866 ASSERT(args.length() == 0);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +0000867 JavaScriptFrameIterator it(isolate);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000868 return isolate->heap()->ToBoolean(it.frame()->IsConstructor());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +0000869}
870
871
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000872// Recursively traverses hidden prototypes if property is not found
873static void GetOwnPropertyImplementation(JSObject* obj,
874 String* name,
875 LookupResult* result) {
876 obj->LocalLookupRealNamedProperty(name, result);
877
878 if (!result->IsProperty()) {
879 Object* proto = obj->GetPrototype();
880 if (proto->IsJSObject() &&
881 JSObject::cast(proto)->map()->is_hidden_prototype())
882 GetOwnPropertyImplementation(JSObject::cast(proto),
883 name, result);
884 }
885}
886
887
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000888static bool CheckAccessException(LookupResult* result,
889 v8::AccessType access_type) {
890 if (result->type() == CALLBACKS) {
891 Object* callback = result->GetCallbackObject();
892 if (callback->IsAccessorInfo()) {
893 AccessorInfo* info = AccessorInfo::cast(callback);
894 bool can_access =
895 (access_type == v8::ACCESS_HAS &&
896 (info->all_can_read() || info->all_can_write())) ||
897 (access_type == v8::ACCESS_GET && info->all_can_read()) ||
898 (access_type == v8::ACCESS_SET && info->all_can_write());
899 return can_access;
900 }
901 }
902
903 return false;
904}
905
906
907static bool CheckAccess(JSObject* obj,
908 String* name,
909 LookupResult* result,
910 v8::AccessType access_type) {
911 ASSERT(result->IsProperty());
912
913 JSObject* holder = result->holder();
914 JSObject* current = obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000915 Isolate* isolate = obj->GetIsolate();
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000916 while (true) {
917 if (current->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000918 !isolate->MayNamedAccess(current, name, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000919 // Access check callback denied the access, but some properties
920 // can have a special permissions which override callbacks descision
921 // (currently see v8::AccessControl).
922 break;
923 }
924
925 if (current == holder) {
926 return true;
927 }
928
929 current = JSObject::cast(current->GetPrototype());
930 }
931
932 // API callbacks can have per callback access exceptions.
933 switch (result->type()) {
934 case CALLBACKS: {
935 if (CheckAccessException(result, access_type)) {
936 return true;
937 }
938 break;
939 }
940 case INTERCEPTOR: {
941 // If the object has an interceptor, try real named properties.
942 // Overwrite the result to fetch the correct property later.
943 holder->LookupRealNamedProperty(name, result);
944 if (result->IsProperty()) {
945 if (CheckAccessException(result, access_type)) {
946 return true;
947 }
948 }
949 break;
950 }
951 default:
952 break;
953 }
954
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000955 isolate->ReportFailedAccessCheck(current, access_type);
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000956 return false;
957}
958
959
960// TODO(1095): we should traverse hidden prototype hierachy as well.
961static bool CheckElementAccess(JSObject* obj,
962 uint32_t index,
963 v8::AccessType access_type) {
964 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000965 !obj->GetIsolate()->MayIndexedAccess(obj, index, access_type)) {
ricow@chromium.org83aa5492011-02-07 12:42:56 +0000966 return false;
967 }
968
969 return true;
970}
971
972
ricow@chromium.org30ce4112010-05-31 10:38:25 +0000973// Enumerator used as indices into the array returned from GetOwnProperty
974enum PropertyDescriptorIndices {
975 IS_ACCESSOR_INDEX,
976 VALUE_INDEX,
977 GETTER_INDEX,
978 SETTER_INDEX,
979 WRITABLE_INDEX,
980 ENUMERABLE_INDEX,
981 CONFIGURABLE_INDEX,
982 DESCRIPTOR_SIZE
983};
984
fschneider@chromium.org0c20e672010-01-14 15:28:53 +0000985// Returns an array with the property description:
986// if args[1] is not a property on args[0]
987// returns undefined
988// if args[1] is a data property on args[0]
989// [false, value, Writeable, Enumerable, Configurable]
990// if args[1] is an accessor on args[0]
991// [true, GetFunction, SetFunction, Enumerable, Configurable]
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +0000992RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOwnProperty) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +0000993 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +0000994 Heap* heap = isolate->heap();
995 HandleScope scope(isolate);
996 Handle<FixedArray> elms = isolate->factory()->NewFixedArray(DESCRIPTOR_SIZE);
997 Handle<JSArray> desc = isolate->factory()->NewJSArrayWithElements(elms);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +0000998 LookupResult result(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +0000999 CONVERT_ARG_CHECKED(JSObject, obj, 0);
1000 CONVERT_ARG_CHECKED(String, name, 1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001001
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001002 // This could be an element.
1003 uint32_t index;
1004 if (name->AsArrayIndex(&index)) {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001005 switch (obj->HasLocalElement(index)) {
1006 case JSObject::UNDEFINED_ELEMENT:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001007 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001008
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001009 case JSObject::STRING_CHARACTER_ELEMENT: {
1010 // Special handling of string objects according to ECMAScript 5
1011 // 15.5.5.2. Note that this might be a string object with elements
1012 // other than the actual string value. This is covered by the
1013 // subsequent cases.
1014 Handle<JSValue> js_value = Handle<JSValue>::cast(obj);
1015 Handle<String> str(String::cast(js_value->value()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001016 Handle<String> substr = SubString(str, index, index + 1, NOT_TENURED);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001018 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001019 elms->set(VALUE_INDEX, *substr);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001020 elms->set(WRITABLE_INDEX, heap->false_value());
1021 elms->set(ENUMERABLE_INDEX, heap->false_value());
1022 elms->set(CONFIGURABLE_INDEX, heap->false_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001023 return *desc;
1024 }
1025
1026 case JSObject::INTERCEPTED_ELEMENT:
1027 case JSObject::FAST_ELEMENT: {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001028 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001029 Handle<Object> value = Object::GetElement(obj, index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001030 RETURN_IF_EMPTY_HANDLE(isolate, value);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001031 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001032 elms->set(WRITABLE_INDEX, heap->true_value());
1033 elms->set(ENUMERABLE_INDEX, heap->true_value());
1034 elms->set(CONFIGURABLE_INDEX, heap->true_value());
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001035 return *desc;
1036 }
1037
1038 case JSObject::DICTIONARY_ELEMENT: {
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001039 Handle<JSObject> holder = obj;
1040 if (obj->IsJSGlobalProxy()) {
1041 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001042 if (proto->IsNull()) return heap->undefined_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001043 ASSERT(proto->IsJSGlobalObject());
1044 holder = Handle<JSObject>(JSObject::cast(proto));
1045 }
whesse@chromium.org7b260152011-06-20 15:33:18 +00001046 FixedArray* elements = FixedArray::cast(holder->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001047 SeededNumberDictionary* dictionary = NULL;
whesse@chromium.org7b260152011-06-20 15:33:18 +00001048 if (elements->map() == heap->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001049 dictionary = SeededNumberDictionary::cast(elements->get(1));
whesse@chromium.org7b260152011-06-20 15:33:18 +00001050 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001051 dictionary = SeededNumberDictionary::cast(elements);
whesse@chromium.org7b260152011-06-20 15:33:18 +00001052 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001053 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001054 ASSERT(entry != SeededNumberDictionary::kNotFound);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001055 PropertyDetails details = dictionary->DetailsAt(entry);
1056 switch (details.type()) {
1057 case CALLBACKS: {
1058 // This is an accessor property with getter and/or setter.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001059 AccessorPair* accessors =
1060 AccessorPair::cast(dictionary->ValueAt(entry));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001061 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001062 if (CheckElementAccess(*obj, index, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001063 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001064 }
1065 if (CheckElementAccess(*obj, index, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001066 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001067 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001068 break;
1069 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001070 case NORMAL: {
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001071 // This is a data property.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001072 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001073 Handle<Object> value = Object::GetElement(obj, index);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00001074 ASSERT(!value.is_null());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001075 elms->set(VALUE_INDEX, *value);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001076 elms->set(WRITABLE_INDEX, heap->ToBoolean(!details.IsReadOnly()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001077 break;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001078 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001079 default:
1080 UNREACHABLE();
1081 break;
1082 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001083 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!details.IsDontEnum()));
1084 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!details.IsDontDelete()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001085 return *desc;
1086 }
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001087 }
1088 }
1089
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001090 // Use recursive implementation to also traverse hidden prototypes
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00001091 GetOwnPropertyImplementation(*obj, *name, &result);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001092
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001093 if (!result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001094 return heap->undefined_value();
ricow@chromium.org30ce4112010-05-31 10:38:25 +00001095 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001096
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001097 if (!CheckAccess(*obj, *name, &result, v8::ACCESS_HAS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001098 return heap->false_value();
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001099 }
1100
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001101 elms->set(ENUMERABLE_INDEX, heap->ToBoolean(!result.IsDontEnum()));
1102 elms->set(CONFIGURABLE_INDEX, heap->ToBoolean(!result.IsDontDelete()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001103
1104 bool is_js_accessor = (result.type() == CALLBACKS) &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001105 (result.GetCallbackObject()->IsAccessorPair());
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001106
1107 if (is_js_accessor) {
1108 // __defineGetter__/__defineSetter__ callback.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001109 elms->set(IS_ACCESSOR_INDEX, heap->true_value());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001110
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001111 AccessorPair* accessors = AccessorPair::cast(result.GetCallbackObject());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001112 if (CheckAccess(*obj, *name, &result, v8::ACCESS_GET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001113 elms->set(GETTER_INDEX, accessors->getter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001114 }
1115 if (CheckAccess(*obj, *name, &result, v8::ACCESS_SET)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001116 elms->set(SETTER_INDEX, accessors->setter());
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001117 }
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001118 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001119 elms->set(IS_ACCESSOR_INDEX, heap->false_value());
1120 elms->set(WRITABLE_INDEX, heap->ToBoolean(!result.IsReadOnly()));
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001121
1122 PropertyAttributes attrs;
1123 Object* value;
ricow@chromium.org83aa5492011-02-07 12:42:56 +00001124 // GetProperty will check access and report any violations.
antonm@chromium.orgdca01352011-01-31 17:15:05 +00001125 { MaybeObject* maybe_value = obj->GetProperty(*obj, &result, *name, &attrs);
1126 if (!maybe_value->ToObject(&value)) return maybe_value;
1127 }
1128 elms->set(VALUE_INDEX, value);
1129 }
1130
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00001131 return *desc;
1132}
1133
1134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001135RUNTIME_FUNCTION(MaybeObject*, Runtime_PreventExtensions) {
kmillikin@chromium.org69ea3962010-07-05 11:01:40 +00001136 ASSERT(args.length() == 1);
1137 CONVERT_CHECKED(JSObject, obj, args[0]);
1138 return obj->PreventExtensions();
1139}
1140
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001141
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001142RUNTIME_FUNCTION(MaybeObject*, Runtime_IsExtensible) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001143 ASSERT(args.length() == 1);
1144 CONVERT_CHECKED(JSObject, obj, args[0]);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001145 if (obj->IsJSGlobalProxy()) {
1146 Object* proto = obj->GetPrototype();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001147 if (proto->IsNull()) return isolate->heap()->false_value();
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00001148 ASSERT(proto->IsJSGlobalObject());
1149 obj = JSObject::cast(proto);
1150 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001151 return isolate->heap()->ToBoolean(obj->map()->is_extensible());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00001152}
1153
1154
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001155RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001156 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001157 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001158 CONVERT_ARG_CHECKED(JSRegExp, re, 0);
1159 CONVERT_ARG_CHECKED(String, pattern, 1);
1160 CONVERT_ARG_CHECKED(String, flags, 2);
ager@chromium.org3bf7b912008-11-17 09:09:45 +00001161 Handle<Object> result = RegExpImpl::Compile(re, pattern, flags);
1162 if (result.is_null()) return Failure::Exception();
1163 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001164}
1165
1166
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001167RUNTIME_FUNCTION(MaybeObject*, Runtime_CreateApiFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001168 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001169 ASSERT(args.length() == 1);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001170 CONVERT_ARG_CHECKED(FunctionTemplateInfo, data, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001171 return *isolate->factory()->CreateApiFunction(data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001172}
1173
1174
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001175RUNTIME_FUNCTION(MaybeObject*, Runtime_IsTemplate) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001176 ASSERT(args.length() == 1);
1177 Object* arg = args[0];
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001178 bool result = arg->IsObjectTemplateInfo() || arg->IsFunctionTemplateInfo();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001179 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001180}
1181
1182
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001183RUNTIME_FUNCTION(MaybeObject*, Runtime_GetTemplateField) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001184 ASSERT(args.length() == 2);
1185 CONVERT_CHECKED(HeapObject, templ, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001186 CONVERT_CHECKED(Smi, field, args[1]);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001187 int index = field->value();
1188 int offset = index * kPointerSize + HeapObject::kHeaderSize;
1189 InstanceType type = templ->map()->instance_type();
1190 RUNTIME_ASSERT(type == FUNCTION_TEMPLATE_INFO_TYPE ||
1191 type == OBJECT_TEMPLATE_INFO_TYPE);
1192 RUNTIME_ASSERT(offset > 0);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00001193 if (type == FUNCTION_TEMPLATE_INFO_TYPE) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00001194 RUNTIME_ASSERT(offset < FunctionTemplateInfo::kSize);
1195 } else {
1196 RUNTIME_ASSERT(offset < ObjectTemplateInfo::kSize);
1197 }
1198 return *HeapObject::RawField(templ, offset);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001199}
1200
1201
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001202RUNTIME_FUNCTION(MaybeObject*, Runtime_DisableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001203 ASSERT(args.length() == 1);
1204 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001205 Map* old_map = object->map();
1206 bool needs_access_checks = old_map->is_access_check_needed();
1207 if (needs_access_checks) {
1208 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001209 Object* new_map;
1210 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1211 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1212 }
ager@chromium.org32912102009-01-16 10:38:43 +00001213
1214 Map::cast(new_map)->set_is_access_check_needed(false);
1215 object->set_map(Map::cast(new_map));
1216 }
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001217 return isolate->heap()->ToBoolean(needs_access_checks);
ager@chromium.org870a0b62008-11-04 11:43:05 +00001218}
1219
1220
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001221RUNTIME_FUNCTION(MaybeObject*, Runtime_EnableAccessChecks) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00001222 ASSERT(args.length() == 1);
1223 CONVERT_CHECKED(HeapObject, object, args[0]);
ager@chromium.org32912102009-01-16 10:38:43 +00001224 Map* old_map = object->map();
1225 if (!old_map->is_access_check_needed()) {
1226 // Copy map so it won't interfere constructor's initial map.
lrn@chromium.org303ada72010-10-27 09:33:13 +00001227 Object* new_map;
1228 { MaybeObject* maybe_new_map = old_map->CopyDropTransitions();
1229 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
1230 }
ager@chromium.org32912102009-01-16 10:38:43 +00001231
1232 Map::cast(new_map)->set_is_access_check_needed(true);
1233 object->set_map(Map::cast(new_map));
1234 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001235 return isolate->heap()->undefined_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00001236}
1237
1238
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001239static Failure* ThrowRedeclarationError(Isolate* isolate,
1240 const char* type,
1241 Handle<String> name) {
1242 HandleScope scope(isolate);
1243 Handle<Object> type_handle =
1244 isolate->factory()->NewStringFromAscii(CStrVector(type));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001245 Handle<Object> args[2] = { type_handle, name };
1246 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001247 isolate->factory()->NewTypeError("redeclaration", HandleVector(args, 2));
1248 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001249}
1250
1251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001252RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareGlobals) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001253 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001254 HandleScope scope(isolate);
1255 Handle<GlobalObject> global = Handle<GlobalObject>(
1256 isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001257
ager@chromium.org3811b432009-10-28 14:53:37 +00001258 Handle<Context> context = args.at<Context>(0);
1259 CONVERT_ARG_CHECKED(FixedArray, pairs, 1);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001260 CONVERT_SMI_ARG_CHECKED(flags, 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001261
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001262 // Traverse the name/value pairs and set the properties.
1263 int length = pairs->length();
1264 for (int i = 0; i < length; i += 2) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001265 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001266 Handle<String> name(String::cast(pairs->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001267 Handle<Object> value(pairs->get(i + 1), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001268
1269 // We have to declare a global const property. To capture we only
1270 // assign to it when evaluating the assignment for "const x =
1271 // <expr>" the initial value is the hole.
1272 bool is_const_property = value->IsTheHole();
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001273 bool is_function_declaration = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001274 if (value->IsUndefined() || is_const_property) {
1275 // Lookup the property in the global object, and don't set the
1276 // value of the variable if the property is already there.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001277 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001278 global->Lookup(*name, &lookup);
1279 if (lookup.IsProperty()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001280 // We found an existing property. Unless it was an interceptor
1281 // that claims the property is absent, skip this declaration.
1282 if (lookup.type() != INTERCEPTOR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001283 continue;
1284 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001285 PropertyAttributes attributes = global->GetPropertyAttribute(*name);
1286 if (attributes != ABSENT) {
1287 continue;
1288 }
1289 // Fall-through and introduce the absent property by using
1290 // SetProperty.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001291 }
1292 } else {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001293 is_function_declaration = true;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001294 // Copy the function and update its context. Use it as value.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00001295 Handle<SharedFunctionInfo> shared =
1296 Handle<SharedFunctionInfo>::cast(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001297 Handle<JSFunction> function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001298 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
1299 context,
1300 TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001301 value = function;
1302 }
1303
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001304 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001305 global->LocalLookup(*name, &lookup);
1306
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001307 // Compute the property attributes. According to ECMA-262, section
1308 // 13, page 71, the property must be read-only and
1309 // non-deletable. However, neither SpiderMonkey nor KJS creates the
1310 // property as read-only, so we don't either.
1311 int attr = NONE;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001312 if (!DeclareGlobalsEvalFlag::decode(flags)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001313 attr |= DONT_DELETE;
1314 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001315 bool is_native = DeclareGlobalsNativeFlag::decode(flags);
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001316 if (is_const_property || (is_native && is_function_declaration)) {
1317 attr |= READ_ONLY;
1318 }
1319
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001320 // Safari does not allow the invocation of callback setters for
1321 // function declarations. To mimic this behavior, we do not allow
1322 // the invocation of setters for function values. This makes a
1323 // difference for global functions with the same names as event
1324 // handlers such as "function onload() {}". Firefox does call the
1325 // onload setter in those case and Safari does not. We follow
1326 // Safari for compatibility.
1327 if (value->IsJSFunction()) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001328 // Do not change DONT_DELETE to false from true.
1329 if (lookup.IsProperty() && (lookup.type() != INTERCEPTOR)) {
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001330 attr |= lookup.GetAttributes() & DONT_DELETE;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001331 }
fschneider@chromium.org1805e212011-09-05 10:49:12 +00001332 PropertyAttributes attributes = static_cast<PropertyAttributes>(attr);
1333
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001334 RETURN_IF_EMPTY_HANDLE(
1335 isolate,
1336 JSObject::SetLocalPropertyIgnoreAttributes(global, name, value,
1337 attributes));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001338 } else {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001339 LanguageMode language_mode = DeclareGlobalsLanguageMode::decode(flags);
1340 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1341 ? kNonStrictMode : kStrictMode;
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001342 RETURN_IF_EMPTY_HANDLE(
1343 isolate,
1344 JSReceiver::SetProperty(global, name, value,
1345 static_cast<PropertyAttributes>(attr),
1346 strict_mode_flag));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001347 }
1348 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00001349
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001350 ASSERT(!isolate->has_pending_exception());
1351 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001352}
1353
1354
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001355RUNTIME_FUNCTION(MaybeObject*, Runtime_DeclareContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001356 HandleScope scope(isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001357 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001358
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001359 // Declarations are always made in a function or global context. In the
1360 // case of eval code, the context passed is the context of the caller,
1361 // which may be some nested context and not the declaration context.
1362 RUNTIME_ASSERT(args[0]->IsContext());
1363 Handle<Context> context(Context::cast(args[0])->declaration_context());
1364
ager@chromium.org7c537e22008-10-16 08:43:32 +00001365 Handle<String> name(String::cast(args[1]));
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001366 PropertyAttributes mode = static_cast<PropertyAttributes>(args.smi_at(2));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +00001367 RUNTIME_ASSERT(mode == READ_ONLY || mode == NONE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001368 Handle<Object> initial_value(args[3], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001369
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001370 int index;
1371 PropertyAttributes attributes;
1372 ContextLookupFlags flags = DONT_FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001373 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001374 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001375 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001376
1377 if (attributes != ABSENT) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001378 // The name was declared before; check for conflicting re-declarations.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001379 if (((attributes & READ_ONLY) != 0) || (mode == READ_ONLY)) {
1380 // Functions are not read-only.
1381 ASSERT(mode != READ_ONLY || initial_value->IsTheHole());
1382 const char* type = ((attributes & READ_ONLY) != 0) ? "const" : "var";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001383 return ThrowRedeclarationError(isolate, type, name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001384 }
1385
1386 // Initialize it if necessary.
1387 if (*initial_value != NULL) {
1388 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001389 ASSERT(holder.is_identical_to(context));
1390 if (((attributes & READ_ONLY) == 0) ||
1391 context->get(index)->IsTheHole()) {
1392 context->set(index, *initial_value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001393 }
1394 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001395 // Slow case: The property is in the context extension object of a
1396 // function context or the global object of a global context.
1397 Handle<JSObject> object = Handle<JSObject>::cast(holder);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001398 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001399 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001400 JSReceiver::SetProperty(object, name, initial_value, mode,
1401 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001402 }
1403 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001404
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001405 } else {
ager@chromium.org7c537e22008-10-16 08:43:32 +00001406 // The property is not in the function context. It needs to be
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001407 // "declared" in the function context's extension context or as a
1408 // property of the the global object.
1409 Handle<JSObject> object;
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00001410 if (context->has_extension()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001411 object = Handle<JSObject>(JSObject::cast(context->extension()));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001412 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001413 // Context extension objects are allocated lazily.
1414 ASSERT(context->IsFunctionContext());
1415 object = isolate->factory()->NewJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001416 isolate->context_extension_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001417 context->set_extension(*object);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001418 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001419 ASSERT(*object != NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001420
ager@chromium.org7c537e22008-10-16 08:43:32 +00001421 // Declare the property by setting it to the initial value if provided,
1422 // or undefined, and use the correct mode (e.g. READ_ONLY attribute for
1423 // constant declarations).
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001424 ASSERT(!object->HasLocalProperty(*name));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001425 Handle<Object> value(isolate->heap()->undefined_value(), isolate);
ager@chromium.org7c537e22008-10-16 08:43:32 +00001426 if (*initial_value != NULL) value = initial_value;
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001427 // Declaring a const context slot is a conflicting declaration if
1428 // there is a callback with that name in a prototype. It is
1429 // allowed to introduce const variables in
1430 // JSContextExtensionObjects. They are treated specially in
1431 // SetProperty and no setters are invoked for those since they are
1432 // not real JSObjects.
1433 if (initial_value->IsTheHole() &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001434 !object->IsJSContextExtensionObject()) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001435 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001436 object->Lookup(*name, &lookup);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001437 if (lookup.IsProperty() && (lookup.type() == CALLBACKS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001438 return ThrowRedeclarationError(isolate, "const", name);
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001439 }
1440 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001441 RETURN_IF_EMPTY_HANDLE(
1442 isolate,
1443 JSReceiver::SetProperty(object, name, value, mode, kNonStrictMode));
ager@chromium.org7c537e22008-10-16 08:43:32 +00001444 }
1445
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001446 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001447}
1448
1449
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001450RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeVarGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001451 NoHandleAllocation nha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001452 // args[0] == name
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001453 // args[1] == language_mode
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001454 // args[2] == value (optional)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001455
1456 // Determine if we need to assign to the variable if it already
1457 // exists (based on the number of arguments).
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001458 RUNTIME_ASSERT(args.length() == 2 || args.length() == 3);
1459 bool assign = args.length() == 3;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001460
1461 CONVERT_ARG_CHECKED(String, name, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001462 GlobalObject* global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001463 RUNTIME_ASSERT(args[1]->IsSmi());
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001464 CONVERT_LANGUAGE_MODE_ARG(language_mode, 1);
1465 StrictModeFlag strict_mode_flag = (language_mode == CLASSIC_MODE)
1466 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001467
1468 // According to ECMA-262, section 12.2, page 62, the property must
1469 // not be deletable.
1470 PropertyAttributes attributes = DONT_DELETE;
1471
1472 // Lookup the property locally in the global object. If it isn't
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001473 // there, there is a property with this name in the prototype chain.
1474 // We follow Safari and Firefox behavior and only set the property
1475 // locally if there is an explicit initialization value that we have
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00001476 // to assign to the property.
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001477 // Note that objects can have hidden prototypes, so we need to traverse
1478 // the whole chain of hidden prototypes to do a 'local' lookup.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001479 Object* object = global;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001480 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001481 while (object->IsJSObject() &&
1482 JSObject::cast(object)->map()->is_hidden_prototype()) {
1483 JSObject* raw_holder = JSObject::cast(object);
1484 raw_holder->LocalLookup(*name, &lookup);
1485 if (lookup.IsProperty() && lookup.type() == INTERCEPTOR) {
1486 HandleScope handle_scope(isolate);
1487 Handle<JSObject> holder(raw_holder);
1488 PropertyAttributes intercepted = holder->GetPropertyAttribute(*name);
1489 // Update the raw pointer in case it's changed due to GC.
1490 raw_holder = *holder;
1491 if (intercepted != ABSENT && (intercepted & READ_ONLY) == 0) {
1492 // Found an interceptor that's not read only.
1493 if (assign) {
1494 return raw_holder->SetProperty(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001495 &lookup, *name, args[2], attributes, strict_mode_flag);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001496 } else {
1497 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00001498 }
1499 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001500 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001501 object = raw_holder->GetPrototype();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001502 }
1503
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001504 // Reload global in case the loop above performed a GC.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001505 global = isolate->context()->global();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001506 if (assign) {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001507 return global->SetProperty(*name, args[2], attributes, strict_mode_flag);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001508 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001509 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001510}
1511
1512
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001513RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstGlobal) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001514 // All constants are declared with an initial value. The name
1515 // of the constant is the first argument and the initial value
1516 // is the second.
1517 RUNTIME_ASSERT(args.length() == 2);
1518 CONVERT_ARG_CHECKED(String, name, 0);
1519 Handle<Object> value = args.at<Object>(1);
1520
1521 // Get the current global object from top.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001522 GlobalObject* global = isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001523
1524 // According to ECMA-262, section 12.2, page 62, the property must
1525 // not be deletable. Since it's a const, it must be READ_ONLY too.
1526 PropertyAttributes attributes =
1527 static_cast<PropertyAttributes>(DONT_DELETE | READ_ONLY);
1528
1529 // Lookup the property locally in the global object. If it isn't
1530 // there, we add the property and take special precautions to always
1531 // add it as a local property even in case of callbacks in the
1532 // prototype chain (this rules out using SetProperty).
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001533 // We use SetLocalPropertyIgnoreAttributes instead
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001534 LookupResult lookup(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001535 global->LocalLookup(*name, &lookup);
1536 if (!lookup.IsProperty()) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001537 return global->SetLocalPropertyIgnoreAttributes(*name,
1538 *value,
1539 attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001540 }
1541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001542 if (!lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001543 // Restore global object from context (in case of GC) and continue
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001544 // with setting the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001545 HandleScope handle_scope(isolate);
1546 Handle<GlobalObject> global(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001547
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001548 // BUG 1213575: Handle the case where we have to set a read-only
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001549 // property through an interceptor and only do it if it's
1550 // uninitialized, e.g. the hole. Nirk...
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001551 // Passing non-strict mode because the property is writable.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001552 RETURN_IF_EMPTY_HANDLE(
1553 isolate,
1554 JSReceiver::SetProperty(global, name, value, attributes,
1555 kNonStrictMode));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001556 return *value;
1557 }
1558
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001559 // Set the value, but only if we're assigning the initial value to a
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001560 // constant. For now, we determine this by checking if the
1561 // current value is the hole.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001562 // Strict mode handling not needed (const is disallowed in strict mode).
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001563 PropertyType type = lookup.type();
1564 if (type == FIELD) {
1565 FixedArray* properties = global->properties();
1566 int index = lookup.GetFieldIndex();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001567 if (properties->get(index)->IsTheHole() || !lookup.IsReadOnly()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001568 properties->set(index, *value);
1569 }
1570 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001571 if (global->GetNormalizedProperty(&lookup)->IsTheHole() ||
1572 !lookup.IsReadOnly()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00001573 global->SetNormalizedProperty(&lookup, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001574 }
1575 } else {
1576 // Ignore re-initialization of constants that have already been
1577 // assigned a function value.
1578 ASSERT(lookup.IsReadOnly() && type == CONSTANT_FUNCTION);
1579 }
1580
1581 // Use the set value as the result of the operation.
1582 return *value;
1583}
1584
1585
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001586RUNTIME_FUNCTION(MaybeObject*, Runtime_InitializeConstContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001587 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001588 ASSERT(args.length() == 3);
1589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001590 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001591 ASSERT(!value->IsTheHole());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001592
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00001593 // Initializations are always done in a function or global context.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001594 RUNTIME_ASSERT(args[1]->IsContext());
1595 Handle<Context> context(Context::cast(args[1])->declaration_context());
1596
1597 Handle<String> name(String::cast(args[2]));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001598
1599 int index;
1600 PropertyAttributes attributes;
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001601 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001602 BindingFlags binding_flags;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00001603 Handle<Object> holder =
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00001604 context->Lookup(name, flags, &index, &attributes, &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001605
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001606 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001607 ASSERT(holder->IsContext());
1608 // Property was found in a context. Perform the assignment if we
1609 // found some non-constant or an uninitialized constant.
1610 Handle<Context> context = Handle<Context>::cast(holder);
1611 if ((attributes & READ_ONLY) == 0 || context->get(index)->IsTheHole()) {
1612 context->set(index, *value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001613 }
1614 return *value;
1615 }
1616
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001617 // The property could not be found, we introduce it as a property of the
1618 // global object.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001619 if (attributes == ABSENT) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001620 Handle<JSObject> global = Handle<JSObject>(
1621 isolate->context()->global());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001622 // Strict mode not needed (const disallowed in strict mode).
1623 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001624 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001625 JSReceiver::SetProperty(global, name, value, NONE, kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001626 return *value;
1627 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001628
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001629 // The property was present in some function's context extension object,
1630 // as a property on the subject of a with, or as a property of the global
1631 // object.
1632 //
1633 // In most situations, eval-introduced consts should still be present in
1634 // the context extension object. However, because declaration and
1635 // initialization are separate, the property might have been deleted
1636 // before we reach the initialization point.
1637 //
1638 // Example:
1639 //
1640 // function f() { eval("delete x; const x;"); }
1641 //
1642 // In that case, the initialization behaves like a normal assignment.
1643 Handle<JSObject> object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001644
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001645 if (*object == context->extension()) {
1646 // This is the property that was introduced by the const declaration.
1647 // Set it if it hasn't been set before. NOTE: We cannot use
1648 // GetProperty() to get the current value as it 'unholes' the value.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00001649 LookupResult lookup(isolate);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001650 object->LocalLookupRealNamedProperty(*name, &lookup);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001651 ASSERT(lookup.IsProperty()); // the property was declared
1652 ASSERT(lookup.IsReadOnly()); // and it was declared as read-only
1653
1654 PropertyType type = lookup.type();
1655 if (type == FIELD) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001656 FixedArray* properties = object->properties();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001657 int index = lookup.GetFieldIndex();
1658 if (properties->get(index)->IsTheHole()) {
1659 properties->set(index, *value);
1660 }
1661 } else if (type == NORMAL) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001662 if (object->GetNormalizedProperty(&lookup)->IsTheHole()) {
1663 object->SetNormalizedProperty(&lookup, *value);
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001664 }
1665 } else {
1666 // We should not reach here. Any real, named property should be
1667 // either a field or a dictionary slot.
1668 UNREACHABLE();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001669 }
1670 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001671 // The property was found on some other object. Set it if it is not a
1672 // read-only property.
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001673 if ((attributes & READ_ONLY) == 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00001674 // Strict mode not needed (const disallowed in strict mode).
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00001675 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001676 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001677 JSReceiver::SetProperty(object, name, value, attributes,
1678 kNonStrictMode));
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001679 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001680 }
ager@chromium.orgddb913d2009-01-27 10:01:48 +00001681
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001682 return *value;
1683}
1684
1685
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001686RUNTIME_FUNCTION(MaybeObject*,
1687 Runtime_OptimizeObjectForAddingMultipleProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001688 HandleScope scope(isolate);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001689 ASSERT(args.length() == 2);
1690 CONVERT_ARG_CHECKED(JSObject, object, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001691 CONVERT_SMI_ARG_CHECKED(properties, 1);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001692 if (object->HasFastProperties()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001693 JSObject::NormalizeProperties(object, KEEP_INOBJECT_PROPERTIES, properties);
sgjesse@chromium.org911335c2009-08-19 12:59:44 +00001694 }
1695 return *object;
1696}
1697
1698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001699RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExec) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001700 HandleScope scope(isolate);
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001701 ASSERT(args.length() == 4);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001702 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
1703 CONVERT_ARG_CHECKED(String, subject, 1);
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001704 // Due to the way the JS calls are constructed this must be less than the
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001705 // length of a string, i.e. it is always a Smi. We check anyway for security.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001706 CONVERT_SMI_ARG_CHECKED(index, 2);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00001707 CONVERT_ARG_CHECKED(JSArray, last_match_info, 3);
ager@chromium.org41826e72009-03-30 13:30:57 +00001708 RUNTIME_ASSERT(last_match_info->HasFastElements());
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001709 RUNTIME_ASSERT(index >= 0);
1710 RUNTIME_ASSERT(index <= subject->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001711 isolate->counters()->regexp_entry_runtime()->Increment();
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001712 Handle<Object> result = RegExpImpl::Exec(regexp,
1713 subject,
kasperl@chromium.org68ac0092009-07-09 06:00:35 +00001714 index,
kasperl@chromium.org7be3c992009-03-12 07:19:55 +00001715 last_match_info);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00001716 if (result.is_null()) return Failure::Exception();
1717 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001718}
1719
1720
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001721RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpConstructResult) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001722 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001723 CONVERT_SMI_ARG_CHECKED(elements_count, 0);
ricow@chromium.org2c99e282011-07-28 09:15:17 +00001724 if (elements_count < 0 ||
1725 elements_count > FixedArray::kMaxLength ||
1726 !Smi::IsValid(elements_count)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001727 return isolate->ThrowIllegalOperation();
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001728 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00001729 Object* new_object;
1730 { MaybeObject* maybe_new_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001731 isolate->heap()->AllocateFixedArrayWithHoles(elements_count);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001732 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1733 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001734 FixedArray* elements = FixedArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001735 { MaybeObject* maybe_new_object = isolate->heap()->AllocateRaw(
1736 JSRegExpResult::kSize, NEW_SPACE, OLD_POINTER_SPACE);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001737 if (!maybe_new_object->ToObject(&new_object)) return maybe_new_object;
1738 }
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001739 {
1740 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001741 HandleScope scope(isolate);
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001742 reinterpret_cast<HeapObject*>(new_object)->
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001743 set_map(isolate->global_context()->regexp_result_map());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001744 }
1745 JSArray* array = JSArray::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001746 array->set_properties(isolate->heap()->empty_fixed_array());
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00001747 array->set_elements(elements);
1748 array->set_length(Smi::FromInt(elements_count));
1749 // Write in-object properties after the length of the array.
1750 array->InObjectPropertyAtPut(JSRegExpResult::kIndexIndex, args[1]);
1751 array->InObjectPropertyAtPut(JSRegExpResult::kInputIndex, args[2]);
1752 return array;
1753}
1754
1755
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001756RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpInitializeObject) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00001757 AssertNoAllocation no_alloc;
1758 ASSERT(args.length() == 5);
1759 CONVERT_CHECKED(JSRegExp, regexp, args[0]);
1760 CONVERT_CHECKED(String, source, args[1]);
1761
1762 Object* global = args[2];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001763 if (!global->IsTrue()) global = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001764
1765 Object* ignoreCase = args[3];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001766 if (!ignoreCase->IsTrue()) ignoreCase = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001767
1768 Object* multiline = args[4];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001769 if (!multiline->IsTrue()) multiline = isolate->heap()->false_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00001770
1771 Map* map = regexp->map();
1772 Object* constructor = map->constructor();
1773 if (constructor->IsJSFunction() &&
1774 JSFunction::cast(constructor)->initial_map() == map) {
1775 // If we still have the original map, set in-object properties directly.
1776 regexp->InObjectPropertyAtPut(JSRegExp::kSourceFieldIndex, source);
erikcorry0ad885c2011-11-21 13:51:57 +00001777 // Both true and false are immovable immortal objects so no need for write
1778 // barrier.
1779 regexp->InObjectPropertyAtPut(
1780 JSRegExp::kGlobalFieldIndex, global, SKIP_WRITE_BARRIER);
1781 regexp->InObjectPropertyAtPut(
1782 JSRegExp::kIgnoreCaseFieldIndex, ignoreCase, SKIP_WRITE_BARRIER);
1783 regexp->InObjectPropertyAtPut(
1784 JSRegExp::kMultilineFieldIndex, multiline, SKIP_WRITE_BARRIER);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001785 regexp->InObjectPropertyAtPut(JSRegExp::kLastIndexFieldIndex,
1786 Smi::FromInt(0),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00001787 SKIP_WRITE_BARRIER); // It's a Smi.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001788 return regexp;
1789 }
1790
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001791 // Map has changed, so use generic, but slower, method.
lrn@chromium.org25156de2010-04-06 13:10:27 +00001792 PropertyAttributes final =
1793 static_cast<PropertyAttributes>(READ_ONLY | DONT_ENUM | DONT_DELETE);
1794 PropertyAttributes writable =
1795 static_cast<PropertyAttributes>(DONT_ENUM | DONT_DELETE);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001796 Heap* heap = isolate->heap();
lrn@chromium.org303ada72010-10-27 09:33:13 +00001797 MaybeObject* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001798 result = regexp->SetLocalPropertyIgnoreAttributes(heap->source_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001799 source,
1800 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001801 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001802 result = regexp->SetLocalPropertyIgnoreAttributes(heap->global_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001803 global,
1804 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001805 ASSERT(!result->IsFailure());
1806 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001807 regexp->SetLocalPropertyIgnoreAttributes(heap->ignore_case_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001808 ignoreCase,
1809 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001810 ASSERT(!result->IsFailure());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001811 result = regexp->SetLocalPropertyIgnoreAttributes(heap->multiline_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001812 multiline,
1813 final);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001814 ASSERT(!result->IsFailure());
1815 result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001816 regexp->SetLocalPropertyIgnoreAttributes(heap->last_index_symbol(),
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00001817 Smi::FromInt(0),
1818 writable);
lrn@chromium.org303ada72010-10-27 09:33:13 +00001819 ASSERT(!result->IsFailure());
1820 USE(result);
lrn@chromium.org25156de2010-04-06 13:10:27 +00001821 return regexp;
1822}
1823
1824
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001825RUNTIME_FUNCTION(MaybeObject*, Runtime_FinishArrayPrototypeSetup) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001826 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001827 ASSERT(args.length() == 1);
1828 CONVERT_ARG_CHECKED(JSArray, prototype, 0);
1829 // This is necessary to enable fast checks for absence of elements
1830 // on Array.prototype and below.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001831 prototype->set_elements(isolate->heap()->empty_fixed_array());
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00001832 return Smi::FromInt(0);
1833}
1834
1835
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001836static Handle<JSFunction> InstallBuiltin(Isolate* isolate,
1837 Handle<JSObject> holder,
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001838 const char* name,
sgjesse@chromium.org720dc0b2010-05-10 09:25:39 +00001839 Builtins::Name builtin_name) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001840 Handle<String> key = isolate->factory()->LookupAsciiSymbol(name);
1841 Handle<Code> code(isolate->builtins()->builtin(builtin_name));
1842 Handle<JSFunction> optimized =
1843 isolate->factory()->NewFunction(key,
1844 JS_OBJECT_TYPE,
1845 JSObject::kHeaderSize,
1846 code,
1847 false);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001848 optimized->shared()->DontAdaptArguments();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00001849 JSReceiver::SetProperty(holder, key, optimized, NONE, kStrictMode);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001850 return optimized;
1851}
1852
1853
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001854RUNTIME_FUNCTION(MaybeObject*, Runtime_SpecialArrayFunctions) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001855 HandleScope scope(isolate);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001856 ASSERT(args.length() == 1);
1857 CONVERT_ARG_CHECKED(JSObject, holder, 0);
1858
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00001859 InstallBuiltin(isolate, holder, "pop", Builtins::kArrayPop);
1860 InstallBuiltin(isolate, holder, "push", Builtins::kArrayPush);
1861 InstallBuiltin(isolate, holder, "shift", Builtins::kArrayShift);
1862 InstallBuiltin(isolate, holder, "unshift", Builtins::kArrayUnshift);
1863 InstallBuiltin(isolate, holder, "slice", Builtins::kArraySlice);
1864 InstallBuiltin(isolate, holder, "splice", Builtins::kArraySplice);
1865 InstallBuiltin(isolate, holder, "concat", Builtins::kArrayConcat);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00001866
1867 return *holder;
1868}
1869
1870
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001871RUNTIME_FUNCTION(MaybeObject*, Runtime_GetDefaultReceiver) {
1872 NoHandleAllocation handle_free;
1873 ASSERT(args.length() == 1);
1874 CONVERT_CHECKED(JSFunction, function, args[0]);
1875 SharedFunctionInfo* shared = function->shared();
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00001876 if (shared->native() || !shared->is_classic_mode()) {
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001877 return isolate->heap()->undefined_value();
1878 }
1879 // Returns undefined for strict or native functions, or
1880 // the associated global receiver for "normal" functions.
1881
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001882 Context* global_context =
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00001883 function->context()->global()->global_context();
ager@chromium.org357bf652010-04-12 11:30:10 +00001884 return global_context->global()->global_receiver();
1885}
1886
1887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001888RUNTIME_FUNCTION(MaybeObject*, Runtime_MaterializeRegExpLiteral) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001889 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001890 ASSERT(args.length() == 4);
1891 CONVERT_ARG_CHECKED(FixedArray, literals, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00001892 int index = args.smi_at(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001893 Handle<String> pattern = args.at<String>(2);
1894 Handle<String> flags = args.at<String>(3);
1895
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00001896 // Get the RegExp function from the context in the literals array.
1897 // This is the RegExp function from the context in which the
1898 // function was created. We do not use the RegExp function from the
1899 // current global context because this might be the RegExp function
1900 // from another context which we should not have access to.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001901 Handle<JSFunction> constructor =
ager@chromium.org236ad962008-09-25 09:45:57 +00001902 Handle<JSFunction>(
1903 JSFunction::GlobalContextFromLiterals(*literals)->regexp_function());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001904 // Compute the regular expression literal.
1905 bool has_pending_exception;
1906 Handle<Object> regexp =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00001907 RegExpImpl::CreateRegExpLiteral(constructor, pattern, flags,
1908 &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001909 if (has_pending_exception) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001910 ASSERT(isolate->has_pending_exception());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001911 return Failure::Exception();
1912 }
1913 literals->set(index, *regexp);
1914 return *regexp;
1915}
1916
1917
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001918RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001919 NoHandleAllocation ha;
1920 ASSERT(args.length() == 1);
1921
1922 CONVERT_CHECKED(JSFunction, f, args[0]);
1923 return f->shared()->name();
1924}
1925
1926
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001927RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetName) {
ager@chromium.org236ad962008-09-25 09:45:57 +00001928 NoHandleAllocation ha;
1929 ASSERT(args.length() == 2);
1930
1931 CONVERT_CHECKED(JSFunction, f, args[0]);
1932 CONVERT_CHECKED(String, name, args[1]);
1933 f->shared()->set_name(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001934 return isolate->heap()->undefined_value();
ager@chromium.org236ad962008-09-25 09:45:57 +00001935}
1936
1937
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00001938RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionNameShouldPrintAsAnonymous) {
1939 NoHandleAllocation ha;
1940 ASSERT(args.length() == 1);
1941 CONVERT_CHECKED(JSFunction, f, args[0]);
1942 return isolate->heap()->ToBoolean(
1943 f->shared()->name_should_print_as_anonymous());
1944}
1945
1946
1947RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionMarkNameShouldPrintAsAnonymous) {
1948 NoHandleAllocation ha;
1949 ASSERT(args.length() == 1);
1950 CONVERT_CHECKED(JSFunction, f, args[0]);
1951 f->shared()->set_name_should_print_as_anonymous(true);
1952 return isolate->heap()->undefined_value();
1953}
1954
1955
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001956RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionRemovePrototype) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001957 NoHandleAllocation ha;
1958 ASSERT(args.length() == 1);
1959
1960 CONVERT_CHECKED(JSFunction, f, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001961 Object* obj = f->RemovePrototype();
1962 if (obj->IsFailure()) return obj;
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001963
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001964 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00001965}
1966
1967
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001968RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001969 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001970 ASSERT(args.length() == 1);
1971
1972 CONVERT_CHECKED(JSFunction, fun, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00001973 Handle<Object> script = Handle<Object>(fun->shared()->script(), isolate);
1974 if (!script->IsScript()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001975
1976 return *GetScriptWrapper(Handle<Script>::cast(script));
1977}
1978
1979
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001980RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetSourceCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001981 NoHandleAllocation ha;
1982 ASSERT(args.length() == 1);
1983
1984 CONVERT_CHECKED(JSFunction, f, args[0]);
1985 return f->shared()->GetSourceCode();
1986}
1987
1988
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001989RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetScriptSourcePosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00001990 NoHandleAllocation ha;
1991 ASSERT(args.length() == 1);
1992
1993 CONVERT_CHECKED(JSFunction, fun, args[0]);
1994 int pos = fun->shared()->start_position();
1995 return Smi::FromInt(pos);
1996}
1997
1998
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00001999RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetPositionForOffset) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002000 ASSERT(args.length() == 2);
2001
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002002 CONVERT_CHECKED(Code, code, args[0]);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002003 CONVERT_NUMBER_CHECKED(int, offset, Int32, args[1]);
2004
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002005 RUNTIME_ASSERT(0 <= offset && offset < code->Size());
2006
2007 Address pc = code->address() + offset;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002008 return Smi::FromInt(code->SourcePosition(pc));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00002009}
2010
2011
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002012RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetInstanceClassName) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002013 NoHandleAllocation ha;
2014 ASSERT(args.length() == 2);
2015
2016 CONVERT_CHECKED(JSFunction, fun, args[0]);
2017 CONVERT_CHECKED(String, name, args[1]);
2018 fun->SetInstanceClassName(name);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002019 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002020}
2021
2022
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002023RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetLength) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002024 NoHandleAllocation ha;
2025 ASSERT(args.length() == 2);
2026
2027 CONVERT_CHECKED(JSFunction, fun, args[0]);
2028 CONVERT_CHECKED(Smi, length, args[1]);
2029 fun->shared()->set_length(length->value());
2030 return length;
2031}
2032
2033
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002034RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetPrototype) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002035 NoHandleAllocation ha;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002036 ASSERT(args.length() == 2);
2037
2038 CONVERT_CHECKED(JSFunction, fun, args[0]);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00002039 ASSERT(fun->should_have_prototype());
lrn@chromium.org303ada72010-10-27 09:33:13 +00002040 Object* obj;
2041 { MaybeObject* maybe_obj =
2042 Accessors::FunctionSetPrototype(fun, args[1], NULL);
2043 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
2044 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002045 return args[0]; // return TOS
2046}
2047
2048
ricow@chromium.org2c99e282011-07-28 09:15:17 +00002049RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionSetReadOnlyPrototype) {
2050 NoHandleAllocation ha;
2051 RUNTIME_ASSERT(args.length() == 1);
2052 CONVERT_CHECKED(JSFunction, function, args[0]);
2053
2054 MaybeObject* maybe_name =
2055 isolate->heap()->AllocateStringFromAscii(CStrVector("prototype"));
2056 String* name;
2057 if (!maybe_name->To(&name)) return maybe_name;
2058
2059 if (function->HasFastProperties()) {
2060 // Construct a new field descriptor with updated attributes.
2061 DescriptorArray* instance_desc = function->map()->instance_descriptors();
2062 int index = instance_desc->Search(name);
2063 ASSERT(index != DescriptorArray::kNotFound);
2064 PropertyDetails details(instance_desc->GetDetails(index));
2065 CallbacksDescriptor new_desc(name,
2066 instance_desc->GetValue(index),
2067 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2068 details.index());
2069 // Construct a new field descriptors array containing the new descriptor.
2070 Object* descriptors_unchecked;
2071 { MaybeObject* maybe_descriptors_unchecked =
2072 instance_desc->CopyInsert(&new_desc, REMOVE_TRANSITIONS);
2073 if (!maybe_descriptors_unchecked->ToObject(&descriptors_unchecked)) {
2074 return maybe_descriptors_unchecked;
2075 }
2076 }
2077 DescriptorArray* new_descriptors =
2078 DescriptorArray::cast(descriptors_unchecked);
2079 // Create a new map featuring the new field descriptors array.
2080 Object* map_unchecked;
2081 { MaybeObject* maybe_map_unchecked = function->map()->CopyDropDescriptors();
2082 if (!maybe_map_unchecked->ToObject(&map_unchecked)) {
2083 return maybe_map_unchecked;
2084 }
2085 }
2086 Map* new_map = Map::cast(map_unchecked);
2087 new_map->set_instance_descriptors(new_descriptors);
2088 function->set_map(new_map);
2089 } else { // Dictionary properties.
2090 // Directly manipulate the property details.
2091 int entry = function->property_dictionary()->FindEntry(name);
2092 ASSERT(entry != StringDictionary::kNotFound);
2093 PropertyDetails details = function->property_dictionary()->DetailsAt(entry);
2094 PropertyDetails new_details(
2095 static_cast<PropertyAttributes>(details.attributes() | READ_ONLY),
2096 details.type(),
2097 details.index());
2098 function->property_dictionary()->DetailsAtPut(entry, new_details);
2099 }
2100 return function;
2101}
2102
2103
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002104RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsAPIFunction) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002105 NoHandleAllocation ha;
2106 ASSERT(args.length() == 1);
2107
2108 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002109 return isolate->heap()->ToBoolean(f->shared()->IsApiFunction());
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002110}
2111
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002112
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002113RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionIsBuiltin) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002114 NoHandleAllocation ha;
2115 ASSERT(args.length() == 1);
2116
2117 CONVERT_CHECKED(JSFunction, f, args[0]);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00002118 return isolate->heap()->ToBoolean(f->IsBuiltin());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00002119}
2120
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00002121
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002122RUNTIME_FUNCTION(MaybeObject*, Runtime_SetCode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002123 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002124 ASSERT(args.length() == 2);
2125
ager@chromium.org5aa501c2009-06-23 07:57:28 +00002126 CONVERT_ARG_CHECKED(JSFunction, target, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002127 Handle<Object> code = args.at<Object>(1);
2128
2129 Handle<Context> context(target->context());
2130
2131 if (!code->IsNull()) {
2132 RUNTIME_ASSERT(code->IsJSFunction());
2133 Handle<JSFunction> fun = Handle<JSFunction>::cast(code);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002134 Handle<SharedFunctionInfo> shared(fun->shared());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002135
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00002136 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002137 return Failure::Exception();
2138 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002139 // Since we don't store the source for this we should never
2140 // optimize this.
2141 shared->code()->set_optimizable(false);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002142 // Set the code, scope info, formal parameter count,
2143 // and the length of the target function.
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00002144 target->shared()->set_code(shared->code());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002145 target->ReplaceCode(shared->code());
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00002146 target->shared()->set_scope_info(shared->scope_info());
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002147 target->shared()->set_length(shared->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002148 target->shared()->set_formal_parameter_count(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00002149 shared->formal_parameter_count());
ager@chromium.org7c537e22008-10-16 08:43:32 +00002150 // Set the source code of the target function to undefined.
2151 // SetCode is only used for built-in constructors like String,
2152 // Array, and Object, and some web code
2153 // doesn't like seeing source code for constructors.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002154 target->shared()->set_script(isolate->heap()->undefined_value());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00002155 target->shared()->code()->set_optimizable(false);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00002156 // Clear the optimization hints related to the compiled code as these are no
2157 // longer valid when the code is overwritten.
2158 target->shared()->ClearThisPropertyAssignmentsInfo();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002159 context = Handle<Context>(fun->context());
2160
2161 // Make sure we get a fresh copy of the literal vector to avoid
2162 // cross context contamination.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002163 int number_of_literals = fun->NumberOfLiterals();
2164 Handle<FixedArray> literals =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002165 isolate->factory()->NewFixedArray(number_of_literals, TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002166 if (number_of_literals > 0) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00002167 // Insert the object, regexp and array functions in the literals
2168 // array prefix. These are the functions that will be used when
2169 // creating object, regexp and array literals.
ager@chromium.org236ad962008-09-25 09:45:57 +00002170 literals->set(JSFunction::kLiteralGlobalContextIndex,
2171 context->global_context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002172 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002173 target->set_literals(*literals);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002174 target->set_next_function_link(isolate->heap()->undefined_value());
lrn@chromium.org34e60782011-09-15 07:25:40 +00002175
2176 if (isolate->logger()->is_logging() || CpuProfiler::is_profiling(isolate)) {
2177 isolate->logger()->LogExistingFunction(
2178 shared, Handle<Code>(shared->code()));
2179 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002180 }
2181
2182 target->set_context(*context);
2183 return *target;
2184}
2185
2186
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002187RUNTIME_FUNCTION(MaybeObject*, Runtime_SetExpectedNumberOfProperties) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002188 HandleScope scope(isolate);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002189 ASSERT(args.length() == 2);
2190 CONVERT_ARG_CHECKED(JSFunction, function, 0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00002191 CONVERT_SMI_ARG_CHECKED(num, 1);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002192 RUNTIME_ASSERT(num >= 0);
2193 SetExpectedNofProperties(function, num);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002194 return isolate->heap()->undefined_value();
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00002195}
2196
2197
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002198MUST_USE_RESULT static MaybeObject* CharFromCode(Isolate* isolate,
2199 Object* char_code) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002200 uint32_t code;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00002201 if (char_code->ToArrayIndex(&code)) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002202 if (code <= 0xffff) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002203 return isolate->heap()->LookupSingleCharacterStringFromCode(code);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002204 }
2205 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002206 return isolate->heap()->empty_string();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002207}
2208
2209
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002210RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCharCodeAt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002211 NoHandleAllocation ha;
2212 ASSERT(args.length() == 2);
2213
2214 CONVERT_CHECKED(String, subject, args[0]);
2215 Object* index = args[1];
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002216 RUNTIME_ASSERT(index->IsNumber());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002217
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002218 uint32_t i = 0;
2219 if (index->IsSmi()) {
2220 int value = Smi::cast(index)->value();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002221 if (value < 0) return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002222 i = value;
2223 } else {
2224 ASSERT(index->IsHeapNumber());
2225 double value = HeapNumber::cast(index)->value();
2226 i = static_cast<uint32_t>(DoubleToInteger(value));
kasperl@chromium.org74e4e5e2010-01-25 10:15:52 +00002227 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002228
2229 // Flatten the string. If someone wants to get a char at an index
2230 // in a cons string, it is likely that more indices will be
2231 // accessed.
lrn@chromium.org303ada72010-10-27 09:33:13 +00002232 Object* flat;
2233 { MaybeObject* maybe_flat = subject->TryFlatten();
2234 if (!maybe_flat->ToObject(&flat)) return maybe_flat;
2235 }
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002236 subject = String::cast(flat);
2237
2238 if (i >= static_cast<uint32_t>(subject->length())) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002239 return isolate->heap()->nan_value();
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00002240 }
2241
2242 return Smi::FromInt(subject->Get(i));
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002243}
2244
2245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00002246RUNTIME_FUNCTION(MaybeObject*, Runtime_CharFromCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002247 NoHandleAllocation ha;
2248 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002249 return CharFromCode(isolate, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00002250}
2251
lrn@chromium.org25156de2010-04-06 13:10:27 +00002252
2253class FixedArrayBuilder {
2254 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002255 explicit FixedArrayBuilder(Isolate* isolate, int initial_capacity)
2256 : array_(isolate->factory()->NewFixedArrayWithHoles(initial_capacity)),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002257 length_(0),
2258 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002259 // Require a non-zero initial size. Ensures that doubling the size to
2260 // extend the array will work.
2261 ASSERT(initial_capacity > 0);
2262 }
2263
2264 explicit FixedArrayBuilder(Handle<FixedArray> backing_store)
2265 : array_(backing_store),
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002266 length_(0),
2267 has_non_smi_elements_(false) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002268 // Require a non-zero initial size. Ensures that doubling the size to
2269 // extend the array will work.
2270 ASSERT(backing_store->length() > 0);
2271 }
2272
2273 bool HasCapacity(int elements) {
2274 int length = array_->length();
2275 int required_length = length_ + elements;
2276 return (length >= required_length);
2277 }
2278
2279 void EnsureCapacity(int elements) {
2280 int length = array_->length();
2281 int required_length = length_ + elements;
2282 if (length < required_length) {
2283 int new_length = length;
2284 do {
2285 new_length *= 2;
2286 } while (new_length < required_length);
2287 Handle<FixedArray> extended_array =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002288 array_->GetIsolate()->factory()->NewFixedArrayWithHoles(new_length);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002289 array_->CopyTo(0, *extended_array, 0, length_);
2290 array_ = extended_array;
2291 }
2292 }
2293
2294 void Add(Object* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002295 ASSERT(!value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002296 ASSERT(length_ < capacity());
2297 array_->set(length_, value);
2298 length_++;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002299 has_non_smi_elements_ = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002300 }
2301
2302 void Add(Smi* value) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002303 ASSERT(value->IsSmi());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002304 ASSERT(length_ < capacity());
2305 array_->set(length_, value);
2306 length_++;
2307 }
2308
2309 Handle<FixedArray> array() {
2310 return array_;
2311 }
2312
2313 int length() {
2314 return length_;
2315 }
2316
2317 int capacity() {
2318 return array_->length();
2319 }
2320
2321 Handle<JSArray> ToJSArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002322 Handle<JSArray> result_array = FACTORY->NewJSArrayWithElements(array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002323 result_array->set_length(Smi::FromInt(length_));
2324 return result_array;
2325 }
2326
2327 Handle<JSArray> ToJSArray(Handle<JSArray> target_array) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002328 FACTORY->SetContent(target_array, array_);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002329 target_array->set_length(Smi::FromInt(length_));
2330 return target_array;
2331 }
2332
2333 private:
2334 Handle<FixedArray> array_;
2335 int length_;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002336 bool has_non_smi_elements_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002337};
2338
2339
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002340// Forward declarations.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002341const int kStringBuilderConcatHelperLengthBits = 11;
2342const int kStringBuilderConcatHelperPositionBits = 19;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002343
2344template <typename schar>
2345static inline void StringBuilderConcatHelper(String*,
2346 schar*,
2347 FixedArray*,
2348 int);
2349
lrn@chromium.org25156de2010-04-06 13:10:27 +00002350typedef BitField<int, 0, kStringBuilderConcatHelperLengthBits>
2351 StringBuilderSubstringLength;
2352typedef BitField<int,
2353 kStringBuilderConcatHelperLengthBits,
2354 kStringBuilderConcatHelperPositionBits>
2355 StringBuilderSubstringPosition;
2356
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002357
2358class ReplacementStringBuilder {
2359 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002360 ReplacementStringBuilder(Heap* heap,
2361 Handle<String> subject,
2362 int estimated_part_count)
2363 : heap_(heap),
2364 array_builder_(heap->isolate(), estimated_part_count),
lrn@chromium.org25156de2010-04-06 13:10:27 +00002365 subject_(subject),
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002366 character_count_(0),
ager@chromium.org5ec48922009-05-05 07:25:34 +00002367 is_ascii_(subject->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002368 // Require a non-zero initial size. Ensures that doubling the size to
2369 // extend the array will work.
2370 ASSERT(estimated_part_count > 0);
2371 }
2372
lrn@chromium.org25156de2010-04-06 13:10:27 +00002373 static inline void AddSubjectSlice(FixedArrayBuilder* builder,
2374 int from,
2375 int to) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002376 ASSERT(from >= 0);
2377 int length = to - from;
2378 ASSERT(length > 0);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002379 if (StringBuilderSubstringLength::is_valid(length) &&
2380 StringBuilderSubstringPosition::is_valid(from)) {
2381 int encoded_slice = StringBuilderSubstringLength::encode(length) |
2382 StringBuilderSubstringPosition::encode(from);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002383 builder->Add(Smi::FromInt(encoded_slice));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002384 } else {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002385 // Otherwise encode as two smis.
lrn@chromium.org25156de2010-04-06 13:10:27 +00002386 builder->Add(Smi::FromInt(-length));
2387 builder->Add(Smi::FromInt(from));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002388 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00002389 }
2390
2391
2392 void EnsureCapacity(int elements) {
2393 array_builder_.EnsureCapacity(elements);
2394 }
2395
2396
2397 void AddSubjectSlice(int from, int to) {
2398 AddSubjectSlice(&array_builder_, from, to);
lrn@chromium.org25156de2010-04-06 13:10:27 +00002399 IncrementCharacterCount(to - from);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002400 }
2401
2402
2403 void AddString(Handle<String> string) {
2404 int length = string->length();
2405 ASSERT(length > 0);
2406 AddElement(*string);
ager@chromium.org5ec48922009-05-05 07:25:34 +00002407 if (!string->IsAsciiRepresentation()) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002408 is_ascii_ = false;
2409 }
2410 IncrementCharacterCount(length);
2411 }
2412
2413
2414 Handle<String> ToString() {
lrn@chromium.org25156de2010-04-06 13:10:27 +00002415 if (array_builder_.length() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002416 return heap_->isolate()->factory()->empty_string();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002417 }
2418
2419 Handle<String> joined_string;
2420 if (is_ascii_) {
ager@chromium.org04921a82011-06-27 13:21:41 +00002421 Handle<SeqAsciiString> seq = NewRawAsciiString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002422 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002423 char* char_buffer = seq->GetChars();
2424 StringBuilderConcatHelper(*subject_,
2425 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002426 *array_builder_.array(),
2427 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002428 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002429 } else {
2430 // Non-ASCII.
ager@chromium.org04921a82011-06-27 13:21:41 +00002431 Handle<SeqTwoByteString> seq = NewRawTwoByteString(character_count_);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002432 AssertNoAllocation no_alloc;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002433 uc16* char_buffer = seq->GetChars();
2434 StringBuilderConcatHelper(*subject_,
2435 char_buffer,
lrn@chromium.org25156de2010-04-06 13:10:27 +00002436 *array_builder_.array(),
2437 array_builder_.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00002438 joined_string = Handle<String>::cast(seq);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002439 }
2440 return joined_string;
2441 }
2442
2443
2444 void IncrementCharacterCount(int by) {
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00002445 if (character_count_ > String::kMaxLength - by) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002446 V8::FatalProcessOutOfMemory("String.replace result too large.");
2447 }
2448 character_count_ += by;
2449 }
2450
lrn@chromium.org25156de2010-04-06 13:10:27 +00002451 Handle<JSArray> GetParts() {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00002452 return array_builder_.ToJSArray();
lrn@chromium.org25156de2010-04-06 13:10:27 +00002453 }
kmillikin@chromium.orgd9825192010-03-30 08:36:16 +00002454
lrn@chromium.org25156de2010-04-06 13:10:27 +00002455 private:
ager@chromium.org04921a82011-06-27 13:21:41 +00002456 Handle<SeqAsciiString> NewRawAsciiString(int length) {
2457 return heap_->isolate()->factory()->NewRawAsciiString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002458 }
2459
2460
ager@chromium.org04921a82011-06-27 13:21:41 +00002461 Handle<SeqTwoByteString> NewRawTwoByteString(int length) {
2462 return heap_->isolate()->factory()->NewRawTwoByteString(length);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002463 }
2464
2465
2466 void AddElement(Object* element) {
2467 ASSERT(element->IsSmi() || element->IsString());
lrn@chromium.org25156de2010-04-06 13:10:27 +00002468 ASSERT(array_builder_.capacity() > array_builder_.length());
2469 array_builder_.Add(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002470 }
2471
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002472 Heap* heap_;
lrn@chromium.org25156de2010-04-06 13:10:27 +00002473 FixedArrayBuilder array_builder_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002474 Handle<String> subject_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002475 int character_count_;
2476 bool is_ascii_;
2477};
2478
2479
2480class CompiledReplacement {
2481 public:
2482 CompiledReplacement()
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002483 : parts_(1), replacement_substrings_(0), simple_hint_(false) {}
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002484
2485 void Compile(Handle<String> replacement,
2486 int capture_count,
2487 int subject_length);
2488
2489 void Apply(ReplacementStringBuilder* builder,
2490 int match_from,
2491 int match_to,
2492 Handle<JSArray> last_match_info);
2493
2494 // Number of distinct parts of the replacement pattern.
2495 int parts() {
2496 return parts_.length();
2497 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002498
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002499 bool simple_hint() {
2500 return simple_hint_;
2501 }
2502
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002503 private:
2504 enum PartType {
2505 SUBJECT_PREFIX = 1,
2506 SUBJECT_SUFFIX,
2507 SUBJECT_CAPTURE,
2508 REPLACEMENT_SUBSTRING,
2509 REPLACEMENT_STRING,
2510
2511 NUMBER_OF_PART_TYPES
2512 };
2513
2514 struct ReplacementPart {
2515 static inline ReplacementPart SubjectMatch() {
2516 return ReplacementPart(SUBJECT_CAPTURE, 0);
2517 }
2518 static inline ReplacementPart SubjectCapture(int capture_index) {
2519 return ReplacementPart(SUBJECT_CAPTURE, capture_index);
2520 }
2521 static inline ReplacementPart SubjectPrefix() {
2522 return ReplacementPart(SUBJECT_PREFIX, 0);
2523 }
2524 static inline ReplacementPart SubjectSuffix(int subject_length) {
2525 return ReplacementPart(SUBJECT_SUFFIX, subject_length);
2526 }
2527 static inline ReplacementPart ReplacementString() {
2528 return ReplacementPart(REPLACEMENT_STRING, 0);
2529 }
2530 static inline ReplacementPart ReplacementSubString(int from, int to) {
2531 ASSERT(from >= 0);
2532 ASSERT(to > from);
2533 return ReplacementPart(-from, to);
2534 }
2535
2536 // If tag <= 0 then it is the negation of a start index of a substring of
2537 // the replacement pattern, otherwise it's a value from PartType.
2538 ReplacementPart(int tag, int data)
2539 : tag(tag), data(data) {
2540 // Must be non-positive or a PartType value.
2541 ASSERT(tag < NUMBER_OF_PART_TYPES);
2542 }
2543 // Either a value of PartType or a non-positive number that is
2544 // the negation of an index into the replacement string.
2545 int tag;
2546 // The data value's interpretation depends on the value of tag:
2547 // tag == SUBJECT_PREFIX ||
2548 // tag == SUBJECT_SUFFIX: data is unused.
2549 // tag == SUBJECT_CAPTURE: data is the number of the capture.
2550 // tag == REPLACEMENT_SUBSTRING ||
2551 // tag == REPLACEMENT_STRING: data is index into array of substrings
2552 // of the replacement string.
2553 // tag <= 0: Temporary representation of the substring of the replacement
2554 // string ranging over -tag .. data.
2555 // Is replaced by REPLACEMENT_{SUB,}STRING when we create the
2556 // substring objects.
2557 int data;
2558 };
2559
2560 template<typename Char>
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002561 static bool ParseReplacementPattern(ZoneList<ReplacementPart>* parts,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002562 Vector<Char> characters,
2563 int capture_count,
2564 int subject_length) {
2565 int length = characters.length();
2566 int last = 0;
2567 for (int i = 0; i < length; i++) {
2568 Char c = characters[i];
2569 if (c == '$') {
2570 int next_index = i + 1;
2571 if (next_index == length) { // No next character!
2572 break;
2573 }
2574 Char c2 = characters[next_index];
2575 switch (c2) {
2576 case '$':
2577 if (i > last) {
2578 // There is a substring before. Include the first "$".
2579 parts->Add(ReplacementPart::ReplacementSubString(last, next_index));
2580 last = next_index + 1; // Continue after the second "$".
2581 } else {
2582 // Let the next substring start with the second "$".
2583 last = next_index;
2584 }
2585 i = next_index;
2586 break;
2587 case '`':
2588 if (i > last) {
2589 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2590 }
2591 parts->Add(ReplacementPart::SubjectPrefix());
2592 i = next_index;
2593 last = i + 1;
2594 break;
2595 case '\'':
2596 if (i > last) {
2597 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2598 }
2599 parts->Add(ReplacementPart::SubjectSuffix(subject_length));
2600 i = next_index;
2601 last = i + 1;
2602 break;
2603 case '&':
2604 if (i > last) {
2605 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2606 }
2607 parts->Add(ReplacementPart::SubjectMatch());
2608 i = next_index;
2609 last = i + 1;
2610 break;
2611 case '0':
2612 case '1':
2613 case '2':
2614 case '3':
2615 case '4':
2616 case '5':
2617 case '6':
2618 case '7':
2619 case '8':
2620 case '9': {
2621 int capture_ref = c2 - '0';
2622 if (capture_ref > capture_count) {
2623 i = next_index;
2624 continue;
2625 }
2626 int second_digit_index = next_index + 1;
2627 if (second_digit_index < length) {
2628 // Peek ahead to see if we have two digits.
2629 Char c3 = characters[second_digit_index];
2630 if ('0' <= c3 && c3 <= '9') { // Double digits.
2631 int double_digit_ref = capture_ref * 10 + c3 - '0';
2632 if (double_digit_ref <= capture_count) {
2633 next_index = second_digit_index;
2634 capture_ref = double_digit_ref;
2635 }
2636 }
2637 }
2638 if (capture_ref > 0) {
2639 if (i > last) {
2640 parts->Add(ReplacementPart::ReplacementSubString(last, i));
2641 }
kasperl@chromium.org71affb52009-05-26 05:44:31 +00002642 ASSERT(capture_ref <= capture_count);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002643 parts->Add(ReplacementPart::SubjectCapture(capture_ref));
2644 last = next_index + 1;
2645 }
2646 i = next_index;
2647 break;
2648 }
2649 default:
2650 i = next_index;
2651 break;
2652 }
2653 }
2654 }
2655 if (length > last) {
2656 if (last == 0) {
2657 parts->Add(ReplacementPart::ReplacementString());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002658 return true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002659 } else {
2660 parts->Add(ReplacementPart::ReplacementSubString(last, length));
2661 }
2662 }
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002663 return false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002664 }
2665
2666 ZoneList<ReplacementPart> parts_;
2667 ZoneList<Handle<String> > replacement_substrings_;
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002668 bool simple_hint_;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002669};
2670
2671
2672void CompiledReplacement::Compile(Handle<String> replacement,
2673 int capture_count,
2674 int subject_length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002675 {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002676 AssertNoAllocation no_alloc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002677 String::FlatContent content = replacement->GetFlatContent();
2678 ASSERT(content.IsFlat());
2679 if (content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002680 simple_hint_ = ParseReplacementPattern(&parts_,
2681 content.ToAsciiVector(),
2682 capture_count,
2683 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002684 } else {
2685 ASSERT(content.IsTwoByte());
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002686 simple_hint_ = ParseReplacementPattern(&parts_,
2687 content.ToUC16Vector(),
2688 capture_count,
2689 subject_length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00002690 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002691 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002692 Isolate* isolate = replacement->GetIsolate();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00002693 // Find substrings of replacement string and create them as String objects.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002694 int substring_index = 0;
2695 for (int i = 0, n = parts_.length(); i < n; i++) {
2696 int tag = parts_[i].tag;
2697 if (tag <= 0) { // A replacement string slice.
2698 int from = -tag;
2699 int to = parts_[i].data;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002700 replacement_substrings_.Add(
2701 isolate->factory()->NewSubString(replacement, from, to));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002702 parts_[i].tag = REPLACEMENT_SUBSTRING;
2703 parts_[i].data = substring_index;
2704 substring_index++;
2705 } else if (tag == REPLACEMENT_STRING) {
2706 replacement_substrings_.Add(replacement);
2707 parts_[i].data = substring_index;
2708 substring_index++;
2709 }
2710 }
2711}
2712
2713
2714void CompiledReplacement::Apply(ReplacementStringBuilder* builder,
2715 int match_from,
2716 int match_to,
2717 Handle<JSArray> last_match_info) {
2718 for (int i = 0, n = parts_.length(); i < n; i++) {
2719 ReplacementPart part = parts_[i];
2720 switch (part.tag) {
2721 case SUBJECT_PREFIX:
2722 if (match_from > 0) builder->AddSubjectSlice(0, match_from);
2723 break;
2724 case SUBJECT_SUFFIX: {
2725 int subject_length = part.data;
2726 if (match_to < subject_length) {
2727 builder->AddSubjectSlice(match_to, subject_length);
2728 }
2729 break;
2730 }
2731 case SUBJECT_CAPTURE: {
2732 int capture = part.data;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002733 FixedArray* match_info = FixedArray::cast(last_match_info->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002734 int from = RegExpImpl::GetCapture(match_info, capture * 2);
2735 int to = RegExpImpl::GetCapture(match_info, capture * 2 + 1);
2736 if (from >= 0 && to > from) {
2737 builder->AddSubjectSlice(from, to);
2738 }
2739 break;
2740 }
2741 case REPLACEMENT_SUBSTRING:
2742 case REPLACEMENT_STRING:
2743 builder->AddString(replacement_substrings_[part.data]);
2744 break;
2745 default:
2746 UNREACHABLE();
2747 }
2748 }
2749}
2750
2751
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002752void FindAsciiStringIndices(Vector<const char> subject,
2753 char pattern,
2754 ZoneList<int>* indices,
2755 unsigned int limit) {
2756 ASSERT(limit > 0);
2757 // Collect indices of pattern in subject using memchr.
2758 // Stop after finding at most limit values.
2759 const char* subject_start = reinterpret_cast<const char*>(subject.start());
2760 const char* subject_end = subject_start + subject.length();
2761 const char* pos = subject_start;
2762 while (limit > 0) {
2763 pos = reinterpret_cast<const char*>(
2764 memchr(pos, pattern, subject_end - pos));
2765 if (pos == NULL) return;
2766 indices->Add(static_cast<int>(pos - subject_start));
2767 pos++;
2768 limit--;
2769 }
2770}
2771
2772
2773template <typename SubjectChar, typename PatternChar>
2774void FindStringIndices(Isolate* isolate,
2775 Vector<const SubjectChar> subject,
2776 Vector<const PatternChar> pattern,
2777 ZoneList<int>* indices,
2778 unsigned int limit) {
2779 ASSERT(limit > 0);
2780 // Collect indices of pattern in subject.
2781 // Stop after finding at most limit values.
2782 int pattern_length = pattern.length();
2783 int index = 0;
2784 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
2785 while (limit > 0) {
2786 index = search.Search(subject, index);
2787 if (index < 0) return;
2788 indices->Add(index);
2789 index += pattern_length;
2790 limit--;
2791 }
2792}
2793
2794
2795void FindStringIndicesDispatch(Isolate* isolate,
2796 String* subject,
2797 String* pattern,
2798 ZoneList<int>* indices,
2799 unsigned int limit) {
2800 {
2801 AssertNoAllocation no_gc;
2802 String::FlatContent subject_content = subject->GetFlatContent();
2803 String::FlatContent pattern_content = pattern->GetFlatContent();
2804 ASSERT(subject_content.IsFlat());
2805 ASSERT(pattern_content.IsFlat());
2806 if (subject_content.IsAscii()) {
2807 Vector<const char> subject_vector = subject_content.ToAsciiVector();
2808 if (pattern_content.IsAscii()) {
2809 Vector<const char> pattern_vector = pattern_content.ToAsciiVector();
2810 if (pattern_vector.length() == 1) {
2811 FindAsciiStringIndices(subject_vector,
2812 pattern_vector[0],
2813 indices,
2814 limit);
2815 } else {
2816 FindStringIndices(isolate,
2817 subject_vector,
2818 pattern_vector,
2819 indices,
2820 limit);
2821 }
2822 } else {
2823 FindStringIndices(isolate,
2824 subject_vector,
2825 pattern_content.ToUC16Vector(),
2826 indices,
2827 limit);
2828 }
2829 } else {
2830 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002831 if (pattern_content.IsAscii()) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002832 FindStringIndices(isolate,
2833 subject_vector,
2834 pattern_content.ToAsciiVector(),
2835 indices,
2836 limit);
2837 } else {
2838 FindStringIndices(isolate,
2839 subject_vector,
2840 pattern_content.ToUC16Vector(),
2841 indices,
2842 limit);
2843 }
2844 }
2845 }
2846}
2847
2848
2849template<typename ResultSeqString>
2850MUST_USE_RESULT static MaybeObject* StringReplaceStringWithString(
2851 Isolate* isolate,
2852 Handle<String> subject,
2853 Handle<JSRegExp> pattern_regexp,
2854 Handle<String> replacement) {
2855 ASSERT(subject->IsFlat());
2856 ASSERT(replacement->IsFlat());
2857
2858 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
2859 ZoneList<int> indices(8);
2860 ASSERT_EQ(JSRegExp::ATOM, pattern_regexp->TypeTag());
2861 String* pattern =
2862 String::cast(pattern_regexp->DataAt(JSRegExp::kAtomPatternIndex));
2863 int subject_len = subject->length();
2864 int pattern_len = pattern->length();
2865 int replacement_len = replacement->length();
2866
2867 FindStringIndicesDispatch(isolate, *subject, pattern, &indices, 0xffffffff);
2868
2869 int matches = indices.length();
2870 if (matches == 0) return *subject;
2871
2872 int result_len = (replacement_len - pattern_len) * matches + subject_len;
2873 int subject_pos = 0;
2874 int result_pos = 0;
2875
2876 Handle<ResultSeqString> result;
2877 if (ResultSeqString::kHasAsciiEncoding) {
2878 result = Handle<ResultSeqString>::cast(
2879 isolate->factory()->NewRawAsciiString(result_len));
2880 } else {
2881 result = Handle<ResultSeqString>::cast(
2882 isolate->factory()->NewRawTwoByteString(result_len));
2883 }
2884
2885 for (int i = 0; i < matches; i++) {
2886 // Copy non-matched subject content.
2887 if (subject_pos < indices.at(i)) {
2888 String::WriteToFlat(*subject,
2889 result->GetChars() + result_pos,
2890 subject_pos,
2891 indices.at(i));
2892 result_pos += indices.at(i) - subject_pos;
2893 }
2894
2895 // Replace match.
2896 if (replacement_len > 0) {
2897 String::WriteToFlat(*replacement,
2898 result->GetChars() + result_pos,
2899 0,
2900 replacement_len);
2901 result_pos += replacement_len;
2902 }
2903
2904 subject_pos = indices.at(i) + pattern_len;
2905 }
2906 // Add remaining subject content at the end.
2907 if (subject_pos < subject_len) {
2908 String::WriteToFlat(*subject,
2909 result->GetChars() + result_pos,
2910 subject_pos,
2911 subject_len);
2912 }
2913 return *result;
2914}
2915
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002916
lrn@chromium.org303ada72010-10-27 09:33:13 +00002917MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002918 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00002919 String* subject,
2920 JSRegExp* regexp,
2921 String* replacement,
2922 JSArray* last_match_info) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002923 ASSERT(subject->IsFlat());
2924 ASSERT(replacement->IsFlat());
2925
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002926 HandleScope handles(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002927
2928 int length = subject->length();
2929 Handle<String> subject_handle(subject);
2930 Handle<JSRegExp> regexp_handle(regexp);
2931 Handle<String> replacement_handle(replacement);
2932 Handle<JSArray> last_match_info_handle(last_match_info);
2933 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
2934 subject_handle,
2935 0,
2936 last_match_info_handle);
2937 if (match.is_null()) {
2938 return Failure::Exception();
2939 }
2940 if (match->IsNull()) {
2941 return *subject_handle;
2942 }
2943
2944 int capture_count = regexp_handle->CaptureCount();
2945
2946 // CompiledReplacement uses zone allocation.
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00002947 ZoneScope zone(isolate, DELETE_ON_EXIT);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002948 CompiledReplacement compiled_replacement;
2949 compiled_replacement.Compile(replacement_handle,
2950 capture_count,
2951 length);
2952
2953 bool is_global = regexp_handle->GetFlags().is_global();
2954
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002955 // Shortcut for simple non-regexp global replacements
2956 if (is_global &&
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00002957 regexp_handle->TypeTag() == JSRegExp::ATOM &&
ricow@chromium.org55ee8072011-09-08 16:33:10 +00002958 compiled_replacement.simple_hint()) {
2959 if (subject_handle->HasOnlyAsciiChars() &&
2960 replacement_handle->HasOnlyAsciiChars()) {
2961 return StringReplaceStringWithString<SeqAsciiString>(
2962 isolate, subject_handle, regexp_handle, replacement_handle);
2963 } else {
2964 return StringReplaceStringWithString<SeqTwoByteString>(
2965 isolate, subject_handle, regexp_handle, replacement_handle);
2966 }
2967 }
2968
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002969 // Guessing the number of parts that the final result string is built
2970 // from. Global regexps can match any number of times, so we guess
2971 // conservatively.
2972 int expected_parts =
2973 (compiled_replacement.parts() + 1) * (is_global ? 4 : 1) + 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002974 ReplacementStringBuilder builder(isolate->heap(),
2975 subject_handle,
2976 expected_parts);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002977
2978 // Index of end of last match.
2979 int prev = 0;
2980
ager@chromium.org6141cbe2009-11-20 12:14:52 +00002981 // Number of parts added by compiled replacement plus preceeding
2982 // string and possibly suffix after last match. It is possible for
2983 // all components to use two elements when encoded as two smis.
2984 const int parts_added_per_loop = 2 * (compiled_replacement.parts() + 2);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002985 bool matched = true;
2986 do {
2987 ASSERT(last_match_info_handle->HasFastElements());
2988 // Increase the capacity of the builder before entering local handle-scope,
2989 // so its internal buffer can safely allocate a new handle if it grows.
2990 builder.EnsureCapacity(parts_added_per_loop);
2991
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00002992 HandleScope loop_scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002993 int start, end;
2994 {
2995 AssertNoAllocation match_info_array_is_not_in_a_handle;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00002996 FixedArray* match_info_array =
2997 FixedArray::cast(last_match_info_handle->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00002998
2999 ASSERT_EQ(capture_count * 2 + 2,
3000 RegExpImpl::GetLastCaptureCount(match_info_array));
3001 start = RegExpImpl::GetCapture(match_info_array, 0);
3002 end = RegExpImpl::GetCapture(match_info_array, 1);
3003 }
3004
3005 if (prev < start) {
3006 builder.AddSubjectSlice(prev, start);
3007 }
3008 compiled_replacement.Apply(&builder,
3009 start,
3010 end,
3011 last_match_info_handle);
3012 prev = end;
3013
3014 // Only continue checking for global regexps.
3015 if (!is_global) break;
3016
3017 // Continue from where the match ended, unless it was an empty match.
3018 int next = end;
3019 if (start == end) {
3020 next = end + 1;
3021 if (next > length) break;
3022 }
3023
3024 match = RegExpImpl::Exec(regexp_handle,
3025 subject_handle,
3026 next,
3027 last_match_info_handle);
3028 if (match.is_null()) {
3029 return Failure::Exception();
3030 }
3031 matched = !match->IsNull();
3032 } while (matched);
3033
3034 if (prev < length) {
3035 builder.AddSubjectSlice(prev, length);
3036 }
3037
3038 return *(builder.ToString());
3039}
3040
3041
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003042template <typename ResultSeqString>
lrn@chromium.org303ada72010-10-27 09:33:13 +00003043MUST_USE_RESULT static MaybeObject* StringReplaceRegExpWithEmptyString(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003044 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00003045 String* subject,
3046 JSRegExp* regexp,
3047 JSArray* last_match_info) {
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003048 ASSERT(subject->IsFlat());
3049
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003050 HandleScope handles(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003051
3052 Handle<String> subject_handle(subject);
3053 Handle<JSRegExp> regexp_handle(regexp);
ricow@chromium.org55ee8072011-09-08 16:33:10 +00003054
3055 // Shortcut for simple non-regexp global replacements
3056 if (regexp_handle->GetFlags().is_global() &&
3057 regexp_handle->TypeTag() == JSRegExp::ATOM) {
3058 Handle<String> empty_string_handle(HEAP->empty_string());
3059 if (subject_handle->HasOnlyAsciiChars()) {
3060 return StringReplaceStringWithString<SeqAsciiString>(
3061 isolate, subject_handle, regexp_handle, empty_string_handle);
3062 } else {
3063 return StringReplaceStringWithString<SeqTwoByteString>(
3064 isolate, subject_handle, regexp_handle, empty_string_handle);
3065 }
3066 }
3067
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003068 Handle<JSArray> last_match_info_handle(last_match_info);
3069 Handle<Object> match = RegExpImpl::Exec(regexp_handle,
3070 subject_handle,
3071 0,
3072 last_match_info_handle);
3073 if (match.is_null()) return Failure::Exception();
3074 if (match->IsNull()) return *subject_handle;
3075
3076 ASSERT(last_match_info_handle->HasFastElements());
3077
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003078 int start, end;
3079 {
3080 AssertNoAllocation match_info_array_is_not_in_a_handle;
3081 FixedArray* match_info_array =
3082 FixedArray::cast(last_match_info_handle->elements());
3083
3084 start = RegExpImpl::GetCapture(match_info_array, 0);
3085 end = RegExpImpl::GetCapture(match_info_array, 1);
3086 }
3087
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00003088 int length = subject_handle->length();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003089 int new_length = length - (end - start);
3090 if (new_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003091 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003092 }
3093 Handle<ResultSeqString> answer;
3094 if (ResultSeqString::kHasAsciiEncoding) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003095 answer = Handle<ResultSeqString>::cast(
3096 isolate->factory()->NewRawAsciiString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003097 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003098 answer = Handle<ResultSeqString>::cast(
3099 isolate->factory()->NewRawTwoByteString(new_length));
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003100 }
3101
3102 // If the regexp isn't global, only match once.
3103 if (!regexp_handle->GetFlags().is_global()) {
3104 if (start > 0) {
3105 String::WriteToFlat(*subject_handle,
3106 answer->GetChars(),
3107 0,
3108 start);
3109 }
3110 if (end < length) {
3111 String::WriteToFlat(*subject_handle,
3112 answer->GetChars() + start,
3113 end,
3114 length);
3115 }
3116 return *answer;
3117 }
3118
3119 int prev = 0; // Index of end of last match.
3120 int next = 0; // Start of next search (prev unless last match was empty).
3121 int position = 0;
3122
3123 do {
3124 if (prev < start) {
3125 // Add substring subject[prev;start] to answer string.
3126 String::WriteToFlat(*subject_handle,
3127 answer->GetChars() + position,
3128 prev,
3129 start);
3130 position += start - prev;
3131 }
3132 prev = end;
3133 next = end;
3134 // Continue from where the match ended, unless it was an empty match.
3135 if (start == end) {
3136 next++;
3137 if (next > length) break;
3138 }
3139 match = RegExpImpl::Exec(regexp_handle,
3140 subject_handle,
3141 next,
3142 last_match_info_handle);
3143 if (match.is_null()) return Failure::Exception();
3144 if (match->IsNull()) break;
3145
3146 ASSERT(last_match_info_handle->HasFastElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003147 HandleScope loop_scope(isolate);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003148 {
3149 AssertNoAllocation match_info_array_is_not_in_a_handle;
3150 FixedArray* match_info_array =
3151 FixedArray::cast(last_match_info_handle->elements());
3152 start = RegExpImpl::GetCapture(match_info_array, 0);
3153 end = RegExpImpl::GetCapture(match_info_array, 1);
3154 }
3155 } while (true);
3156
3157 if (prev < length) {
3158 // Add substring subject[prev;length] to answer string.
3159 String::WriteToFlat(*subject_handle,
3160 answer->GetChars() + position,
3161 prev,
3162 length);
3163 position += length - prev;
3164 }
3165
3166 if (position == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003167 return isolate->heap()->empty_string();
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003168 }
3169
3170 // Shorten string and fill
3171 int string_size = ResultSeqString::SizeFor(position);
3172 int allocated_string_size = ResultSeqString::SizeFor(new_length);
3173 int delta = allocated_string_size - string_size;
3174
3175 answer->set_length(position);
3176 if (delta == 0) return *answer;
3177
3178 Address end_of_string = answer->address() + string_size;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003179 isolate->heap()->CreateFillerObjectAt(end_of_string, delta);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003180 if (Marking::IsBlack(Marking::MarkBitFrom(*answer))) {
3181 MemoryChunk::IncrementLiveBytes(answer->address(), -delta);
3182 }
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003183
3184 return *answer;
3185}
3186
3187
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003188RUNTIME_FUNCTION(MaybeObject*, Runtime_StringReplaceRegExpWithString) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003189 ASSERT(args.length() == 4);
3190
3191 CONVERT_CHECKED(String, subject, args[0]);
3192 if (!subject->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003193 Object* flat_subject;
3194 { MaybeObject* maybe_flat_subject = subject->TryFlatten();
3195 if (!maybe_flat_subject->ToObject(&flat_subject)) {
3196 return maybe_flat_subject;
3197 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003198 }
3199 subject = String::cast(flat_subject);
3200 }
3201
3202 CONVERT_CHECKED(String, replacement, args[2]);
3203 if (!replacement->IsFlat()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00003204 Object* flat_replacement;
3205 { MaybeObject* maybe_flat_replacement = replacement->TryFlatten();
3206 if (!maybe_flat_replacement->ToObject(&flat_replacement)) {
3207 return maybe_flat_replacement;
3208 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003209 }
3210 replacement = String::cast(flat_replacement);
3211 }
3212
3213 CONVERT_CHECKED(JSRegExp, regexp, args[1]);
3214 CONVERT_CHECKED(JSArray, last_match_info, args[3]);
3215
3216 ASSERT(last_match_info->HasFastElements());
3217
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003218 if (replacement->length() == 0) {
3219 if (subject->HasOnlyAsciiChars()) {
3220 return StringReplaceRegExpWithEmptyString<SeqAsciiString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003221 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003222 } else {
3223 return StringReplaceRegExpWithEmptyString<SeqTwoByteString>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003224 isolate, subject, regexp, last_match_info);
erik.corry@gmail.com4a2e25e2010-07-07 12:22:46 +00003225 }
3226 }
3227
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003228 return StringReplaceRegExpWithString(isolate,
3229 subject,
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003230 regexp,
3231 replacement,
3232 last_match_info);
3233}
3234
3235
ager@chromium.org7c537e22008-10-16 08:43:32 +00003236// Perform string match of pattern on subject, starting at start index.
3237// Caller must ensure that 0 <= start_index <= sub->length(),
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003238// and should check that pat->length() + start_index <= sub->length().
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003239int Runtime::StringMatch(Isolate* isolate,
3240 Handle<String> sub,
ager@chromium.org7c537e22008-10-16 08:43:32 +00003241 Handle<String> pat,
3242 int start_index) {
3243 ASSERT(0 <= start_index);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003244 ASSERT(start_index <= sub->length());
ager@chromium.org7c537e22008-10-16 08:43:32 +00003245
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003246 int pattern_length = pat->length();
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003247 if (pattern_length == 0) return start_index;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003248
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003249 int subject_length = sub->length();
ager@chromium.org7c537e22008-10-16 08:43:32 +00003250 if (start_index + pattern_length > subject_length) return -1;
3251
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003252 if (!sub->IsFlat()) FlattenString(sub);
3253 if (!pat->IsFlat()) FlattenString(pat);
ager@chromium.org236ad962008-09-25 09:45:57 +00003254
ager@chromium.org7c537e22008-10-16 08:43:32 +00003255 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003256 // Extract flattened substrings of cons strings before determining asciiness.
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003257 String::FlatContent seq_sub = sub->GetFlatContent();
3258 String::FlatContent seq_pat = pat->GetFlatContent();
lrn@chromium.org32d961d2010-06-30 09:09:34 +00003259
ager@chromium.org7c537e22008-10-16 08:43:32 +00003260 // dispatch on type of strings
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003261 if (seq_pat.IsAscii()) {
3262 Vector<const char> pat_vector = seq_pat.ToAsciiVector();
3263 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003264 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003265 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003266 pat_vector,
3267 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003268 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003269 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003270 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003271 pat_vector,
3272 start_index);
ager@chromium.org236ad962008-09-25 09:45:57 +00003273 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003274 Vector<const uc16> pat_vector = seq_pat.ToUC16Vector();
3275 if (seq_sub.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003276 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003277 seq_sub.ToAsciiVector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003278 pat_vector,
3279 start_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003280 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003281 return SearchString(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003282 seq_sub.ToUC16Vector(),
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003283 pat_vector,
3284 start_index);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003285}
3286
3287
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003288RUNTIME_FUNCTION(MaybeObject*, Runtime_StringIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003289 HandleScope scope(isolate); // create a new handle scope
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003290 ASSERT(args.length() == 3);
3291
ager@chromium.org7c537e22008-10-16 08:43:32 +00003292 CONVERT_ARG_CHECKED(String, sub, 0);
3293 CONVERT_ARG_CHECKED(String, pat, 1);
3294
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003295 Object* index = args[2];
3296 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003297 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00003298
ager@chromium.org870a0b62008-11-04 11:43:05 +00003299 RUNTIME_ASSERT(start_index <= static_cast<uint32_t>(sub->length()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003300 int position =
3301 Runtime::StringMatch(isolate, sub, pat, start_index);
ager@chromium.org7c537e22008-10-16 08:43:32 +00003302 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003303}
3304
3305
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003306template <typename schar, typename pchar>
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003307static int StringMatchBackwards(Vector<const schar> subject,
3308 Vector<const pchar> pattern,
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003309 int idx) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003310 int pattern_length = pattern.length();
3311 ASSERT(pattern_length >= 1);
3312 ASSERT(idx + pattern_length <= subject.length());
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003313
3314 if (sizeof(schar) == 1 && sizeof(pchar) > 1) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003315 for (int i = 0; i < pattern_length; i++) {
3316 uc16 c = pattern[i];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003317 if (c > String::kMaxAsciiCharCode) {
3318 return -1;
3319 }
3320 }
3321 }
3322
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003323 pchar pattern_first_char = pattern[0];
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003324 for (int i = idx; i >= 0; i--) {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003325 if (subject[i] != pattern_first_char) continue;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003326 int j = 1;
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003327 while (j < pattern_length) {
3328 if (pattern[j] != subject[i+j]) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003329 break;
3330 }
3331 j++;
3332 }
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +00003333 if (j == pattern_length) {
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003334 return i;
3335 }
3336 }
3337 return -1;
3338}
3339
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003340RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLastIndexOf) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003341 HandleScope scope(isolate); // create a new handle scope
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003342 ASSERT(args.length() == 3);
3343
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003344 CONVERT_ARG_CHECKED(String, sub, 0);
3345 CONVERT_ARG_CHECKED(String, pat, 1);
3346
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003347 Object* index = args[2];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003348 uint32_t start_index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00003349 if (!index->ToArrayIndex(&start_index)) return Smi::FromInt(-1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003350
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003351 uint32_t pat_length = pat->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003352 uint32_t sub_length = sub->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003353
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003354 if (start_index + pat_length > sub_length) {
3355 start_index = sub_length - pat_length;
kasper.lundbd3ec4e2008-07-09 11:06:54 +00003356 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003357
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003358 if (pat_length == 0) {
3359 return Smi::FromInt(start_index);
3360 }
3361
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00003362 if (!sub->IsFlat()) FlattenString(sub);
3363 if (!pat->IsFlat()) FlattenString(pat);
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003364
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003365 int position = -1;
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003366 AssertNoAllocation no_heap_allocation; // ensure vectors stay valid
3367
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003368 String::FlatContent sub_content = sub->GetFlatContent();
3369 String::FlatContent pat_content = pat->GetFlatContent();
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003370
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003371 if (pat_content.IsAscii()) {
3372 Vector<const char> pat_vector = pat_content.ToAsciiVector();
3373 if (sub_content.IsAscii()) {
3374 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003375 pat_vector,
3376 start_index);
3377 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003378 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003379 pat_vector,
3380 start_index);
3381 }
3382 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003383 Vector<const uc16> pat_vector = pat_content.ToUC16Vector();
3384 if (sub_content.IsAscii()) {
3385 position = StringMatchBackwards(sub_content.ToAsciiVector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003386 pat_vector,
3387 start_index);
3388 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003389 position = StringMatchBackwards(sub_content.ToUC16Vector(),
fschneider@chromium.orgb95b98b2010-02-23 10:34:29 +00003390 pat_vector,
3391 start_index);
3392 }
3393 }
3394
3395 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003396}
3397
3398
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003399RUNTIME_FUNCTION(MaybeObject*, Runtime_StringLocaleCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003400 NoHandleAllocation ha;
3401 ASSERT(args.length() == 2);
3402
3403 CONVERT_CHECKED(String, str1, args[0]);
3404 CONVERT_CHECKED(String, str2, args[1]);
3405
3406 if (str1 == str2) return Smi::FromInt(0); // Equal.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003407 int str1_length = str1->length();
3408 int str2_length = str2->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003409
3410 // Decide trivial cases without flattening.
3411 if (str1_length == 0) {
3412 if (str2_length == 0) return Smi::FromInt(0); // Equal.
3413 return Smi::FromInt(-str2_length);
3414 } else {
3415 if (str2_length == 0) return Smi::FromInt(str1_length);
3416 }
3417
3418 int end = str1_length < str2_length ? str1_length : str2_length;
3419
3420 // No need to flatten if we are going to find the answer on the first
3421 // character. At this point we know there is at least one character
3422 // in each string, due to the trivial case handling above.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00003423 int d = str1->Get(0) - str2->Get(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003424 if (d != 0) return Smi::FromInt(d);
3425
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00003426 str1->TryFlatten();
3427 str2->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003428
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003429 StringInputBuffer& buf1 =
3430 *isolate->runtime_state()->string_locale_compare_buf1();
3431 StringInputBuffer& buf2 =
3432 *isolate->runtime_state()->string_locale_compare_buf2();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003433
3434 buf1.Reset(str1);
3435 buf2.Reset(str2);
3436
3437 for (int i = 0; i < end; i++) {
3438 uint16_t char1 = buf1.GetNext();
3439 uint16_t char2 = buf2.GetNext();
3440 if (char1 != char2) return Smi::FromInt(char1 - char2);
3441 }
3442
3443 return Smi::FromInt(str1_length - str2_length);
3444}
3445
3446
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003447RUNTIME_FUNCTION(MaybeObject*, Runtime_SubString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003448 NoHandleAllocation ha;
3449 ASSERT(args.length() == 3);
3450
3451 CONVERT_CHECKED(String, value, args[0]);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003452 int start, end;
3453 // We have a fast integer-only case here to avoid a conversion to double in
3454 // the common case where from and to are Smis.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003455 if (args[1]->IsSmi() && args[2]->IsSmi()) {
3456 CONVERT_SMI_ARG_CHECKED(from_number, 1);
3457 CONVERT_SMI_ARG_CHECKED(to_number, 2);
3458 start = from_number;
3459 end = to_number;
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003460 } else {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003461 CONVERT_DOUBLE_ARG_CHECKED(from_number, 1);
3462 CONVERT_DOUBLE_ARG_CHECKED(to_number, 2);
ager@chromium.org6141cbe2009-11-20 12:14:52 +00003463 start = FastD2I(from_number);
3464 end = FastD2I(to_number);
3465 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003466 RUNTIME_ASSERT(end >= start);
3467 RUNTIME_ASSERT(start >= 0);
ager@chromium.orgc3e50d82008-11-05 11:53:10 +00003468 RUNTIME_ASSERT(end <= value->length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003469 isolate->counters()->sub_string_runtime()->Increment();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00003470 return value->SubString(start, end);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003471}
3472
3473
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003474RUNTIME_FUNCTION(MaybeObject*, Runtime_StringMatch) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003475 ASSERT_EQ(3, args.length());
3476
3477 CONVERT_ARG_CHECKED(String, subject, 0);
3478 CONVERT_ARG_CHECKED(JSRegExp, regexp, 1);
3479 CONVERT_ARG_CHECKED(JSArray, regexp_info, 2);
3480 HandleScope handles;
3481
3482 Handle<Object> match = RegExpImpl::Exec(regexp, subject, 0, regexp_info);
3483
3484 if (match.is_null()) {
3485 return Failure::Exception();
3486 }
3487 if (match->IsNull()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003488 return isolate->heap()->null_value();
ager@chromium.org41826e72009-03-30 13:30:57 +00003489 }
3490 int length = subject->length();
3491
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00003492 ZoneScope zone_space(isolate, DELETE_ON_EXIT);
ager@chromium.org41826e72009-03-30 13:30:57 +00003493 ZoneList<int> offsets(8);
ager@chromium.org04921a82011-06-27 13:21:41 +00003494 int start;
3495 int end;
ager@chromium.org41826e72009-03-30 13:30:57 +00003496 do {
ager@chromium.org41826e72009-03-30 13:30:57 +00003497 {
3498 AssertNoAllocation no_alloc;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00003499 FixedArray* elements = FixedArray::cast(regexp_info->elements());
ager@chromium.org41826e72009-03-30 13:30:57 +00003500 start = Smi::cast(elements->get(RegExpImpl::kFirstCapture))->value();
3501 end = Smi::cast(elements->get(RegExpImpl::kFirstCapture + 1))->value();
3502 }
3503 offsets.Add(start);
3504 offsets.Add(end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003505 if (start == end) if (++end > length) break;
3506 match = RegExpImpl::Exec(regexp, subject, end, regexp_info);
ager@chromium.org41826e72009-03-30 13:30:57 +00003507 if (match.is_null()) {
3508 return Failure::Exception();
3509 }
3510 } while (!match->IsNull());
3511 int matches = offsets.length() / 2;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003512 Handle<FixedArray> elements = isolate->factory()->NewFixedArray(matches);
ager@chromium.org04921a82011-06-27 13:21:41 +00003513 Handle<String> substring = isolate->factory()->
3514 NewSubString(subject, offsets.at(0), offsets.at(1));
3515 elements->set(0, *substring);
3516 for (int i = 1; i < matches ; i++) {
ager@chromium.org41826e72009-03-30 13:30:57 +00003517 int from = offsets.at(i * 2);
3518 int to = offsets.at(i * 2 + 1);
ager@chromium.org04921a82011-06-27 13:21:41 +00003519 Handle<String> substring = isolate->factory()->
3520 NewProperSubString(subject, from, to);
3521 elements->set(i, *substring);
ager@chromium.org41826e72009-03-30 13:30:57 +00003522 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003523 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.org41826e72009-03-30 13:30:57 +00003524 result->set_length(Smi::FromInt(matches));
3525 return *result;
3526}
3527
3528
lrn@chromium.org25156de2010-04-06 13:10:27 +00003529// Two smis before and after the match, for very long strings.
3530const int kMaxBuilderEntriesPerRegExpMatch = 5;
3531
3532
3533static void SetLastMatchInfoNoCaptures(Handle<String> subject,
3534 Handle<JSArray> last_match_info,
3535 int match_start,
3536 int match_end) {
3537 // Fill last_match_info with a single capture.
3538 last_match_info->EnsureSize(2 + RegExpImpl::kLastMatchOverhead);
3539 AssertNoAllocation no_gc;
3540 FixedArray* elements = FixedArray::cast(last_match_info->elements());
3541 RegExpImpl::SetLastCaptureCount(elements, 2);
3542 RegExpImpl::SetLastInput(elements, *subject);
3543 RegExpImpl::SetLastSubject(elements, *subject);
3544 RegExpImpl::SetCapture(elements, 0, match_start);
3545 RegExpImpl::SetCapture(elements, 1, match_end);
3546}
3547
3548
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003549template <typename SubjectChar, typename PatternChar>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003550static bool SearchStringMultiple(Isolate* isolate,
3551 Vector<const SubjectChar> subject,
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003552 Vector<const PatternChar> pattern,
3553 String* pattern_string,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003554 FixedArrayBuilder* builder,
3555 int* match_pos) {
3556 int pos = *match_pos;
3557 int subject_length = subject.length();
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003558 int pattern_length = pattern.length();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003559 int max_search_start = subject_length - pattern_length;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003560 StringSearch<PatternChar, SubjectChar> search(isolate, pattern);
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003561 while (pos <= max_search_start) {
3562 if (!builder->HasCapacity(kMaxBuilderEntriesPerRegExpMatch)) {
3563 *match_pos = pos;
3564 return false;
3565 }
3566 // Position of end of previous match.
3567 int match_end = pos + pattern_length;
3568 int new_pos = search.Search(subject, match_end);
3569 if (new_pos >= 0) {
3570 // A match.
3571 if (new_pos > match_end) {
3572 ReplacementStringBuilder::AddSubjectSlice(builder,
3573 match_end,
3574 new_pos);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003575 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003576 pos = new_pos;
3577 builder->Add(pattern_string);
3578 } else {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003579 break;
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003580 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003581 }
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003582
lrn@chromium.org25156de2010-04-06 13:10:27 +00003583 if (pos < max_search_start) {
3584 ReplacementStringBuilder::AddSubjectSlice(builder,
3585 pos + pattern_length,
3586 subject_length);
3587 }
3588 *match_pos = pos;
3589 return true;
3590}
3591
3592
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003593static bool SearchStringMultiple(Isolate* isolate,
3594 Handle<String> subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003595 Handle<String> pattern,
3596 Handle<JSArray> last_match_info,
3597 FixedArrayBuilder* builder) {
3598 ASSERT(subject->IsFlat());
3599 ASSERT(pattern->IsFlat());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003600
3601 // Treating as if a previous match was before first character.
3602 int match_pos = -pattern->length();
3603
3604 for (;;) { // Break when search complete.
3605 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3606 AssertNoAllocation no_gc;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003607 String::FlatContent subject_content = subject->GetFlatContent();
3608 String::FlatContent pattern_content = pattern->GetFlatContent();
3609 if (subject_content.IsAscii()) {
3610 Vector<const char> subject_vector = subject_content.ToAsciiVector();
3611 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003612 if (SearchStringMultiple(isolate,
3613 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003614 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003615 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003616 builder,
3617 &match_pos)) break;
3618 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003619 if (SearchStringMultiple(isolate,
3620 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003621 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003622 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003623 builder,
3624 &match_pos)) break;
3625 }
3626 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003627 Vector<const uc16> subject_vector = subject_content.ToUC16Vector();
3628 if (pattern_content.IsAscii()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003629 if (SearchStringMultiple(isolate,
3630 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003631 pattern_content.ToAsciiVector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003632 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003633 builder,
3634 &match_pos)) break;
3635 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003636 if (SearchStringMultiple(isolate,
3637 subject_vector,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00003638 pattern_content.ToUC16Vector(),
kmillikin@chromium.orgf05f2912010-09-30 10:07:24 +00003639 *pattern,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003640 builder,
3641 &match_pos)) break;
3642 }
3643 }
3644 }
3645
3646 if (match_pos >= 0) {
3647 SetLastMatchInfoNoCaptures(subject,
3648 last_match_info,
3649 match_pos,
3650 match_pos + pattern->length());
3651 return true;
3652 }
3653 return false; // No matches at all.
3654}
3655
3656
3657static RegExpImpl::IrregexpResult SearchRegExpNoCaptureMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003658 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003659 Handle<String> subject,
3660 Handle<JSRegExp> regexp,
3661 Handle<JSArray> last_match_array,
3662 FixedArrayBuilder* builder) {
3663 ASSERT(subject->IsFlat());
3664 int match_start = -1;
3665 int match_end = 0;
3666 int pos = 0;
3667 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3668 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3669
3670 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003671 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003672 int subject_length = subject->length();
ager@chromium.org04921a82011-06-27 13:21:41 +00003673 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003674
3675 for (;;) { // Break on failure, return on exception.
3676 RegExpImpl::IrregexpResult result =
3677 RegExpImpl::IrregexpExecOnce(regexp,
3678 subject,
3679 pos,
3680 register_vector);
3681 if (result == RegExpImpl::RE_SUCCESS) {
3682 match_start = register_vector[0];
3683 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3684 if (match_end < match_start) {
3685 ReplacementStringBuilder::AddSubjectSlice(builder,
3686 match_end,
3687 match_start);
3688 }
3689 match_end = register_vector[1];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003690 HandleScope loop_scope(isolate);
ager@chromium.org04921a82011-06-27 13:21:41 +00003691 if (!first) {
3692 builder->Add(*isolate->factory()->NewProperSubString(subject,
3693 match_start,
3694 match_end));
3695 } else {
3696 builder->Add(*isolate->factory()->NewSubString(subject,
3697 match_start,
3698 match_end));
3699 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003700 if (match_start != match_end) {
3701 pos = match_end;
3702 } else {
3703 pos = match_end + 1;
3704 if (pos > subject_length) break;
3705 }
3706 } else if (result == RegExpImpl::RE_FAILURE) {
3707 break;
3708 } else {
3709 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3710 return result;
3711 }
ager@chromium.org04921a82011-06-27 13:21:41 +00003712 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003713 }
3714
3715 if (match_start >= 0) {
3716 if (match_end < subject_length) {
3717 ReplacementStringBuilder::AddSubjectSlice(builder,
3718 match_end,
3719 subject_length);
3720 }
3721 SetLastMatchInfoNoCaptures(subject,
3722 last_match_array,
3723 match_start,
3724 match_end);
3725 return RegExpImpl::RE_SUCCESS;
3726 } else {
3727 return RegExpImpl::RE_FAILURE; // No matches at all.
3728 }
3729}
3730
3731
3732static RegExpImpl::IrregexpResult SearchRegExpMultiple(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003733 Isolate* isolate,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003734 Handle<String> subject,
3735 Handle<JSRegExp> regexp,
3736 Handle<JSArray> last_match_array,
3737 FixedArrayBuilder* builder) {
3738
3739 ASSERT(subject->IsFlat());
3740 int required_registers = RegExpImpl::IrregexpPrepare(regexp, subject);
3741 if (required_registers < 0) return RegExpImpl::RE_EXCEPTION;
3742
3743 OffsetsVector registers(required_registers);
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003744 Vector<int32_t> register_vector(registers.vector(), registers.length());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003745
3746 RegExpImpl::IrregexpResult result =
3747 RegExpImpl::IrregexpExecOnce(regexp,
3748 subject,
3749 0,
3750 register_vector);
3751
3752 int capture_count = regexp->CaptureCount();
3753 int subject_length = subject->length();
3754
3755 // Position to search from.
3756 int pos = 0;
3757 // End of previous match. Differs from pos if match was empty.
3758 int match_end = 0;
3759 if (result == RegExpImpl::RE_SUCCESS) {
3760 // Need to keep a copy of the previous match for creating last_match_info
3761 // at the end, so we have two vectors that we swap between.
3762 OffsetsVector registers2(required_registers);
3763 Vector<int> prev_register_vector(registers2.vector(), registers2.length());
ager@chromium.org04921a82011-06-27 13:21:41 +00003764 bool first = true;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003765 do {
3766 int match_start = register_vector[0];
3767 builder->EnsureCapacity(kMaxBuilderEntriesPerRegExpMatch);
3768 if (match_end < match_start) {
3769 ReplacementStringBuilder::AddSubjectSlice(builder,
3770 match_end,
3771 match_start);
3772 }
3773 match_end = register_vector[1];
3774
3775 {
3776 // Avoid accumulating new handles inside loop.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003777 HandleScope temp_scope(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003778 // Arguments array to replace function is match, captures, index and
3779 // subject, i.e., 3 + capture count in total.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003780 Handle<FixedArray> elements =
3781 isolate->factory()->NewFixedArray(3 + capture_count);
ager@chromium.org04921a82011-06-27 13:21:41 +00003782 Handle<String> match;
3783 if (!first) {
3784 match = isolate->factory()->NewProperSubString(subject,
3785 match_start,
3786 match_end);
3787 } else {
3788 match = isolate->factory()->NewSubString(subject,
3789 match_start,
3790 match_end);
3791 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00003792 elements->set(0, *match);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003793 for (int i = 1; i <= capture_count; i++) {
3794 int start = register_vector[i * 2];
3795 if (start >= 0) {
3796 int end = register_vector[i * 2 + 1];
3797 ASSERT(start <= end);
ager@chromium.org04921a82011-06-27 13:21:41 +00003798 Handle<String> substring;
3799 if (!first) {
3800 substring = isolate->factory()->NewProperSubString(subject,
3801 start,
3802 end);
3803 } else {
3804 substring = isolate->factory()->NewSubString(subject, start, end);
3805 }
lrn@chromium.org25156de2010-04-06 13:10:27 +00003806 elements->set(i, *substring);
3807 } else {
3808 ASSERT(register_vector[i * 2 + 1] < 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003809 elements->set(i, isolate->heap()->undefined_value());
lrn@chromium.org25156de2010-04-06 13:10:27 +00003810 }
3811 }
3812 elements->set(capture_count + 1, Smi::FromInt(match_start));
3813 elements->set(capture_count + 2, *subject);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003814 builder->Add(*isolate->factory()->NewJSArrayWithElements(elements));
lrn@chromium.org25156de2010-04-06 13:10:27 +00003815 }
3816 // Swap register vectors, so the last successful match is in
3817 // prev_register_vector.
erik.corry@gmail.com145eff52010-08-23 11:36:18 +00003818 Vector<int32_t> tmp = prev_register_vector;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003819 prev_register_vector = register_vector;
3820 register_vector = tmp;
3821
3822 if (match_end > match_start) {
3823 pos = match_end;
3824 } else {
3825 pos = match_end + 1;
3826 if (pos > subject_length) {
3827 break;
3828 }
3829 }
3830
3831 result = RegExpImpl::IrregexpExecOnce(regexp,
3832 subject,
3833 pos,
3834 register_vector);
ager@chromium.org04921a82011-06-27 13:21:41 +00003835 first = false;
lrn@chromium.org25156de2010-04-06 13:10:27 +00003836 } while (result == RegExpImpl::RE_SUCCESS);
3837
3838 if (result != RegExpImpl::RE_EXCEPTION) {
3839 // Finished matching, with at least one match.
3840 if (match_end < subject_length) {
3841 ReplacementStringBuilder::AddSubjectSlice(builder,
3842 match_end,
3843 subject_length);
3844 }
3845
3846 int last_match_capture_count = (capture_count + 1) * 2;
3847 int last_match_array_size =
3848 last_match_capture_count + RegExpImpl::kLastMatchOverhead;
3849 last_match_array->EnsureSize(last_match_array_size);
3850 AssertNoAllocation no_gc;
3851 FixedArray* elements = FixedArray::cast(last_match_array->elements());
3852 RegExpImpl::SetLastCaptureCount(elements, last_match_capture_count);
3853 RegExpImpl::SetLastSubject(elements, *subject);
3854 RegExpImpl::SetLastInput(elements, *subject);
3855 for (int i = 0; i < last_match_capture_count; i++) {
3856 RegExpImpl::SetCapture(elements, i, prev_register_vector[i]);
3857 }
3858 return RegExpImpl::RE_SUCCESS;
3859 }
3860 }
3861 // No matches at all, return failure or exception result directly.
3862 return result;
3863}
3864
3865
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003866RUNTIME_FUNCTION(MaybeObject*, Runtime_RegExpExecMultiple) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003867 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003868 HandleScope handles(isolate);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003869
3870 CONVERT_ARG_CHECKED(String, subject, 1);
ricow@chromium.org4668a2c2011-08-29 10:41:00 +00003871 if (!subject->IsFlat()) FlattenString(subject);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003872 CONVERT_ARG_CHECKED(JSRegExp, regexp, 0);
3873 CONVERT_ARG_CHECKED(JSArray, last_match_info, 2);
3874 CONVERT_ARG_CHECKED(JSArray, result_array, 3);
3875
3876 ASSERT(last_match_info->HasFastElements());
3877 ASSERT(regexp->GetFlags().is_global());
3878 Handle<FixedArray> result_elements;
3879 if (result_array->HasFastElements()) {
3880 result_elements =
3881 Handle<FixedArray>(FixedArray::cast(result_array->elements()));
ager@chromium.org04921a82011-06-27 13:21:41 +00003882 }
3883 if (result_elements.is_null() || result_elements->length() < 16) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003884 result_elements = isolate->factory()->NewFixedArrayWithHoles(16);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003885 }
3886 FixedArrayBuilder builder(result_elements);
3887
3888 if (regexp->TypeTag() == JSRegExp::ATOM) {
3889 Handle<String> pattern(
3890 String::cast(regexp->DataAt(JSRegExp::kAtomPatternIndex)));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00003891 ASSERT(pattern->IsFlat());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003892 if (SearchStringMultiple(isolate, subject, pattern,
3893 last_match_info, &builder)) {
lrn@chromium.org25156de2010-04-06 13:10:27 +00003894 return *builder.ToJSArray(result_array);
3895 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003896 return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003897 }
3898
3899 ASSERT_EQ(regexp->TypeTag(), JSRegExp::IRREGEXP);
3900
3901 RegExpImpl::IrregexpResult result;
3902 if (regexp->CaptureCount() == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003903 result = SearchRegExpNoCaptureMultiple(isolate,
3904 subject,
lrn@chromium.org25156de2010-04-06 13:10:27 +00003905 regexp,
3906 last_match_info,
3907 &builder);
3908 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003909 result = SearchRegExpMultiple(isolate,
3910 subject,
3911 regexp,
3912 last_match_info,
3913 &builder);
lrn@chromium.org25156de2010-04-06 13:10:27 +00003914 }
3915 if (result == RegExpImpl::RE_SUCCESS) return *builder.ToJSArray(result_array);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003916 if (result == RegExpImpl::RE_FAILURE) return isolate->heap()->null_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00003917 ASSERT_EQ(result, RegExpImpl::RE_EXCEPTION);
3918 return Failure::Exception();
3919}
3920
3921
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003922RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToRadixString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003923 NoHandleAllocation ha;
3924 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003925 CONVERT_SMI_ARG_CHECKED(radix, 1);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003926 RUNTIME_ASSERT(2 <= radix && radix <= 36);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003927
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003928 // Fast case where the result is a one character string.
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00003929 if (args[0]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003930 int value = args.smi_at(0);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003931 if (value >= 0 && value < radix) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003932 // Character array used for conversion.
3933 static const char kCharTable[] = "0123456789abcdefghijklmnopqrstuvwxyz";
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003934 return isolate->heap()->
3935 LookupSingleCharacterStringFromCode(kCharTable[value]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +00003936 }
3937 }
3938
3939 // Slow case.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003940 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003941 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003942 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003943 }
3944 if (isinf(value)) {
3945 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003946 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003947 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003948 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003949 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003950 char* str = DoubleToRadixCString(value, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003951 MaybeObject* result =
3952 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003953 DeleteArray(str);
3954 return result;
3955}
3956
3957
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003958RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToFixed) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003959 NoHandleAllocation ha;
3960 ASSERT(args.length() == 2);
3961
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003962 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003963 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003964 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003965 }
3966 if (isinf(value)) {
3967 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003968 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003969 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003970 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003971 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003972 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003973 int f = FastD2I(f_number);
3974 RUNTIME_ASSERT(f >= 0);
3975 char* str = DoubleToFixedCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003976 MaybeObject* res =
3977 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003978 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00003979 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003980}
3981
3982
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00003983RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToExponential) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003984 NoHandleAllocation ha;
3985 ASSERT(args.length() == 2);
3986
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003987 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003988 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003989 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003990 }
3991 if (isinf(value)) {
3992 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003993 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003994 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00003995 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003996 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00003997 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00003998 int f = FastD2I(f_number);
3999 RUNTIME_ASSERT(f >= -1 && f <= 20);
4000 char* str = DoubleToExponentialCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004001 MaybeObject* res =
4002 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004003 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004004 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004005}
4006
4007
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004008RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToPrecision) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004009 NoHandleAllocation ha;
4010 ASSERT(args.length() == 2);
4011
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004012 CONVERT_DOUBLE_ARG_CHECKED(value, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004013 if (isnan(value)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004014 return *isolate->factory()->nan_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004015 }
4016 if (isinf(value)) {
4017 if (value < 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004018 return *isolate->factory()->minus_infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004019 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004020 return *isolate->factory()->infinity_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004021 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004022 CONVERT_DOUBLE_ARG_CHECKED(f_number, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004023 int f = FastD2I(f_number);
4024 RUNTIME_ASSERT(f >= 1 && f <= 21);
4025 char* str = DoubleToPrecisionCString(value, f);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004026 MaybeObject* res =
4027 isolate->heap()->AllocateStringFromAscii(CStrVector(str));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004028 DeleteArray(str);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004029 return res;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004030}
4031
4032
4033// Returns a single character string where first character equals
4034// string->Get(index).
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004035static Handle<Object> GetCharAt(Handle<String> string, uint32_t index) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004036 if (index < static_cast<uint32_t>(string->length())) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004037 string->TryFlatten();
ager@chromium.org870a0b62008-11-04 11:43:05 +00004038 return LookupSingleCharacterStringFromCode(
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00004039 string->Get(index));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004040 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004041 return Execution::CharAt(string, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004042}
4043
4044
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004045MaybeObject* Runtime::GetElementOrCharAt(Isolate* isolate,
4046 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004047 uint32_t index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004048 // Handle [] indexing on Strings
4049 if (object->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004050 Handle<Object> result = GetCharAt(Handle<String>::cast(object), index);
4051 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004052 }
4053
4054 // Handle [] indexing on String objects
4055 if (object->IsStringObjectWithCharacterAt(index)) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004056 Handle<JSValue> js_value = Handle<JSValue>::cast(object);
4057 Handle<Object> result =
4058 GetCharAt(Handle<String>(String::cast(js_value->value())), index);
4059 if (!result->IsUndefined()) return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004060 }
4061
4062 if (object->IsString() || object->IsNumber() || object->IsBoolean()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004063 return object->GetPrototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004064 }
4065
4066 return object->GetElement(index);
4067}
4068
4069
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004070MaybeObject* Runtime::GetObjectProperty(Isolate* isolate,
4071 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004072 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004073 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004074
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004075 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004076 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004077 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004078 isolate->factory()->NewTypeError("non_object_property_load",
4079 HandleVector(args, 2));
4080 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004081 }
4082
4083 // Check if the given key is an array index.
4084 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004085 if (key->ToArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004086 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004087 }
4088
4089 // Convert the key to a string - possibly by calling back into JavaScript.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004090 Handle<String> name;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004091 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004092 name = Handle<String>::cast(key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004093 } else {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004094 bool has_pending_exception = false;
4095 Handle<Object> converted =
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004096 Execution::ToString(key, &has_pending_exception);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004097 if (has_pending_exception) return Failure::Exception();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004098 name = Handle<String>::cast(converted);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004099 }
4100
ager@chromium.org32912102009-01-16 10:38:43 +00004101 // Check if the name is trivially convertible to an index and get
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004102 // the element if so.
4103 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004104 return GetElementOrCharAt(isolate, object, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004105 } else {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004106 return object->GetProperty(*name);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004107 }
4108}
4109
4110
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004111RUNTIME_FUNCTION(MaybeObject*, Runtime_GetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004112 NoHandleAllocation ha;
4113 ASSERT(args.length() == 2);
4114
4115 Handle<Object> object = args.at<Object>(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004116 Handle<Object> key = args.at<Object>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004117
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004118 return Runtime::GetObjectProperty(isolate, object, key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004119}
4120
4121
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004122MaybeObject* TransitionElements(Handle<Object> object,
4123 ElementsKind to_kind,
4124 Isolate* isolate) {
4125 HandleScope scope(isolate);
4126 if (!object->IsJSObject()) return isolate->ThrowIllegalOperation();
4127 ElementsKind from_kind =
4128 Handle<JSObject>::cast(object)->map()->elements_kind();
4129 if (Map::IsValidElementsTransition(from_kind, to_kind)) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004130 Handle<Object> result = JSObject::TransitionElementsKind(
4131 Handle<JSObject>::cast(object), to_kind);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004132 if (result.is_null()) return isolate->ThrowIllegalOperation();
4133 return *result;
4134 }
4135 return isolate->ThrowIllegalOperation();
4136}
4137
4138
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004139// KeyedStringGetProperty is called from KeyedLoadIC::GenerateGeneric.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004140RUNTIME_FUNCTION(MaybeObject*, Runtime_KeyedGetProperty) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00004141 NoHandleAllocation ha;
4142 ASSERT(args.length() == 2);
4143
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004144 // Fast cases for getting named properties of the receiver JSObject
ager@chromium.org8bb60582008-12-11 12:02:20 +00004145 // itself.
4146 //
4147 // The global proxy objects has to be excluded since LocalLookup on
ager@chromium.org32912102009-01-16 10:38:43 +00004148 // the global proxy object can return a valid result even though the
ager@chromium.org8bb60582008-12-11 12:02:20 +00004149 // global proxy object never has properties. This is the case
4150 // because the global proxy object forwards everything to its hidden
4151 // prototype including local lookups.
4152 //
4153 // Additionally, we need to make sure that we do not cache results
4154 // for objects that require access checks.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004155 if (args[0]->IsJSObject()) {
4156 if (!args[0]->IsJSGlobalProxy() &&
4157 !args[0]->IsAccessCheckNeeded() &&
4158 args[1]->IsString()) {
4159 JSObject* receiver = JSObject::cast(args[0]);
4160 String* key = String::cast(args[1]);
4161 if (receiver->HasFastProperties()) {
4162 // Attempt to use lookup cache.
4163 Map* receiver_map = receiver->map();
4164 KeyedLookupCache* keyed_lookup_cache = isolate->keyed_lookup_cache();
4165 int offset = keyed_lookup_cache->Lookup(receiver_map, key);
4166 if (offset != -1) {
4167 Object* value = receiver->FastPropertyAt(offset);
4168 return value->IsTheHole()
4169 ? isolate->heap()->undefined_value()
4170 : value;
4171 }
4172 // Lookup cache miss. Perform lookup and update the cache if
4173 // appropriate.
4174 LookupResult result(isolate);
4175 receiver->LocalLookup(key, &result);
4176 if (result.IsProperty() && result.type() == FIELD) {
4177 int offset = result.GetFieldIndex();
4178 keyed_lookup_cache->Update(receiver_map, key, offset);
4179 return receiver->FastPropertyAt(offset);
4180 }
4181 } else {
4182 // Attempt dictionary lookup.
4183 StringDictionary* dictionary = receiver->property_dictionary();
4184 int entry = dictionary->FindEntry(key);
4185 if ((entry != StringDictionary::kNotFound) &&
4186 (dictionary->DetailsAt(entry).type() == NORMAL)) {
4187 Object* value = dictionary->ValueAt(entry);
4188 if (!receiver->IsGlobalObject()) return value;
4189 value = JSGlobalPropertyCell::cast(value)->value();
4190 if (!value->IsTheHole()) return value;
4191 // If value is the hole do the general lookup.
4192 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004193 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004194 } else if (FLAG_smi_only_arrays && args.at<Object>(1)->IsSmi()) {
4195 // JSObject without a string key. If the key is a Smi, check for a
4196 // definite out-of-bounds access to elements, which is a strong indicator
4197 // that subsequent accesses will also call the runtime. Proactively
4198 // transition elements to FAST_ELEMENTS to avoid excessive boxing of
4199 // doubles for those future calls in the case that the elements would
4200 // become FAST_DOUBLE_ELEMENTS.
4201 Handle<JSObject> js_object(args.at<JSObject>(0));
4202 ElementsKind elements_kind = js_object->GetElementsKind();
4203 if (elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4204 elements_kind == FAST_DOUBLE_ELEMENTS) {
4205 FixedArrayBase* elements = js_object->elements();
4206 if (args.at<Smi>(1)->value() >= elements->length()) {
4207 MaybeObject* maybe_object = TransitionElements(js_object,
4208 FAST_ELEMENTS,
4209 isolate);
4210 if (maybe_object->IsFailure()) return maybe_object;
4211 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004212 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004213 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004214 } else if (args[0]->IsString() && args[1]->IsSmi()) {
4215 // Fast case for string indexing using [] with a smi index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004216 HandleScope scope(isolate);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00004217 Handle<String> str = args.at<String>(0);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004218 int index = args.smi_at(1);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004219 if (index >= 0 && index < str->length()) {
4220 Handle<Object> result = GetCharAt(str, index);
4221 return *result;
4222 }
ager@chromium.org7c537e22008-10-16 08:43:32 +00004223 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00004224
4225 // Fall back to GetObjectProperty.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004226 return Runtime::GetObjectProperty(isolate,
4227 args.at<Object>(0),
ager@chromium.org7c537e22008-10-16 08:43:32 +00004228 args.at<Object>(1));
4229}
4230
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004231// Implements part of 8.12.9 DefineOwnProperty.
4232// There are 3 cases that lead here:
4233// Step 4b - define a new accessor property.
4234// Steps 9c & 12 - replace an existing data property with an accessor property.
4235// Step 12 - update an existing accessor property with an accessor or generic
4236// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004237RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineAccessorProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004238 ASSERT(args.length() == 5);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004239 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004240 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4241 CONVERT_CHECKED(String, name, args[1]);
4242 CONVERT_CHECKED(Smi, flag_setter, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004243 Object* fun = args[3];
ager@chromium.org5c838252010-02-19 08:53:10 +00004244 CONVERT_CHECKED(Smi, flag_attr, args[4]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004245
ager@chromium.org5c838252010-02-19 08:53:10 +00004246 int unchecked = flag_attr->value();
4247 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004248 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004249
4250 RUNTIME_ASSERT(!obj->IsNull());
4251 RUNTIME_ASSERT(fun->IsSpecFunction() || fun->IsUndefined());
ager@chromium.org5c838252010-02-19 08:53:10 +00004252 return obj->DefineAccessor(name, flag_setter->value() == 0, fun, attr);
4253}
4254
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004255// Implements part of 8.12.9 DefineOwnProperty.
4256// There are 3 cases that lead here:
4257// Step 4a - define a new data property.
4258// Steps 9b & 12 - replace an existing accessor property with a data property.
4259// Step 12 - update an existing data property with a data or generic
4260// descriptor.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004261RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineOrRedefineDataProperty) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004262 ASSERT(args.length() == 4);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004263 HandleScope scope(isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00004264 CONVERT_ARG_CHECKED(JSObject, js_object, 0);
4265 CONVERT_ARG_CHECKED(String, name, 1);
4266 Handle<Object> obj_value = args.at<Object>(2);
ager@chromium.org5c838252010-02-19 08:53:10 +00004267 CONVERT_CHECKED(Smi, flag, args[3]);
ricow@chromium.org7ad65222011-12-19 12:13:11 +00004268
ager@chromium.org5c838252010-02-19 08:53:10 +00004269 int unchecked = flag->value();
4270 RUNTIME_ASSERT((unchecked & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004271 PropertyAttributes attr = static_cast<PropertyAttributes>(unchecked);
4272
4273 // Check if this is an element.
4274 uint32_t index;
4275 bool is_element = name->AsArrayIndex(&index);
4276
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004277 // Special case for elements if any of the flags might be involved.
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004278 // If elements are in fast case we always implicitly assume that:
4279 // DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004280 if (is_element && (attr != NONE ||
4281 js_object->HasLocalElement(index) == JSObject::DICTIONARY_ELEMENT)) {
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004282 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004283 if (js_object->IsJSGlobalProxy()) {
fschneider@chromium.org3a5fd782011-02-24 10:10:44 +00004284 // We do not need to do access checks here since these has already
4285 // been performed by the call to GetOwnProperty.
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004286 Handle<Object> proto(js_object->GetPrototype());
4287 // If proxy is detached, ignore the assignment. Alternatively,
4288 // we could throw an exception.
4289 if (proto->IsNull()) return *obj_value;
4290 js_object = Handle<JSObject>::cast(proto);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004291 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004292
4293 // Don't allow element properties to be redefined on objects with external
4294 // array elements.
4295 if (js_object->HasExternalArrayElements()) {
4296 Handle<Object> args[2] = { js_object, name };
4297 Handle<Object> error =
4298 isolate->factory()->NewTypeError("redef_external_array_element",
4299 HandleVector(args, 2));
4300 return isolate->Throw(*error);
4301 }
4302
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004303 Handle<SeededNumberDictionary> dictionary =
4304 JSObject::NormalizeElements(js_object);
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004305 // Make sure that we never go back to fast case.
4306 dictionary->set_requires_slow_elements();
4307 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004308 Handle<SeededNumberDictionary> extended_dictionary =
4309 SeededNumberDictionary::Set(dictionary, index, obj_value, details);
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004310 if (*extended_dictionary != *dictionary) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00004311 if (js_object->GetElementsKind() == NON_STRICT_ARGUMENTS_ELEMENTS) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +00004312 FixedArray::cast(js_object->elements())->set(1, *extended_dictionary);
4313 } else {
4314 js_object->set_elements(*extended_dictionary);
4315 }
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00004316 }
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004317 return *obj_value;
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004318 }
4319
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004320 LookupResult result(isolate);
whesse@chromium.org7b260152011-06-20 15:33:18 +00004321 js_object->LocalLookupRealNamedProperty(*name, &result);
ager@chromium.org5c838252010-02-19 08:53:10 +00004322
danno@chromium.orge78f9fc2011-12-21 08:29:34 +00004323 // Special case for callback properties.
4324 if (result.IsProperty() && result.type() == CALLBACKS) {
4325 Object* callback = result.GetCallbackObject();
4326 // To be compatible with Safari we do not change the value on API objects
4327 // in Object.defineProperty(). Firefox disagrees here, and actually changes
4328 // the value.
4329 if (callback->IsAccessorInfo()) {
4330 return isolate->heap()->undefined_value();
4331 }
4332 // Avoid redefining foreign callback as data property, just use the stored
4333 // setter to update the value instead.
4334 // TODO(mstarzinger): So far this only works if property attributes don't
4335 // change, this should be fixed once we cleanup the underlying code.
4336 if (callback->IsForeign() && result.GetAttributes() == attr) {
4337 return js_object->SetPropertyWithCallback(callback,
4338 *name,
4339 *obj_value,
4340 result.holder(),
4341 kStrictMode);
4342 }
ricow@chromium.orgf5a18a22011-03-15 10:00:20 +00004343 }
4344
ager@chromium.org5c838252010-02-19 08:53:10 +00004345 // Take special care when attributes are different and there is already
4346 // a property. For simplicity we normalize the property which enables us
4347 // to not worry about changing the instance_descriptor and creating a new
4348 // map. The current version of SetObjectProperty does not handle attributes
4349 // correctly in the case where a property is a field and is reset with
4350 // new attributes.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00004351 if (result.IsProperty() &&
4352 (attr != result.GetAttributes() || result.type() == CALLBACKS)) {
ager@chromium.org5c838252010-02-19 08:53:10 +00004353 // New attributes - normalize to avoid writing to instance descriptor
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00004354 if (js_object->IsJSGlobalProxy()) {
4355 // Since the result is a property, the prototype will exist so
4356 // we don't have to check for null.
4357 js_object = Handle<JSObject>(JSObject::cast(js_object->GetPrototype()));
ricow@chromium.org83aa5492011-02-07 12:42:56 +00004358 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004359 JSObject::NormalizeProperties(js_object, CLEAR_INOBJECT_PROPERTIES, 0);
ager@chromium.org5c838252010-02-19 08:53:10 +00004360 // Use IgnoreAttributes version since a readonly property may be
4361 // overridden and SetProperty does not allow this.
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004362 return js_object->SetLocalPropertyIgnoreAttributes(*name,
4363 *obj_value,
4364 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004365 }
whesse@chromium.org2c186ca2010-06-16 11:32:39 +00004366
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004367 return Runtime::ForceSetObjectProperty(isolate,
4368 js_object,
4369 name,
4370 obj_value,
4371 attr);
ager@chromium.org5c838252010-02-19 08:53:10 +00004372}
4373
4374
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004375// Special case for elements if any of the flags are true.
4376// If elements are in fast case we always implicitly assume that:
4377// DONT_DELETE: false, DONT_ENUM: false, READ_ONLY: false.
4378static MaybeObject* NormalizeObjectSetElement(Isolate* isolate,
4379 Handle<JSObject> js_object,
4380 uint32_t index,
4381 Handle<Object> value,
4382 PropertyAttributes attr) {
4383 // Normalize the elements to enable attributes on the property.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004384 Handle<SeededNumberDictionary> dictionary =
4385 JSObject::NormalizeElements(js_object);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004386 // Make sure that we never go back to fast case.
4387 dictionary->set_requires_slow_elements();
4388 PropertyDetails details = PropertyDetails(attr, NORMAL);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004389 Handle<SeededNumberDictionary> extended_dictionary =
4390 SeededNumberDictionary::Set(dictionary, index, value, details);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004391 if (*extended_dictionary != *dictionary) {
4392 js_object->set_elements(*extended_dictionary);
4393 }
4394 return *value;
4395}
4396
4397
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004398MaybeObject* Runtime::SetObjectProperty(Isolate* isolate,
4399 Handle<Object> object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004400 Handle<Object> key,
4401 Handle<Object> value,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004402 PropertyAttributes attr,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004403 StrictModeFlag strict_mode) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004404 HandleScope scope(isolate);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004405
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004406 if (object->IsUndefined() || object->IsNull()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004407 Handle<Object> args[2] = { key, object };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004408 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004409 isolate->factory()->NewTypeError("non_object_property_store",
4410 HandleVector(args, 2));
4411 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004412 }
4413
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004414 if (object->IsJSProxy()) {
4415 bool has_pending_exception = false;
4416 Handle<Object> name = Execution::ToString(key, &has_pending_exception);
4417 if (has_pending_exception) return Failure::Exception();
4418 return JSProxy::cast(*object)->SetProperty(
4419 String::cast(*name), *value, attr, strict_mode);
4420 }
4421
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004422 // If the object isn't a JavaScript object, we ignore the store.
4423 if (!object->IsJSObject()) return *value;
4424
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004425 Handle<JSObject> js_object = Handle<JSObject>::cast(object);
4426
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004427 // Check if the given key is an array index.
4428 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004429 if (key->ToArrayIndex(&index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004430 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4431 // of a string using [] notation. We need to support this too in
4432 // JavaScript.
4433 // In the case of a String object we just need to redirect the assignment to
4434 // the underlying string if the index is in range. Since the underlying
4435 // string does nothing with the assignment then we can ignore such
4436 // assignments.
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004437 if (js_object->IsStringObjectWithCharacterAt(index)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004438 return *value;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004439 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004440
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004441 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4442 return NormalizeObjectSetElement(isolate, js_object, index, value, attr);
4443 }
4444
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004445 Handle<Object> result =
4446 JSObject::SetElement(js_object, index, value, strict_mode);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004447 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004448 return *value;
4449 }
4450
4451 if (key->IsString()) {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004452 Handle<Object> result;
4453 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004454 if (((attr & (DONT_DELETE | DONT_ENUM | READ_ONLY)) != 0)) {
4455 return NormalizeObjectSetElement(isolate,
4456 js_object,
4457 index,
4458 value,
4459 attr);
4460 }
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004461 result =
4462 JSObject::SetElement(js_object, index, value, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004463 } else {
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004464 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004465 key_string->TryFlatten();
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004466 result = JSReceiver::SetProperty(
4467 js_object, key_string, value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004468 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00004469 if (result.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004470 return *value;
4471 }
4472
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004473 // Call-back into JavaScript to convert the key to a string.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004474 bool has_pending_exception = false;
4475 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4476 if (has_pending_exception) return Failure::Exception();
4477 Handle<String> name = Handle<String>::cast(converted);
4478
4479 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004480 return js_object->SetElement(index, *value, strict_mode, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004481 } else {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004482 return js_object->SetProperty(*name, *value, attr, strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004483 }
4484}
4485
4486
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004487MaybeObject* Runtime::ForceSetObjectProperty(Isolate* isolate,
4488 Handle<JSObject> js_object,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004489 Handle<Object> key,
4490 Handle<Object> value,
4491 PropertyAttributes attr) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004492 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004493
4494 // Check if the given key is an array index.
4495 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00004496 if (key->ToArrayIndex(&index)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004497 // In Firefox/SpiderMonkey, Safari and Opera you can access the characters
4498 // of a string using [] notation. We need to support this too in
4499 // JavaScript.
4500 // In the case of a String object we just need to redirect the assignment to
4501 // the underlying string if the index is in range. Since the underlying
4502 // string does nothing with the assignment then we can ignore such
4503 // assignments.
4504 if (js_object->IsStringObjectWithCharacterAt(index)) {
4505 return *value;
4506 }
4507
whesse@chromium.org7b260152011-06-20 15:33:18 +00004508 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004509 }
4510
4511 if (key->IsString()) {
4512 if (Handle<String>::cast(key)->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004513 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004514 } else {
4515 Handle<String> key_string = Handle<String>::cast(key);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004516 key_string->TryFlatten();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004517 return js_object->SetLocalPropertyIgnoreAttributes(*key_string,
4518 *value,
4519 attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004520 }
4521 }
4522
4523 // Call-back into JavaScript to convert the key to a string.
4524 bool has_pending_exception = false;
4525 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4526 if (has_pending_exception) return Failure::Exception();
4527 Handle<String> name = Handle<String>::cast(converted);
4528
4529 if (name->AsArrayIndex(&index)) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00004530 return js_object->SetElement(index, *value, kNonStrictMode, true);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004531 } else {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004532 return js_object->SetLocalPropertyIgnoreAttributes(*name, *value, attr);
ager@chromium.org65dad4b2009-04-23 08:48:43 +00004533 }
4534}
4535
4536
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004537MaybeObject* Runtime::ForceDeleteObjectProperty(Isolate* isolate,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004538 Handle<JSReceiver> receiver,
lrn@chromium.org303ada72010-10-27 09:33:13 +00004539 Handle<Object> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004540 HandleScope scope(isolate);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004541
4542 // Check if the given key is an array index.
4543 uint32_t index;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004544 if (key->ToArrayIndex(&index)) {
ager@chromium.orge2902be2009-06-08 12:21:35 +00004545 // In Firefox/SpiderMonkey, Safari and Opera you can access the
4546 // characters of a string using [] notation. In the case of a
4547 // String object we just need to redirect the deletion to the
4548 // underlying string if the index is in range. Since the
4549 // underlying string does nothing with the deletion, we can ignore
4550 // such deletions.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004551 if (receiver->IsStringObjectWithCharacterAt(index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004552 return isolate->heap()->true_value();
ager@chromium.orge2902be2009-06-08 12:21:35 +00004553 }
4554
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004555 return receiver->DeleteElement(index, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004556 }
4557
4558 Handle<String> key_string;
4559 if (key->IsString()) {
4560 key_string = Handle<String>::cast(key);
4561 } else {
4562 // Call-back into JavaScript to convert the key to a string.
4563 bool has_pending_exception = false;
4564 Handle<Object> converted = Execution::ToString(key, &has_pending_exception);
4565 if (has_pending_exception) return Failure::Exception();
4566 key_string = Handle<String>::cast(converted);
4567 }
4568
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00004569 key_string->TryFlatten();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004570 return receiver->DeleteProperty(*key_string, JSReceiver::FORCE_DELETION);
ager@chromium.orge2902be2009-06-08 12:21:35 +00004571}
4572
4573
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004574RUNTIME_FUNCTION(MaybeObject*, Runtime_SetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004575 NoHandleAllocation ha;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004576 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004577
4578 Handle<Object> object = args.at<Object>(0);
4579 Handle<Object> key = args.at<Object>(1);
4580 Handle<Object> value = args.at<Object>(2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00004581 CONVERT_SMI_ARG_CHECKED(unchecked_attributes, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004582 RUNTIME_ASSERT(
4583 (unchecked_attributes & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004584 // Compute attributes.
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004585 PropertyAttributes attributes =
4586 static_cast<PropertyAttributes>(unchecked_attributes);
4587
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004588 StrictModeFlag strict_mode = kNonStrictMode;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004589 if (args.length() == 5) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004590 CONVERT_STRICT_MODE_ARG(strict_mode_flag, 4);
4591 strict_mode = strict_mode_flag;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004592 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00004593
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004594 return Runtime::SetObjectProperty(isolate,
4595 object,
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00004596 key,
4597 value,
4598 attributes,
4599 strict_mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004600}
4601
4602
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004603RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsSmiToDouble) {
4604 NoHandleAllocation ha;
4605 RUNTIME_ASSERT(args.length() == 1);
4606 Handle<Object> object = args.at<Object>(0);
4607 return TransitionElements(object, FAST_DOUBLE_ELEMENTS, isolate);
4608}
4609
4610
4611RUNTIME_FUNCTION(MaybeObject*, Runtime_TransitionElementsDoubleToObject) {
4612 NoHandleAllocation ha;
4613 RUNTIME_ASSERT(args.length() == 1);
4614 Handle<Object> object = args.at<Object>(0);
4615 return TransitionElements(object, FAST_ELEMENTS, isolate);
4616}
4617
4618
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004619// Set the native flag on the function.
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004620// This is used to decide if we should transform null and undefined
4621// into the global object when doing call and apply.
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004622RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNativeFlag) {
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004623 NoHandleAllocation ha;
4624 RUNTIME_ASSERT(args.length() == 1);
4625
4626 Handle<Object> object = args.at<Object>(0);
4627
4628 if (object->IsJSFunction()) {
4629 JSFunction* func = JSFunction::cast(*object);
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00004630 func->shared()->set_native(true);
ricow@chromium.org6fe7a8e2011-05-13 07:57:29 +00004631 }
4632 return isolate->heap()->undefined_value();
4633}
4634
4635
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004636RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreArrayLiteralElement) {
4637 RUNTIME_ASSERT(args.length() == 5);
4638 CONVERT_ARG_CHECKED(JSObject, object, 0);
4639 CONVERT_SMI_ARG_CHECKED(store_index, 1);
4640 Handle<Object> value = args.at<Object>(2);
4641 CONVERT_ARG_CHECKED(FixedArray, literals, 3);
4642 CONVERT_SMI_ARG_CHECKED(literal_index, 4);
4643 HandleScope scope;
4644
4645 Object* raw_boilerplate_object = literals->get(literal_index);
4646 Handle<JSArray> boilerplate_object(JSArray::cast(raw_boilerplate_object));
4647#if DEBUG
4648 ElementsKind elements_kind = object->GetElementsKind();
4649#endif
4650 ASSERT(elements_kind <= FAST_DOUBLE_ELEMENTS);
4651 // Smis should never trigger transitions.
4652 ASSERT(!value->IsSmi());
4653
4654 if (value->IsNumber()) {
4655 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004656 JSObject::TransitionElementsKind(object, FAST_DOUBLE_ELEMENTS);
4657 JSObject::TransitionElementsKind(boilerplate_object, FAST_DOUBLE_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004658 ASSERT(object->GetElementsKind() == FAST_DOUBLE_ELEMENTS);
4659 FixedDoubleArray* double_array =
4660 FixedDoubleArray::cast(object->elements());
4661 HeapNumber* number = HeapNumber::cast(*value);
4662 double_array->set(store_index, number->Number());
4663 } else {
4664 ASSERT(elements_kind == FAST_SMI_ONLY_ELEMENTS ||
4665 elements_kind == FAST_DOUBLE_ELEMENTS);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004666 JSObject::TransitionElementsKind(object, FAST_ELEMENTS);
4667 JSObject::TransitionElementsKind(boilerplate_object, FAST_ELEMENTS);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00004668 FixedArray* object_array =
4669 FixedArray::cast(object->elements());
4670 object_array->set(store_index, *value);
4671 }
4672 return *object;
4673}
4674
4675
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004676// Set a local property, even if it is READ_ONLY. If the property does not
4677// exist, it will be added with attributes NONE.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004678RUNTIME_FUNCTION(MaybeObject*, Runtime_IgnoreAttributesAndSetProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004679 NoHandleAllocation ha;
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004680 RUNTIME_ASSERT(args.length() == 3 || args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004681 CONVERT_CHECKED(JSObject, object, args[0]);
4682 CONVERT_CHECKED(String, name, args[1]);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004683 // Compute attributes.
4684 PropertyAttributes attributes = NONE;
4685 if (args.length() == 4) {
4686 CONVERT_CHECKED(Smi, value_obj, args[3]);
4687 int unchecked_value = value_obj->value();
4688 // Only attribute bits should be set.
4689 RUNTIME_ASSERT(
4690 (unchecked_value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
4691 attributes = static_cast<PropertyAttributes>(unchecked_value);
4692 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004693
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00004694 return object->
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +00004695 SetLocalPropertyIgnoreAttributes(name, args[2], attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004696}
4697
4698
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004699RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004700 NoHandleAllocation ha;
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00004701 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004702
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004703 CONVERT_CHECKED(JSReceiver, object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004704 CONVERT_CHECKED(String, key, args[1]);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00004705 CONVERT_STRICT_MODE_ARG(strict_mode, 2);
4706 return object->DeleteProperty(key, (strict_mode == kStrictMode)
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +00004707 ? JSReceiver::STRICT_DELETION
4708 : JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004709}
4710
4711
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004712static Object* HasLocalPropertyImplementation(Isolate* isolate,
4713 Handle<JSObject> object,
ager@chromium.org9085a012009-05-11 19:22:57 +00004714 Handle<String> key) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004715 if (object->HasLocalProperty(*key)) return isolate->heap()->true_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004716 // Handle hidden prototypes. If there's a hidden prototype above this thing
4717 // then we have to check it for properties, because they are supposed to
4718 // look like they are on this object.
4719 Handle<Object> proto(object->GetPrototype());
4720 if (proto->IsJSObject() &&
4721 Handle<JSObject>::cast(proto)->map()->is_hidden_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004722 return HasLocalPropertyImplementation(isolate,
4723 Handle<JSObject>::cast(proto),
4724 key);
ager@chromium.org9085a012009-05-11 19:22:57 +00004725 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004726 return isolate->heap()->false_value();
ager@chromium.org9085a012009-05-11 19:22:57 +00004727}
4728
4729
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004730RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLocalProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004731 NoHandleAllocation ha;
4732 ASSERT(args.length() == 2);
4733 CONVERT_CHECKED(String, key, args[1]);
4734
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004735 uint32_t index;
4736 const bool key_is_array_index = key->AsArrayIndex(&index);
4737
ager@chromium.org9085a012009-05-11 19:22:57 +00004738 Object* obj = args[0];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004739 // Only JS objects can have properties.
ager@chromium.org9085a012009-05-11 19:22:57 +00004740 if (obj->IsJSObject()) {
4741 JSObject* object = JSObject::cast(obj);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004742 // Fast case: either the key is a real named property or it is not
4743 // an array index and there are no interceptors or hidden
4744 // prototypes.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004745 if (object->HasRealNamedProperty(key)) return isolate->heap()->true_value();
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004746 Map* map = object->map();
4747 if (!key_is_array_index &&
4748 !map->has_named_interceptor() &&
4749 !HeapObject::cast(map->prototype())->map()->is_hidden_prototype()) {
4750 return isolate->heap()->false_value();
4751 }
4752 // Slow case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004753 HandleScope scope(isolate);
4754 return HasLocalPropertyImplementation(isolate,
4755 Handle<JSObject>(object),
ager@chromium.org9085a012009-05-11 19:22:57 +00004756 Handle<String>(key));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004757 } else if (obj->IsString() && key_is_array_index) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004758 // Well, there is one exception: Handle [] on strings.
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00004759 String* string = String::cast(obj);
4760 if (index < static_cast<uint32_t>(string->length())) {
4761 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004762 }
4763 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004764 return isolate->heap()->false_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004765}
4766
4767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004768RUNTIME_FUNCTION(MaybeObject*, Runtime_HasProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004769 NoHandleAllocation na;
4770 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004771 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4772 CONVERT_CHECKED(String, key, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004773
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004774 bool result = receiver->HasProperty(key);
4775 if (isolate->has_pending_exception()) return Failure::Exception();
4776 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004777}
4778
4779
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004780RUNTIME_FUNCTION(MaybeObject*, Runtime_HasElement) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004781 NoHandleAllocation na;
4782 ASSERT(args.length() == 2);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004783 CONVERT_CHECKED(JSReceiver, receiver, args[0]);
4784 CONVERT_CHECKED(Smi, index, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004785
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004786 bool result = receiver->HasElement(index->value());
4787 if (isolate->has_pending_exception()) return Failure::Exception();
4788 return isolate->heap()->ToBoolean(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004789}
4790
4791
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004792RUNTIME_FUNCTION(MaybeObject*, Runtime_IsPropertyEnumerable) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004793 NoHandleAllocation ha;
4794 ASSERT(args.length() == 2);
4795
4796 CONVERT_CHECKED(JSObject, object, args[0]);
4797 CONVERT_CHECKED(String, key, args[1]);
4798
4799 uint32_t index;
4800 if (key->AsArrayIndex(&index)) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004801 JSObject::LocalElementType type = object->HasLocalElement(index);
4802 switch (type) {
4803 case JSObject::UNDEFINED_ELEMENT:
4804 case JSObject::STRING_CHARACTER_ELEMENT:
4805 return isolate->heap()->false_value();
4806 case JSObject::INTERCEPTED_ELEMENT:
4807 case JSObject::FAST_ELEMENT:
4808 return isolate->heap()->true_value();
4809 case JSObject::DICTIONARY_ELEMENT: {
4810 if (object->IsJSGlobalProxy()) {
4811 Object* proto = object->GetPrototype();
4812 if (proto->IsNull()) {
4813 return isolate->heap()->false_value();
4814 }
4815 ASSERT(proto->IsJSGlobalObject());
4816 object = JSObject::cast(proto);
4817 }
4818 FixedArray* elements = FixedArray::cast(object->elements());
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004819 SeededNumberDictionary* dictionary = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004820 if (elements->map() ==
4821 isolate->heap()->non_strict_arguments_elements_map()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004822 dictionary = SeededNumberDictionary::cast(elements->get(1));
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004823 } else {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004824 dictionary = SeededNumberDictionary::cast(elements);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004825 }
4826 int entry = dictionary->FindEntry(index);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00004827 ASSERT(entry != SeededNumberDictionary::kNotFound);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00004828 PropertyDetails details = dictionary->DetailsAt(entry);
4829 return isolate->heap()->ToBoolean(!details.IsDontEnum());
4830 }
4831 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004832 }
4833
ager@chromium.org870a0b62008-11-04 11:43:05 +00004834 PropertyAttributes att = object->GetLocalPropertyAttribute(key);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004835 return isolate->heap()->ToBoolean(att != ABSENT && (att & DONT_ENUM) == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004836}
4837
4838
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004839RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004840 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004841 ASSERT(args.length() == 1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004842 CONVERT_ARG_CHECKED(JSReceiver, object, 0);
4843 bool threw = false;
4844 Handle<JSArray> result = GetKeysFor(object, &threw);
4845 if (threw) return Failure::Exception();
4846 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004847}
4848
4849
4850// Returns either a FixedArray as Runtime_GetPropertyNames,
4851// or, if the given object has an enum cache that contains
4852// all enumerable properties of the object and its prototypes
4853// have none, the map of the object. This is used to speed up
4854// the check for deletions during a for-in.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004855RUNTIME_FUNCTION(MaybeObject*, Runtime_GetPropertyNamesFast) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004856 ASSERT(args.length() == 1);
4857
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004858 CONVERT_CHECKED(JSReceiver, raw_object, args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004859
4860 if (raw_object->IsSimpleEnum()) return raw_object->map();
4861
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004862 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00004863 Handle<JSReceiver> object(raw_object);
4864 bool threw = false;
4865 Handle<FixedArray> content =
4866 GetKeysInFixedArrayFor(object, INCLUDE_PROTOS, &threw);
4867 if (threw) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00004868
4869 // Test again, since cache may have been built by preceding call.
4870 if (object->IsSimpleEnum()) return object->map();
4871
4872 return *content;
4873}
4874
4875
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004876// Find the length of the prototype chain that is to to handled as one. If a
4877// prototype object is hidden it is to be viewed as part of the the object it
4878// is prototype for.
4879static int LocalPrototypeChainLength(JSObject* obj) {
4880 int count = 1;
4881 Object* proto = obj->GetPrototype();
4882 while (proto->IsJSObject() &&
4883 JSObject::cast(proto)->map()->is_hidden_prototype()) {
4884 count++;
4885 proto = JSObject::cast(proto)->GetPrototype();
4886 }
4887 return count;
4888}
4889
4890
4891// Return the names of the local named properties.
4892// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004893RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004894 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004895 ASSERT(args.length() == 1);
4896 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004897 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004898 }
4899 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4900
4901 // Skip the global proxy as it has no properties and always delegates to the
4902 // real global object.
4903 if (obj->IsJSGlobalProxy()) {
4904 // Only collect names if access is permitted.
4905 if (obj->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004906 !isolate->MayNamedAccess(*obj,
4907 isolate->heap()->undefined_value(),
4908 v8::ACCESS_KEYS)) {
4909 isolate->ReportFailedAccessCheck(*obj, v8::ACCESS_KEYS);
4910 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004911 }
4912 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
4913 }
4914
4915 // Find the number of objects making up this.
4916 int length = LocalPrototypeChainLength(*obj);
4917
4918 // Find the number of local properties for each of the objects.
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00004919 ScopedVector<int> local_property_count(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004920 int total_property_count = 0;
4921 Handle<JSObject> jsproto = obj;
4922 for (int i = 0; i < length; i++) {
4923 // Only collect names if access is permitted.
4924 if (jsproto->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004925 !isolate->MayNamedAccess(*jsproto,
4926 isolate->heap()->undefined_value(),
4927 v8::ACCESS_KEYS)) {
4928 isolate->ReportFailedAccessCheck(*jsproto, v8::ACCESS_KEYS);
4929 return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004930 }
4931 int n;
4932 n = jsproto->NumberOfLocalProperties(static_cast<PropertyAttributes>(NONE));
4933 local_property_count[i] = n;
4934 total_property_count += n;
4935 if (i < length - 1) {
4936 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4937 }
4938 }
4939
4940 // Allocate an array with storage for all the property names.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004941 Handle<FixedArray> names =
4942 isolate->factory()->NewFixedArray(total_property_count);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004943
4944 // Get the property names.
4945 jsproto = obj;
4946 int proto_with_hidden_properties = 0;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004947 int next_copy_index = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004948 for (int i = 0; i < length; i++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00004949 jsproto->GetLocalPropertyNames(*names, next_copy_index);
4950 next_copy_index += local_property_count[i];
vegorov@chromium.org7943d462011-08-01 11:41:52 +00004951 if (jsproto->HasHiddenProperties()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004952 proto_with_hidden_properties++;
4953 }
4954 if (i < length - 1) {
4955 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
4956 }
4957 }
4958
4959 // Filter out name of hidden propeties object.
4960 if (proto_with_hidden_properties > 0) {
4961 Handle<FixedArray> old_names = names;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004962 names = isolate->factory()->NewFixedArray(
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004963 names->length() - proto_with_hidden_properties);
4964 int dest_pos = 0;
4965 for (int i = 0; i < total_property_count; i++) {
4966 Object* name = old_names->get(i);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004967 if (name == isolate->heap()->hidden_symbol()) {
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004968 continue;
4969 }
4970 names->set(dest_pos++, name);
4971 }
4972 }
4973
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004974 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004975}
4976
4977
4978// Return the names of the local indexed properties.
4979// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004980RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLocalElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004981 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004982 ASSERT(args.length() == 1);
4983 if (!args[0]->IsJSObject()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004984 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004985 }
4986 CONVERT_ARG_CHECKED(JSObject, obj, 0);
4987
4988 int n = obj->NumberOfLocalElements(static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004989 Handle<FixedArray> names = isolate->factory()->NewFixedArray(n);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004990 obj->GetLocalElementKeys(*names, static_cast<PropertyAttributes>(NONE));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004991 return *isolate->factory()->NewJSArrayWithElements(names);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004992}
4993
4994
4995// Return information on whether an object has a named or indexed interceptor.
4996// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00004997RUNTIME_FUNCTION(MaybeObject*, Runtime_GetInterceptorInfo) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00004998 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00004999 ASSERT(args.length() == 1);
5000 if (!args[0]->IsJSObject()) {
5001 return Smi::FromInt(0);
5002 }
5003 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5004
5005 int result = 0;
5006 if (obj->HasNamedInterceptor()) result |= 2;
5007 if (obj->HasIndexedInterceptor()) result |= 1;
5008
5009 return Smi::FromInt(result);
5010}
5011
5012
5013// Return property names from named interceptor.
5014// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005015RUNTIME_FUNCTION(MaybeObject*, Runtime_GetNamedInterceptorPropertyNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005016 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005017 ASSERT(args.length() == 1);
5018 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5019
5020 if (obj->HasNamedInterceptor()) {
5021 v8::Handle<v8::Array> result = GetKeysForNamedInterceptor(obj, obj);
5022 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5023 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005024 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005025}
5026
5027
5028// Return element names from indexed interceptor.
5029// args[0]: object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005030RUNTIME_FUNCTION(MaybeObject*, Runtime_GetIndexedInterceptorElementNames) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005031 HandleScope scope(isolate);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005032 ASSERT(args.length() == 1);
5033 CONVERT_ARG_CHECKED(JSObject, obj, 0);
5034
5035 if (obj->HasIndexedInterceptor()) {
5036 v8::Handle<v8::Array> result = GetKeysForIndexedInterceptor(obj, obj);
5037 if (!result.IsEmpty()) return *v8::Utils::OpenHandle(*result);
5038 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005039 return isolate->heap()->undefined_value();
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00005040}
5041
5042
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005043RUNTIME_FUNCTION(MaybeObject*, Runtime_LocalKeys) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005044 ASSERT_EQ(args.length(), 1);
5045 CONVERT_CHECKED(JSObject, raw_object, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005046 HandleScope scope(isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005047 Handle<JSObject> object(raw_object);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005048
5049 if (object->IsJSGlobalProxy()) {
ricow@chromium.org65001782011-02-15 13:36:41 +00005050 // Do access checks before going to the global object.
5051 if (object->IsAccessCheckNeeded() &&
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005052 !isolate->MayNamedAccess(*object, isolate->heap()->undefined_value(),
ricow@chromium.org65001782011-02-15 13:36:41 +00005053 v8::ACCESS_KEYS)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005054 isolate->ReportFailedAccessCheck(*object, v8::ACCESS_KEYS);
5055 return *isolate->factory()->NewJSArray(0);
ricow@chromium.org65001782011-02-15 13:36:41 +00005056 }
5057
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005058 Handle<Object> proto(object->GetPrototype());
5059 // If proxy is detached we simply return an empty array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005060 if (proto->IsNull()) return *isolate->factory()->NewJSArray(0);
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +00005061 object = Handle<JSObject>::cast(proto);
5062 }
5063
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00005064 bool threw = false;
5065 Handle<FixedArray> contents =
5066 GetKeysInFixedArrayFor(object, LOCAL_ONLY, &threw);
5067 if (threw) return Failure::Exception();
5068
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005069 // Some fast paths through GetKeysInFixedArrayFor reuse a cached
5070 // property array and since the result is mutable we have to create
5071 // a fresh clone on each invocation.
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005072 int length = contents->length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005073 Handle<FixedArray> copy = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005074 for (int i = 0; i < length; i++) {
5075 Object* entry = contents->get(i);
5076 if (entry->IsString()) {
5077 copy->set(i, entry);
5078 } else {
5079 ASSERT(entry->IsNumber());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005080 HandleScope scope(isolate);
5081 Handle<Object> entry_handle(entry, isolate);
5082 Handle<Object> entry_str =
5083 isolate->factory()->NumberToString(entry_handle);
sgjesse@chromium.orgc5145742009-10-07 09:00:33 +00005084 copy->set(i, *entry_str);
5085 }
5086 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005087 return *isolate->factory()->NewJSArrayWithElements(copy);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +00005088}
5089
5090
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005091RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArgumentsProperty) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005092 NoHandleAllocation ha;
5093 ASSERT(args.length() == 1);
5094
5095 // Compute the frame holding the arguments.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00005096 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005097 it.AdvanceToArgumentsFrame();
5098 JavaScriptFrame* frame = it.frame();
5099
5100 // Get the actual number of provided arguments.
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00005101 const uint32_t n = frame->ComputeParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005102
5103 // Try to convert the key to an index. If successful and within
5104 // index return the the argument from the frame.
5105 uint32_t index;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00005106 if (args[0]->ToArrayIndex(&index) && index < n) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005107 return frame->GetParameter(index);
5108 }
5109
5110 // Convert the key to a string.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005111 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005112 bool exception = false;
5113 Handle<Object> converted =
5114 Execution::ToString(args.at<Object>(0), &exception);
5115 if (exception) return Failure::Exception();
5116 Handle<String> key = Handle<String>::cast(converted);
5117
5118 // Try to convert the string key into an array index.
5119 if (key->AsArrayIndex(&index)) {
5120 if (index < n) {
5121 return frame->GetParameter(index);
5122 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005123 return isolate->initial_object_prototype()->GetElement(index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005124 }
5125 }
5126
5127 // Handle special arguments properties.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005128 if (key->Equals(isolate->heap()->length_symbol())) return Smi::FromInt(n);
5129 if (key->Equals(isolate->heap()->callee_symbol())) {
5130 Object* function = frame->function();
5131 if (function->IsJSFunction() &&
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00005132 !JSFunction::cast(function)->shared()->is_classic_mode()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005133 return isolate->Throw(*isolate->factory()->NewTypeError(
5134 "strict_arguments_callee", HandleVector<Object>(NULL, 0)));
5135 }
5136 return function;
5137 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005138
5139 // Lookup in the initial Object.prototype object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005140 return isolate->initial_object_prototype()->GetProperty(*key);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005141}
5142
5143
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005144RUNTIME_FUNCTION(MaybeObject*, Runtime_ToFastProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005145 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005146 Object* object = args[0];
5147 return (object->IsJSObject() && !object->IsGlobalObject())
5148 ? JSObject::cast(object)->TransformToFastProperties(0)
5149 : object;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005150}
5151
5152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005153RUNTIME_FUNCTION(MaybeObject*, Runtime_ToSlowProperties) {
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005154 ASSERT(args.length() == 1);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00005155 Object* obj = args[0];
5156 return (obj->IsJSObject() && !obj->IsJSGlobalProxy())
5157 ? JSObject::cast(obj)->NormalizeProperties(CLEAR_INOBJECT_PROPERTIES, 0)
5158 : obj;
kasperl@chromium.org061ef742009-02-27 12:16:20 +00005159}
5160
5161
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005162RUNTIME_FUNCTION(MaybeObject*, Runtime_ToBool) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005163 NoHandleAllocation ha;
5164 ASSERT(args.length() == 1);
5165
5166 return args[0]->ToBoolean();
5167}
5168
5169
5170// Returns the type string of a value; see ECMA-262, 11.4.3 (p 47).
5171// Possible optimizations: put the type string into the oddballs.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005172RUNTIME_FUNCTION(MaybeObject*, Runtime_Typeof) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005173 NoHandleAllocation ha;
5174
5175 Object* obj = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005176 if (obj->IsNumber()) return isolate->heap()->number_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005177 HeapObject* heap_obj = HeapObject::cast(obj);
5178
5179 // typeof an undetectable object is 'undefined'
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005180 if (heap_obj->map()->is_undetectable()) {
5181 return isolate->heap()->undefined_symbol();
5182 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005183
5184 InstanceType instance_type = heap_obj->map()->instance_type();
5185 if (instance_type < FIRST_NONSTRING_TYPE) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005186 return isolate->heap()->string_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005187 }
5188
5189 switch (instance_type) {
5190 case ODDBALL_TYPE:
5191 if (heap_obj->IsTrue() || heap_obj->IsFalse()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005192 return isolate->heap()->boolean_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005193 }
5194 if (heap_obj->IsNull()) {
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00005195 return FLAG_harmony_typeof
5196 ? isolate->heap()->null_symbol()
5197 : isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005198 }
5199 ASSERT(heap_obj->IsUndefined());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005200 return isolate->heap()->undefined_symbol();
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005201 case JS_FUNCTION_TYPE:
lrn@chromium.org34e60782011-09-15 07:25:40 +00005202 case JS_FUNCTION_PROXY_TYPE:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005203 return isolate->heap()->function_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005204 default:
5205 // For any kind of object not handled above, the spec rule for
5206 // host objects gives that it is okay to return "object"
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005207 return isolate->heap()->object_symbol();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005208 }
5209}
5210
5211
lrn@chromium.org25156de2010-04-06 13:10:27 +00005212static bool AreDigits(const char*s, int from, int to) {
5213 for (int i = from; i < to; i++) {
5214 if (s[i] < '0' || s[i] > '9') return false;
5215 }
5216
5217 return true;
5218}
5219
5220
5221static int ParseDecimalInteger(const char*s, int from, int to) {
5222 ASSERT(to - from < 10); // Overflow is not possible.
5223 ASSERT(from < to);
5224 int d = s[from] - '0';
5225
5226 for (int i = from + 1; i < to; i++) {
5227 d = 10 * d + (s[i] - '0');
5228 }
5229
5230 return d;
5231}
5232
5233
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005234RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToNumber) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005235 NoHandleAllocation ha;
5236 ASSERT(args.length() == 1);
5237 CONVERT_CHECKED(String, subject, args[0]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005238 subject->TryFlatten();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005239
5240 // Fast case: short integer or some sorts of junk values.
5241 int len = subject->length();
5242 if (subject->IsSeqAsciiString()) {
5243 if (len == 0) return Smi::FromInt(0);
5244
5245 char const* data = SeqAsciiString::cast(subject)->GetChars();
5246 bool minus = (data[0] == '-');
5247 int start_pos = (minus ? 1 : 0);
5248
5249 if (start_pos == len) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005250 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005251 } else if (data[start_pos] > '9') {
5252 // Fast check for a junk value. A valid string may start from a
5253 // whitespace, a sign ('+' or '-'), the decimal point, a decimal digit or
5254 // the 'I' character ('Infinity'). All of that have codes not greater than
5255 // '9' except 'I'.
5256 if (data[start_pos] != 'I') {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005257 return isolate->heap()->nan_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005258 }
5259 } else if (len - start_pos < 10 && AreDigits(data, start_pos, len)) {
5260 // The maximal/minimal smi has 10 digits. If the string has less digits we
5261 // know it will fit into the smi-data type.
5262 int d = ParseDecimalInteger(data, start_pos, len);
5263 if (minus) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005264 if (d == 0) return isolate->heap()->minus_zero_value();
lrn@chromium.org25156de2010-04-06 13:10:27 +00005265 d = -d;
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005266 } else if (!subject->HasHashCode() &&
5267 len <= String::kMaxArrayIndexSize &&
5268 (len == 1 || data[0] != '0')) {
5269 // String hash is not calculated yet but all the data are present.
5270 // Update the hash field to speed up sequential convertions.
ager@chromium.org5b2fbee2010-09-08 06:38:15 +00005271 uint32_t hash = StringHasher::MakeArrayIndexHash(d, len);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005272#ifdef DEBUG
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00005273 subject->Hash(); // Force hash calculation.
5274 ASSERT_EQ(static_cast<int>(subject->hash_field()),
5275 static_cast<int>(hash));
5276#endif
5277 subject->set_hash_field(hash);
lrn@chromium.org25156de2010-04-06 13:10:27 +00005278 }
5279 return Smi::FromInt(d);
5280 }
5281 }
5282
5283 // Slower case.
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005284 return isolate->heap()->NumberFromDouble(
5285 StringToDouble(isolate->unicode_cache(), subject, ALLOW_HEX));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005286}
5287
5288
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005289RUNTIME_FUNCTION(MaybeObject*, Runtime_StringFromCharCodeArray) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005290 NoHandleAllocation ha;
5291 ASSERT(args.length() == 1);
5292
5293 CONVERT_CHECKED(JSArray, codes, args[0]);
5294 int length = Smi::cast(codes->length())->value();
5295
5296 // Check if the string can be ASCII.
5297 int i;
5298 for (i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005299 Object* element;
5300 { MaybeObject* maybe_element = codes->GetElement(i);
5301 // We probably can't get an exception here, but just in order to enforce
5302 // the checking of inputs in the runtime calls we check here.
5303 if (!maybe_element->ToObject(&element)) return maybe_element;
5304 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005305 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
5306 if ((chr & 0xffff) > String::kMaxAsciiCharCode)
5307 break;
5308 }
5309
lrn@chromium.org303ada72010-10-27 09:33:13 +00005310 MaybeObject* maybe_object = NULL;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005311 if (i == length) { // The string is ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005312 maybe_object = isolate->heap()->AllocateRawAsciiString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005313 } else { // The string is not ASCII.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005314 maybe_object = isolate->heap()->AllocateRawTwoByteString(length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005315 }
5316
lrn@chromium.org303ada72010-10-27 09:33:13 +00005317 Object* object = NULL;
5318 if (!maybe_object->ToObject(&object)) return maybe_object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005319 String* result = String::cast(object);
5320 for (int i = 0; i < length; i++) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00005321 Object* element;
5322 { MaybeObject* maybe_element = codes->GetElement(i);
5323 if (!maybe_element->ToObject(&element)) return maybe_element;
5324 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005325 CONVERT_NUMBER_CHECKED(int, chr, Int32, element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005326 result->Set(i, chr & 0xffff);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005327 }
5328 return result;
5329}
5330
5331
5332// kNotEscaped is generated by the following:
5333//
5334// #!/bin/perl
5335// for (my $i = 0; $i < 256; $i++) {
5336// print "\n" if $i % 16 == 0;
5337// my $c = chr($i);
5338// my $escaped = 1;
5339// $escaped = 0 if $c =~ m#[A-Za-z0-9@*_+./-]#;
5340// print $escaped ? "0, " : "1, ";
5341// }
5342
5343
5344static bool IsNotEscaped(uint16_t character) {
5345 // Only for 8 bit characters, the rest are always escaped (in a different way)
5346 ASSERT(character < 256);
5347 static const char kNotEscaped[256] = {
5348 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5349 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5350 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
5351 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0,
5352 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5353 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1,
5354 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
5355 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0,
5356 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5357 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5358 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5359 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5360 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5361 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5362 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5363 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
5364 };
5365 return kNotEscaped[character] != 0;
5366}
5367
5368
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005369RUNTIME_FUNCTION(MaybeObject*, Runtime_URIEscape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005370 const char hex_chars[] = "0123456789ABCDEF";
5371 NoHandleAllocation ha;
5372 ASSERT(args.length() == 1);
5373 CONVERT_CHECKED(String, source, args[0]);
5374
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005375 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005376
5377 int escaped_length = 0;
5378 int length = source->length();
5379 {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005380 Access<StringInputBuffer> buffer(
5381 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005382 buffer->Reset(source);
5383 while (buffer->has_more()) {
5384 uint16_t character = buffer->GetNext();
5385 if (character >= 256) {
5386 escaped_length += 6;
5387 } else if (IsNotEscaped(character)) {
5388 escaped_length++;
5389 } else {
5390 escaped_length += 3;
5391 }
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005392 // We don't allow strings that are longer than a maximal length.
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00005393 ASSERT(String::kMaxLength < 0x7fffffff - 6); // Cannot overflow.
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00005394 if (escaped_length > String::kMaxLength) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005395 isolate->context()->mark_out_of_memory();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005396 return Failure::OutOfMemoryException();
5397 }
5398 }
5399 }
5400 // No length change implies no change. Return original string if no change.
5401 if (escaped_length == length) {
5402 return source;
5403 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00005404 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005405 { MaybeObject* maybe_o =
5406 isolate->heap()->AllocateRawAsciiString(escaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005407 if (!maybe_o->ToObject(&o)) return maybe_o;
5408 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005409 String* destination = String::cast(o);
5410 int dest_position = 0;
5411
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005412 Access<StringInputBuffer> buffer(
5413 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005414 buffer->Rewind();
5415 while (buffer->has_more()) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00005416 uint16_t chr = buffer->GetNext();
5417 if (chr >= 256) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005418 destination->Set(dest_position, '%');
5419 destination->Set(dest_position+1, 'u');
5420 destination->Set(dest_position+2, hex_chars[chr >> 12]);
5421 destination->Set(dest_position+3, hex_chars[(chr >> 8) & 0xf]);
5422 destination->Set(dest_position+4, hex_chars[(chr >> 4) & 0xf]);
5423 destination->Set(dest_position+5, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005424 dest_position += 6;
ager@chromium.org870a0b62008-11-04 11:43:05 +00005425 } else if (IsNotEscaped(chr)) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005426 destination->Set(dest_position, chr);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005427 dest_position++;
5428 } else {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005429 destination->Set(dest_position, '%');
5430 destination->Set(dest_position+1, hex_chars[chr >> 4]);
5431 destination->Set(dest_position+2, hex_chars[chr & 0xf]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005432 dest_position += 3;
5433 }
5434 }
5435 return destination;
5436}
5437
5438
5439static inline int TwoDigitHex(uint16_t character1, uint16_t character2) {
5440 static const signed char kHexValue['g'] = {
5441 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5442 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5443 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5444 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1,
5445 -1, 10, 11, 12, 13, 14, 15, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5446 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
5447 -1, 10, 11, 12, 13, 14, 15 };
5448
5449 if (character1 > 'f') return -1;
5450 int hi = kHexValue[character1];
5451 if (hi == -1) return -1;
5452 if (character2 > 'f') return -1;
5453 int lo = kHexValue[character2];
5454 if (lo == -1) return -1;
5455 return (hi << 4) + lo;
5456}
5457
5458
ager@chromium.org870a0b62008-11-04 11:43:05 +00005459static inline int Unescape(String* source,
ager@chromium.org870a0b62008-11-04 11:43:05 +00005460 int i,
5461 int length,
5462 int* step) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005463 uint16_t character = source->Get(i);
ager@chromium.org870a0b62008-11-04 11:43:05 +00005464 int32_t hi = 0;
5465 int32_t lo = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005466 if (character == '%' &&
5467 i <= length - 6 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005468 source->Get(i + 1) == 'u' &&
5469 (hi = TwoDigitHex(source->Get(i + 2),
5470 source->Get(i + 3))) != -1 &&
5471 (lo = TwoDigitHex(source->Get(i + 4),
5472 source->Get(i + 5))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005473 *step = 6;
5474 return (hi << 8) + lo;
5475 } else if (character == '%' &&
5476 i <= length - 3 &&
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005477 (lo = TwoDigitHex(source->Get(i + 1),
5478 source->Get(i + 2))) != -1) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005479 *step = 3;
5480 return lo;
5481 } else {
5482 *step = 1;
5483 return character;
5484 }
5485}
5486
5487
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005488RUNTIME_FUNCTION(MaybeObject*, Runtime_URIUnescape) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005489 NoHandleAllocation ha;
5490 ASSERT(args.length() == 1);
5491 CONVERT_CHECKED(String, source, args[0]);
5492
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005493 source->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005494
5495 bool ascii = true;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005496 int length = source->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005497
5498 int unescaped_length = 0;
5499 for (int i = 0; i < length; unescaped_length++) {
5500 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005501 if (Unescape(source, i, length, &step) > String::kMaxAsciiCharCode) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005502 ascii = false;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005503 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005504 i += step;
5505 }
5506
5507 // No length change implies no change. Return original string if no change.
5508 if (unescaped_length == length)
5509 return source;
5510
lrn@chromium.org303ada72010-10-27 09:33:13 +00005511 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005512 { MaybeObject* maybe_o =
5513 ascii ?
5514 isolate->heap()->AllocateRawAsciiString(unescaped_length) :
5515 isolate->heap()->AllocateRawTwoByteString(unescaped_length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005516 if (!maybe_o->ToObject(&o)) return maybe_o;
5517 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005518 String* destination = String::cast(o);
5519
5520 int dest_position = 0;
5521 for (int i = 0; i < length; dest_position++) {
5522 int step;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005523 destination->Set(dest_position, Unescape(source, i, length, &step));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005524 i += step;
5525 }
5526 return destination;
5527}
5528
5529
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005530static const unsigned int kQuoteTableLength = 128u;
5531
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005532static const int kJsonQuotesCharactersPerEntry = 8;
5533static const char* const JsonQuotes =
5534 "\\u0000 \\u0001 \\u0002 \\u0003 "
5535 "\\u0004 \\u0005 \\u0006 \\u0007 "
5536 "\\b \\t \\n \\u000b "
5537 "\\f \\r \\u000e \\u000f "
5538 "\\u0010 \\u0011 \\u0012 \\u0013 "
5539 "\\u0014 \\u0015 \\u0016 \\u0017 "
5540 "\\u0018 \\u0019 \\u001a \\u001b "
5541 "\\u001c \\u001d \\u001e \\u001f "
5542 " ! \\\" # "
5543 "$ % & ' "
5544 "( ) * + "
5545 ", - . / "
5546 "0 1 2 3 "
5547 "4 5 6 7 "
5548 "8 9 : ; "
5549 "< = > ? "
5550 "@ A B C "
5551 "D E F G "
5552 "H I J K "
5553 "L M N O "
5554 "P Q R S "
5555 "T U V W "
5556 "X Y Z [ "
5557 "\\\\ ] ^ _ "
5558 "` a b c "
5559 "d e f g "
5560 "h i j k "
5561 "l m n o "
5562 "p q r s "
5563 "t u v w "
5564 "x y z { "
5565 "| } ~ \177 ";
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005566
5567
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005568// For a string that is less than 32k characters it should always be
5569// possible to allocate it in new space.
5570static const int kMaxGuaranteedNewSpaceString = 32 * 1024;
5571
5572
5573// Doing JSON quoting cannot make the string more than this many times larger.
5574static const int kJsonQuoteWorstCaseBlowup = 6;
5575
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005576static const int kSpaceForQuotesAndComma = 3;
5577static const int kSpaceForBrackets = 2;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005578
5579// Covers the entire ASCII range (all other characters are unchanged by JSON
5580// quoting).
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005581static const byte JsonQuoteLengths[kQuoteTableLength] = {
5582 6, 6, 6, 6, 6, 6, 6, 6,
5583 2, 2, 2, 6, 2, 2, 6, 6,
5584 6, 6, 6, 6, 6, 6, 6, 6,
5585 6, 6, 6, 6, 6, 6, 6, 6,
5586 1, 1, 2, 1, 1, 1, 1, 1,
5587 1, 1, 1, 1, 1, 1, 1, 1,
5588 1, 1, 1, 1, 1, 1, 1, 1,
5589 1, 1, 1, 1, 1, 1, 1, 1,
5590 1, 1, 1, 1, 1, 1, 1, 1,
5591 1, 1, 1, 1, 1, 1, 1, 1,
5592 1, 1, 1, 1, 1, 1, 1, 1,
5593 1, 1, 1, 1, 2, 1, 1, 1,
5594 1, 1, 1, 1, 1, 1, 1, 1,
5595 1, 1, 1, 1, 1, 1, 1, 1,
5596 1, 1, 1, 1, 1, 1, 1, 1,
5597 1, 1, 1, 1, 1, 1, 1, 1,
5598};
5599
5600
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005601template <typename StringType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005602MaybeObject* AllocateRawString(Isolate* isolate, int length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005603
5604
5605template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005606MaybeObject* AllocateRawString<SeqTwoByteString>(Isolate* isolate, int length) {
5607 return isolate->heap()->AllocateRawTwoByteString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005608}
5609
5610
5611template <>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005612MaybeObject* AllocateRawString<SeqAsciiString>(Isolate* isolate, int length) {
5613 return isolate->heap()->AllocateRawAsciiString(length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005614}
5615
5616
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005617template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005618static MaybeObject* SlowQuoteJsonString(Isolate* isolate,
5619 Vector<const Char> characters) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005620 int length = characters.length();
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005621 const Char* read_cursor = characters.start();
5622 const Char* end = read_cursor + length;
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005623 const int kSpaceForQuotes = 2 + (comma ? 1 :0);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005624 int quoted_length = kSpaceForQuotes;
5625 while (read_cursor < end) {
5626 Char c = *(read_cursor++);
5627 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5628 quoted_length++;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005629 } else {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005630 quoted_length += JsonQuoteLengths[static_cast<unsigned>(c)];
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005631 }
5632 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005633 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5634 quoted_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005635 Object* new_object;
5636 if (!new_alloc->ToObject(&new_object)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005637 return new_alloc;
5638 }
5639 StringType* new_string = StringType::cast(new_object);
5640
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005641 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005642 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005643 if (comma) *(write_cursor++) = ',';
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005644 *(write_cursor++) = '"';
5645
5646 read_cursor = characters.start();
5647 while (read_cursor < end) {
5648 Char c = *(read_cursor++);
5649 if (sizeof(Char) > 1u && static_cast<unsigned>(c) >= kQuoteTableLength) {
5650 *(write_cursor++) = c;
5651 } else {
5652 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5653 const char* replacement = JsonQuotes +
5654 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5655 for (int i = 0; i < len; i++) {
5656 *write_cursor++ = *replacement++;
5657 }
5658 }
5659 }
5660 *(write_cursor++) = '"';
5661 return new_string;
5662}
5663
5664
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005665template <typename SinkChar, typename SourceChar>
5666static inline SinkChar* WriteQuoteJsonString(
5667 Isolate* isolate,
5668 SinkChar* write_cursor,
5669 Vector<const SourceChar> characters) {
ricow@chromium.orgd2be9012011-06-01 06:00:58 +00005670 // SinkChar is only char if SourceChar is guaranteed to be char.
5671 ASSERT(sizeof(SinkChar) >= sizeof(SourceChar));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005672 const SourceChar* read_cursor = characters.start();
5673 const SourceChar* end = read_cursor + characters.length();
5674 *(write_cursor++) = '"';
5675 while (read_cursor < end) {
5676 SourceChar c = *(read_cursor++);
5677 if (sizeof(SourceChar) > 1u &&
5678 static_cast<unsigned>(c) >= kQuoteTableLength) {
5679 *(write_cursor++) = static_cast<SinkChar>(c);
5680 } else {
5681 int len = JsonQuoteLengths[static_cast<unsigned>(c)];
5682 const char* replacement = JsonQuotes +
5683 static_cast<unsigned>(c) * kJsonQuotesCharactersPerEntry;
5684 write_cursor[0] = replacement[0];
5685 if (len > 1) {
5686 write_cursor[1] = replacement[1];
5687 if (len > 2) {
5688 ASSERT(len == 6);
5689 write_cursor[2] = replacement[2];
5690 write_cursor[3] = replacement[3];
5691 write_cursor[4] = replacement[4];
5692 write_cursor[5] = replacement[5];
5693 }
5694 }
5695 write_cursor += len;
5696 }
5697 }
5698 *(write_cursor++) = '"';
5699 return write_cursor;
5700}
5701
5702
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005703template <typename Char, typename StringType, bool comma>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005704static MaybeObject* QuoteJsonString(Isolate* isolate,
5705 Vector<const Char> characters) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005706 int length = characters.length();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005707 isolate->counters()->quote_json_char_count()->Increment(length);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005708 int worst_case_length =
5709 length * kJsonQuoteWorstCaseBlowup + kSpaceForQuotesAndComma;
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005710 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005711 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005712 }
5713
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005714 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5715 worst_case_length);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005716 Object* new_object;
5717 if (!new_alloc->ToObject(&new_object)) {
5718 return new_alloc;
5719 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005720 if (!isolate->heap()->new_space()->Contains(new_object)) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005721 // Even if our string is small enough to fit in new space we still have to
5722 // handle it being allocated in old space as may happen in the third
5723 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5724 // CEntryStub::GenerateCore.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005725 return SlowQuoteJsonString<Char, StringType, comma>(isolate, characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005726 }
5727 StringType* new_string = StringType::cast(new_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005728 ASSERT(isolate->heap()->new_space()->Contains(new_string));
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005729
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005730 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005731 new_string->address() + SeqString::kHeaderSize);
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005732 if (comma) *(write_cursor++) = ',';
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005733 write_cursor = WriteQuoteJsonString<Char, Char>(isolate,
5734 write_cursor,
5735 characters);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00005736 int final_length = static_cast<int>(
5737 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005738 new_string->address() + SeqString::kHeaderSize));
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00005739 isolate->heap()->new_space()->
5740 template ShrinkStringAtAllocationBoundary<StringType>(
5741 new_string, final_length);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005742 return new_string;
5743}
5744
5745
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005746RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONString) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005747 NoHandleAllocation ha;
5748 CONVERT_CHECKED(String, str, args[0]);
5749 if (!str->IsFlat()) {
5750 MaybeObject* try_flatten = str->TryFlatten();
5751 Object* flat;
5752 if (!try_flatten->ToObject(&flat)) {
5753 return try_flatten;
5754 }
5755 str = String::cast(flat);
5756 ASSERT(str->IsFlat());
5757 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005758 String::FlatContent flat = str->GetFlatContent();
5759 ASSERT(flat.IsFlat());
5760 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005761 return QuoteJsonString<uc16, SeqTwoByteString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005762 flat.ToUC16Vector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005763 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005764 return QuoteJsonString<char, SeqAsciiString, false>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005765 flat.ToAsciiVector());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00005766 }
5767}
5768
5769
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005770RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringComma) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005771 NoHandleAllocation ha;
5772 CONVERT_CHECKED(String, str, args[0]);
5773 if (!str->IsFlat()) {
5774 MaybeObject* try_flatten = str->TryFlatten();
5775 Object* flat;
5776 if (!try_flatten->ToObject(&flat)) {
5777 return try_flatten;
5778 }
5779 str = String::cast(flat);
5780 ASSERT(str->IsFlat());
5781 }
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005782 String::FlatContent flat = str->GetFlatContent();
5783 if (flat.IsTwoByte()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005784 return QuoteJsonString<uc16, SeqTwoByteString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005785 flat.ToUC16Vector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005786 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005787 return QuoteJsonString<char, SeqAsciiString, true>(isolate,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005788 flat.ToAsciiVector());
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00005789 }
5790}
5791
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005792
5793template <typename Char, typename StringType>
5794static MaybeObject* QuoteJsonStringArray(Isolate* isolate,
5795 FixedArray* array,
5796 int worst_case_length) {
5797 int length = array->length();
5798
5799 MaybeObject* new_alloc = AllocateRawString<StringType>(isolate,
5800 worst_case_length);
5801 Object* new_object;
5802 if (!new_alloc->ToObject(&new_object)) {
5803 return new_alloc;
5804 }
5805 if (!isolate->heap()->new_space()->Contains(new_object)) {
5806 // Even if our string is small enough to fit in new space we still have to
5807 // handle it being allocated in old space as may happen in the third
5808 // attempt. See CALL_AND_RETRY in heap-inl.h and similar code in
5809 // CEntryStub::GenerateCore.
5810 return isolate->heap()->undefined_value();
5811 }
5812 AssertNoAllocation no_gc;
5813 StringType* new_string = StringType::cast(new_object);
5814 ASSERT(isolate->heap()->new_space()->Contains(new_string));
5815
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005816 Char* write_cursor = reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005817 new_string->address() + SeqString::kHeaderSize);
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005818 *(write_cursor++) = '[';
5819 for (int i = 0; i < length; i++) {
5820 if (i != 0) *(write_cursor++) = ',';
5821 String* str = String::cast(array->get(i));
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005822 String::FlatContent content = str->GetFlatContent();
5823 ASSERT(content.IsFlat());
5824 if (content.IsTwoByte()) {
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005825 write_cursor = WriteQuoteJsonString<Char, uc16>(isolate,
5826 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005827 content.ToUC16Vector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005828 } else {
5829 write_cursor = WriteQuoteJsonString<Char, char>(isolate,
5830 write_cursor,
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00005831 content.ToAsciiVector());
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005832 }
5833 }
5834 *(write_cursor++) = ']';
5835
5836 int final_length = static_cast<int>(
5837 write_cursor - reinterpret_cast<Char*>(
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00005838 new_string->address() + SeqString::kHeaderSize));
ricow@chromium.orgc54d3652011-05-30 09:20:16 +00005839 isolate->heap()->new_space()->
5840 template ShrinkStringAtAllocationBoundary<StringType>(
5841 new_string, final_length);
5842 return new_string;
5843}
5844
5845
5846RUNTIME_FUNCTION(MaybeObject*, Runtime_QuoteJSONStringArray) {
5847 NoHandleAllocation ha;
5848 ASSERT(args.length() == 1);
5849 CONVERT_CHECKED(JSArray, array, args[0]);
5850
5851 if (!array->HasFastElements()) return isolate->heap()->undefined_value();
5852 FixedArray* elements = FixedArray::cast(array->elements());
5853 int n = elements->length();
5854 bool ascii = true;
5855 int total_length = 0;
5856
5857 for (int i = 0; i < n; i++) {
5858 Object* elt = elements->get(i);
5859 if (!elt->IsString()) return isolate->heap()->undefined_value();
5860 String* element = String::cast(elt);
5861 if (!element->IsFlat()) return isolate->heap()->undefined_value();
5862 total_length += element->length();
5863 if (ascii && element->IsTwoByteRepresentation()) {
5864 ascii = false;
5865 }
5866 }
5867
5868 int worst_case_length =
5869 kSpaceForBrackets + n * kSpaceForQuotesAndComma
5870 + total_length * kJsonQuoteWorstCaseBlowup;
5871
5872 if (worst_case_length > kMaxGuaranteedNewSpaceString) {
5873 return isolate->heap()->undefined_value();
5874 }
5875
5876 if (ascii) {
5877 return QuoteJsonStringArray<char, SeqAsciiString>(isolate,
5878 elements,
5879 worst_case_length);
5880 } else {
5881 return QuoteJsonStringArray<uc16, SeqTwoByteString>(isolate,
5882 elements,
5883 worst_case_length);
5884 }
5885}
5886
5887
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005888RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseInt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005889 NoHandleAllocation ha;
5890
5891 CONVERT_CHECKED(String, s, args[0]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00005892 CONVERT_SMI_ARG_CHECKED(radix, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005893
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00005894 s->TryFlatten();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005895
lrn@chromium.org25156de2010-04-06 13:10:27 +00005896 RUNTIME_ASSERT(radix == 0 || (2 <= radix && radix <= 36));
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005897 double value = StringToInt(isolate->unicode_cache(), s, radix);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005898 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005899}
5900
5901
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00005902RUNTIME_FUNCTION(MaybeObject*, Runtime_StringParseFloat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005903 NoHandleAllocation ha;
5904 CONVERT_CHECKED(String, str, args[0]);
5905
5906 // ECMA-262 section 15.1.2.3, empty string is NaN
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00005907 double value = StringToDouble(isolate->unicode_cache(),
5908 str, ALLOW_TRAILING_JUNK, OS::nan_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005909
5910 // Create a number object from the value.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005911 return isolate->heap()->NumberFromDouble(value);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005912}
5913
5914
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005915template <class Converter>
lrn@chromium.org303ada72010-10-27 09:33:13 +00005916MUST_USE_RESULT static MaybeObject* ConvertCaseHelper(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005917 Isolate* isolate,
lrn@chromium.org303ada72010-10-27 09:33:13 +00005918 String* s,
5919 int length,
5920 int input_string_length,
5921 unibrow::Mapping<Converter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005922 // We try this twice, once with the assumption that the result is no longer
5923 // than the input and, if that assumption breaks, again with the exact
5924 // length. This may not be pretty, but it is nicer than what was here before
5925 // and I hereby claim my vaffel-is.
5926 //
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005927 // Allocate the resulting string.
5928 //
5929 // NOTE: This assumes that the upper/lower case of an ascii
5930 // character is also ascii. This is currently the case, but it
5931 // might break in the future if we implement more context and locale
5932 // dependent upper/lower conversions.
lrn@chromium.org303ada72010-10-27 09:33:13 +00005933 Object* o;
5934 { MaybeObject* maybe_o = s->IsAsciiRepresentation()
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005935 ? isolate->heap()->AllocateRawAsciiString(length)
5936 : isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00005937 if (!maybe_o->ToObject(&o)) return maybe_o;
5938 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005939 String* result = String::cast(o);
5940 bool has_changed_character = false;
5941
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005942 // Convert all characters to upper case, assuming that they will fit
5943 // in the buffer
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005944 Access<StringInputBuffer> buffer(
5945 isolate->runtime_state()->string_input_buffer());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005946 buffer->Reset(s);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00005947 unibrow::uchar chars[Converter::kMaxWidth];
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005948 // We can assume that the string is not empty
5949 uc32 current = buffer->GetNext();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005950 for (int i = 0; i < length;) {
ager@chromium.org7c537e22008-10-16 08:43:32 +00005951 bool has_next = buffer->has_more();
5952 uc32 next = has_next ? buffer->GetNext() : 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005953 int char_length = mapping->get(current, next, chars);
5954 if (char_length == 0) {
5955 // The case conversion of this character is the character itself.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005956 result->Set(i, current);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005957 i++;
5958 } else if (char_length == 1) {
5959 // Common case: converting the letter resulted in one character.
5960 ASSERT(static_cast<uc32>(chars[0]) != current);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005961 result->Set(i, chars[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005962 has_changed_character = true;
5963 i++;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005964 } else if (length == input_string_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005965 // We've assumed that the result would be as long as the
5966 // input but here is a character that converts to several
5967 // characters. No matter, we calculate the exact length
5968 // of the result and try the whole thing again.
5969 //
5970 // Note that this leaves room for optimization. We could just
5971 // memcpy what we already have to the result string. Also,
5972 // the result string is the last object allocated we could
5973 // "realloc" it and probably, in the vast majority of cases,
5974 // extend the existing string to be able to hold the full
5975 // result.
ager@chromium.org7c537e22008-10-16 08:43:32 +00005976 int next_length = 0;
5977 if (has_next) {
5978 next_length = mapping->get(next, 0, chars);
5979 if (next_length == 0) next_length = 1;
5980 }
5981 int current_length = i + char_length + next_length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005982 while (buffer->has_more()) {
5983 current = buffer->GetNext();
ager@chromium.org7c537e22008-10-16 08:43:32 +00005984 // NOTE: we use 0 as the next character here because, while
5985 // the next character may affect what a character converts to,
5986 // it does not in any case affect the length of what it convert
5987 // to.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005988 int char_length = mapping->get(current, 0, chars);
5989 if (char_length == 0) char_length = 1;
ager@chromium.org7c537e22008-10-16 08:43:32 +00005990 current_length += char_length;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005991 if (current_length > Smi::kMaxValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00005992 isolate->context()->mark_out_of_memory();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005993 return Failure::OutOfMemoryException();
5994 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005995 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00005996 // Try again with the real length.
5997 return Smi::FromInt(current_length);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00005998 } else {
5999 for (int j = 0; j < char_length; j++) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006000 result->Set(i, chars[j]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006001 i++;
6002 }
6003 has_changed_character = true;
6004 }
6005 current = next;
6006 }
6007 if (has_changed_character) {
6008 return result;
6009 } else {
6010 // If we didn't actually change anything in doing the conversion
6011 // we simple return the result and let the converted string
6012 // become garbage; there is no reason to keep two identical strings
6013 // alive.
6014 return s;
6015 }
6016}
6017
6018
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006019namespace {
6020
lrn@chromium.org303ada72010-10-27 09:33:13 +00006021static const uintptr_t kOneInEveryByte = kUintptrAllBitsSet / 0xFF;
6022
6023
6024// Given a word and two range boundaries returns a word with high bit
6025// set in every byte iff the corresponding input byte was strictly in
6026// the range (m, n). All the other bits in the result are cleared.
6027// This function is only useful when it can be inlined and the
6028// boundaries are statically known.
6029// Requires: all bytes in the input word and the boundaries must be
6030// ascii (less than 0x7F).
6031static inline uintptr_t AsciiRangeMask(uintptr_t w, char m, char n) {
6032 // Every byte in an ascii string is less than or equal to 0x7F.
6033 ASSERT((w & (kOneInEveryByte * 0x7F)) == w);
6034 // Use strict inequalities since in edge cases the function could be
6035 // further simplified.
6036 ASSERT(0 < m && m < n && n < 0x7F);
6037 // Has high bit set in every w byte less than n.
6038 uintptr_t tmp1 = kOneInEveryByte * (0x7F + n) - w;
6039 // Has high bit set in every w byte greater than m.
6040 uintptr_t tmp2 = w + kOneInEveryByte * (0x7F - m);
6041 return (tmp1 & tmp2 & (kOneInEveryByte * 0x80));
6042}
6043
6044
6045enum AsciiCaseConversion {
6046 ASCII_TO_LOWER,
6047 ASCII_TO_UPPER
6048};
6049
6050
6051template <AsciiCaseConversion dir>
6052struct FastAsciiConverter {
6053 static bool Convert(char* dst, char* src, int length) {
6054#ifdef DEBUG
6055 char* saved_dst = dst;
6056 char* saved_src = src;
6057#endif
6058 // We rely on the distance between upper and lower case letters
6059 // being a known power of 2.
6060 ASSERT('a' - 'A' == (1 << 5));
6061 // Boundaries for the range of input characters than require conversion.
6062 const char lo = (dir == ASCII_TO_LOWER) ? 'A' - 1 : 'a' - 1;
6063 const char hi = (dir == ASCII_TO_LOWER) ? 'Z' + 1 : 'z' + 1;
6064 bool changed = false;
6065 char* const limit = src + length;
6066#ifdef V8_HOST_CAN_READ_UNALIGNED
6067 // Process the prefix of the input that requires no conversion one
6068 // (machine) word at a time.
6069 while (src <= limit - sizeof(uintptr_t)) {
6070 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6071 if (AsciiRangeMask(w, lo, hi) != 0) {
6072 changed = true;
6073 break;
6074 }
6075 *reinterpret_cast<uintptr_t*>(dst) = w;
6076 src += sizeof(uintptr_t);
6077 dst += sizeof(uintptr_t);
6078 }
6079 // Process the remainder of the input performing conversion when
6080 // required one word at a time.
6081 while (src <= limit - sizeof(uintptr_t)) {
6082 uintptr_t w = *reinterpret_cast<uintptr_t*>(src);
6083 uintptr_t m = AsciiRangeMask(w, lo, hi);
6084 // The mask has high (7th) bit set in every byte that needs
6085 // conversion and we know that the distance between cases is
6086 // 1 << 5.
6087 *reinterpret_cast<uintptr_t*>(dst) = w ^ (m >> 2);
6088 src += sizeof(uintptr_t);
6089 dst += sizeof(uintptr_t);
6090 }
6091#endif
6092 // Process the last few bytes of the input (or the whole input if
6093 // unaligned access is not supported).
6094 while (src < limit) {
6095 char c = *src;
6096 if (lo < c && c < hi) {
6097 c ^= (1 << 5);
6098 changed = true;
6099 }
6100 *dst = c;
6101 ++src;
6102 ++dst;
6103 }
6104#ifdef DEBUG
6105 CheckConvert(saved_dst, saved_src, length, changed);
6106#endif
6107 return changed;
6108 }
6109
6110#ifdef DEBUG
6111 static void CheckConvert(char* dst, char* src, int length, bool changed) {
6112 bool expected_changed = false;
6113 for (int i = 0; i < length; i++) {
6114 if (dst[i] == src[i]) continue;
6115 expected_changed = true;
6116 if (dir == ASCII_TO_LOWER) {
6117 ASSERT('A' <= src[i] && src[i] <= 'Z');
6118 ASSERT(dst[i] == src[i] + ('a' - 'A'));
6119 } else {
6120 ASSERT(dir == ASCII_TO_UPPER);
6121 ASSERT('a' <= src[i] && src[i] <= 'z');
6122 ASSERT(dst[i] == src[i] - ('a' - 'A'));
6123 }
6124 }
6125 ASSERT(expected_changed == changed);
6126 }
6127#endif
6128};
6129
6130
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006131struct ToLowerTraits {
6132 typedef unibrow::ToLowercase UnibrowConverter;
6133
lrn@chromium.org303ada72010-10-27 09:33:13 +00006134 typedef FastAsciiConverter<ASCII_TO_LOWER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006135};
6136
6137
6138struct ToUpperTraits {
6139 typedef unibrow::ToUppercase UnibrowConverter;
6140
lrn@chromium.org303ada72010-10-27 09:33:13 +00006141 typedef FastAsciiConverter<ASCII_TO_UPPER> AsciiConverter;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006142};
6143
6144} // namespace
6145
6146
6147template <typename ConvertTraits>
lrn@chromium.org303ada72010-10-27 09:33:13 +00006148MUST_USE_RESULT static MaybeObject* ConvertCase(
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006149 Arguments args,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006150 Isolate* isolate,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006151 unibrow::Mapping<typename ConvertTraits::UnibrowConverter, 128>* mapping) {
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006152 NoHandleAllocation ha;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006153 CONVERT_CHECKED(String, s, args[0]);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006154 s = s->TryFlattenGetString();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006155
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006156 const int length = s->length();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006157 // Assume that the string is not empty; we need this assumption later
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006158 if (length == 0) return s;
6159
6160 // Simpler handling of ascii strings.
6161 //
6162 // NOTE: This assumes that the upper/lower case of an ascii
6163 // character is also ascii. This is currently the case, but it
6164 // might break in the future if we implement more context and locale
6165 // dependent upper/lower conversions.
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006166 if (s->IsSeqAsciiString()) {
lrn@chromium.org303ada72010-10-27 09:33:13 +00006167 Object* o;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006168 { MaybeObject* maybe_o = isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006169 if (!maybe_o->ToObject(&o)) return maybe_o;
6170 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006171 SeqAsciiString* result = SeqAsciiString::cast(o);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006172 bool has_changed_character = ConvertTraits::AsciiConverter::Convert(
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006173 result->GetChars(), SeqAsciiString::cast(s)->GetChars(), length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006174 return has_changed_character ? result : s;
6175 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006176
lrn@chromium.org303ada72010-10-27 09:33:13 +00006177 Object* answer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006178 { MaybeObject* maybe_answer =
6179 ConvertCaseHelper(isolate, s, length, length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006180 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6181 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006182 if (answer->IsSmi()) {
6183 // Retry with correct length.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006184 { MaybeObject* maybe_answer =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006185 ConvertCaseHelper(isolate,
6186 s, Smi::cast(answer)->value(), length, mapping);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006187 if (!maybe_answer->ToObject(&answer)) return maybe_answer;
6188 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006189 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00006190 return answer;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006191}
6192
6193
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006194RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToLowerCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006195 return ConvertCase<ToLowerTraits>(
6196 args, isolate, isolate->runtime_state()->to_lower_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006197}
6198
6199
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006200RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToUpperCase) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006201 return ConvertCase<ToUpperTraits>(
6202 args, isolate, isolate->runtime_state()->to_upper_mapping());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006203}
6204
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006205
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006206static inline bool IsTrimWhiteSpace(unibrow::uchar c) {
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00006207 return unibrow::WhiteSpace::Is(c) || c == 0x200b || c == 0xfeff;
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006208}
6209
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006211RUNTIME_FUNCTION(MaybeObject*, Runtime_StringTrim) {
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006212 NoHandleAllocation ha;
6213 ASSERT(args.length() == 3);
6214
6215 CONVERT_CHECKED(String, s, args[0]);
6216 CONVERT_BOOLEAN_CHECKED(trimLeft, args[1]);
6217 CONVERT_BOOLEAN_CHECKED(trimRight, args[2]);
6218
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006219 s->TryFlatten();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006220 int length = s->length();
6221
6222 int left = 0;
6223 if (trimLeft) {
6224 while (left < length && IsTrimWhiteSpace(s->Get(left))) {
6225 left++;
6226 }
6227 }
6228
6229 int right = length;
6230 if (trimRight) {
6231 while (right > left && IsTrimWhiteSpace(s->Get(right - 1))) {
6232 right--;
6233 }
6234 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006235 return s->SubString(left, right);
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006236}
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006237
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006238
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006239RUNTIME_FUNCTION(MaybeObject*, Runtime_StringSplit) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006240 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006241 HandleScope handle_scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006242 CONVERT_ARG_CHECKED(String, subject, 0);
6243 CONVERT_ARG_CHECKED(String, pattern, 1);
6244 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[2]);
6245
6246 int subject_length = subject->length();
6247 int pattern_length = pattern->length();
6248 RUNTIME_ASSERT(pattern_length > 0);
6249
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006250 if (limit == 0xffffffffu) {
6251 Handle<Object> cached_answer(StringSplitCache::Lookup(
6252 isolate->heap()->string_split_cache(),
6253 *subject,
6254 *pattern));
6255 if (*cached_answer != Smi::FromInt(0)) {
6256 Handle<JSArray> result =
6257 isolate->factory()->NewJSArrayWithElements(
6258 Handle<FixedArray>::cast(cached_answer));
6259 return *result;
6260 }
6261 }
6262
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006263 // The limit can be very large (0xffffffffu), but since the pattern
6264 // isn't empty, we can never create more parts than ~half the length
6265 // of the subject.
6266
6267 if (!subject->IsFlat()) FlattenString(subject);
6268
6269 static const int kMaxInitialListCapacity = 16;
6270
danno@chromium.org40cb8782011-05-25 07:58:50 +00006271 ZoneScope scope(isolate, DELETE_ON_EXIT);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006272
6273 // Find (up to limit) indices of separator and end-of-string in subject
6274 int initial_capacity = Min<uint32_t>(kMaxInitialListCapacity, limit);
6275 ZoneList<int> indices(initial_capacity);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006276 if (!pattern->IsFlat()) FlattenString(pattern);
6277
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006278 FindStringIndicesDispatch(isolate, *subject, *pattern, &indices, limit);
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006279
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006280 if (static_cast<uint32_t>(indices.length()) < limit) {
6281 indices.Add(subject_length);
6282 }
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006283
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006284 // The list indices now contains the end of each part to create.
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006285
6286 // Create JSArray of substrings separated by separator.
6287 int part_count = indices.length();
6288
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006289 Handle<JSArray> result = isolate->factory()->NewJSArray(part_count);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006290 MaybeObject* maybe_result = result->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006291 if (maybe_result->IsFailure()) return maybe_result;
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006292 result->set_length(Smi::FromInt(part_count));
6293
6294 ASSERT(result->HasFastElements());
6295
6296 if (part_count == 1 && indices.at(0) == subject_length) {
6297 FixedArray::cast(result->elements())->set(0, *subject);
6298 return *result;
6299 }
6300
6301 Handle<FixedArray> elements(FixedArray::cast(result->elements()));
6302 int part_start = 0;
6303 for (int i = 0; i < part_count; i++) {
6304 HandleScope local_loop_handle;
6305 int part_end = indices.at(i);
6306 Handle<String> substring =
ager@chromium.org04921a82011-06-27 13:21:41 +00006307 isolate->factory()->NewProperSubString(subject, part_start, part_end);
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006308 elements->set(i, *substring);
6309 part_start = part_end + pattern_length;
6310 }
6311
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006312 if (limit == 0xffffffffu) {
ricow@chromium.org55ee8072011-09-08 16:33:10 +00006313 if (result->HasFastElements()) {
6314 StringSplitCache::Enter(isolate->heap(),
6315 isolate->heap()->string_split_cache(),
6316 *subject,
6317 *pattern,
6318 *elements);
6319 }
jkummerow@chromium.org486075a2011-09-07 12:44:28 +00006320 }
6321
fschneider@chromium.org086aac62010-03-17 13:18:24 +00006322 return *result;
6323}
6324
6325
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006326// Copies ascii characters to the given fixed array looking up
6327// one-char strings in the cache. Gives up on the first char that is
6328// not in the cache and fills the remainder with smi zeros. Returns
6329// the length of the successfully copied prefix.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006330static int CopyCachedAsciiCharsToArray(Heap* heap,
6331 const char* chars,
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006332 FixedArray* elements,
6333 int length) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006334 AssertNoAllocation no_gc;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006335 FixedArray* ascii_cache = heap->single_character_string_cache();
6336 Object* undefined = heap->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006337 int i;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006338 WriteBarrierMode mode = elements->GetWriteBarrierMode(no_gc);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006339 for (i = 0; i < length; ++i) {
6340 Object* value = ascii_cache->get(chars[i]);
6341 if (value == undefined) break;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006342 elements->set(i, value, mode);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006343 }
6344 if (i < length) {
6345 ASSERT(Smi::FromInt(0) == 0);
6346 memset(elements->data_start() + i, 0, kPointerSize * (length - i));
6347 }
6348#ifdef DEBUG
6349 for (int j = 0; j < length; ++j) {
6350 Object* element = elements->get(j);
6351 ASSERT(element == Smi::FromInt(0) ||
6352 (element->IsString() && String::cast(element)->LooksValid()));
6353 }
6354#endif
6355 return i;
6356}
6357
6358
6359// Converts a String to JSArray.
6360// For example, "foo" => ["f", "o", "o"].
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006361RUNTIME_FUNCTION(MaybeObject*, Runtime_StringToArray) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006362 HandleScope scope(isolate);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006363 ASSERT(args.length() == 2);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006364 CONVERT_ARG_CHECKED(String, s, 0);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006365 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006366
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006367 s = FlattenGetString(s);
ager@chromium.orgbeb25712010-11-29 08:02:25 +00006368 const int length = static_cast<int>(Min<uint32_t>(s->length(), limit));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006369
6370 Handle<FixedArray> elements;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006371 int position = 0;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006372 if (s->IsFlat() && s->IsAsciiRepresentation()) {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006373 // Try using cached chars where possible.
lrn@chromium.org303ada72010-10-27 09:33:13 +00006374 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006375 { MaybeObject* maybe_obj =
6376 isolate->heap()->AllocateUninitializedFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006377 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
6378 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006379 elements = Handle<FixedArray>(FixedArray::cast(obj), isolate);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006380 String::FlatContent content = s->GetFlatContent();
6381 if (content.IsAscii()) {
6382 Vector<const char> chars = content.ToAsciiVector();
6383 // Note, this will initialize all elements (not only the prefix)
6384 // to prevent GC from seeing partially initialized array.
6385 position = CopyCachedAsciiCharsToArray(isolate->heap(),
6386 chars.start(),
6387 *elements,
6388 length);
6389 } else {
6390 MemsetPointer(elements->data_start(),
6391 isolate->heap()->undefined_value(),
6392 length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006393 }
6394 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006395 elements = isolate->factory()->NewFixedArray(length);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00006396 }
6397 for (int i = position; i < length; ++i) {
6398 Handle<Object> str = LookupSingleCharacterStringFromCode(s->Get(i));
6399 elements->set(i, *str);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006400 }
6401
6402#ifdef DEBUG
6403 for (int i = 0; i < length; ++i) {
6404 ASSERT(String::cast(elements->get(i))->length() == 1);
6405 }
6406#endif
6407
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006408 return *isolate->factory()->NewJSArrayWithElements(elements);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006409}
6410
6411
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006412RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStringWrapper) {
ricow@chromium.orgd236f4d2010-09-01 06:52:08 +00006413 NoHandleAllocation ha;
6414 ASSERT(args.length() == 1);
6415 CONVERT_CHECKED(String, value, args[0]);
6416 return value->ToObject();
6417}
6418
6419
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006420bool Runtime::IsUpperCaseChar(RuntimeState* runtime_state, uint16_t ch) {
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006421 unibrow::uchar chars[unibrow::ToUppercase::kMaxWidth];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006422 int char_length = runtime_state->to_upper_mapping()->get(ch, 0, chars);
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +00006423 return char_length == 0;
6424}
6425
6426
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006427RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToString) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006428 NoHandleAllocation ha;
6429 ASSERT(args.length() == 1);
6430
6431 Object* number = args[0];
6432 RUNTIME_ASSERT(number->IsNumber());
6433
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006434 return isolate->heap()->NumberToString(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006435}
6436
6437
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006438RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToStringSkipCache) {
ager@chromium.org357bf652010-04-12 11:30:10 +00006439 NoHandleAllocation ha;
6440 ASSERT(args.length() == 1);
6441
6442 Object* number = args[0];
6443 RUNTIME_ASSERT(number->IsNumber());
6444
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006445 return isolate->heap()->NumberToString(number, false);
ager@chromium.org357bf652010-04-12 11:30:10 +00006446}
6447
6448
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006449RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToInteger) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006450 NoHandleAllocation ha;
6451 ASSERT(args.length() == 1);
6452
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006453 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006454
6455 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6456 if (number > 0 && number <= Smi::kMaxValue) {
6457 return Smi::FromInt(static_cast<int>(number));
6458 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006459 return isolate->heap()->NumberFromDouble(DoubleToInteger(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006460}
6461
6462
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006463RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToIntegerMapMinusZero) {
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006464 NoHandleAllocation ha;
6465 ASSERT(args.length() == 1);
6466
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006467 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006468
6469 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6470 if (number > 0 && number <= Smi::kMaxValue) {
6471 return Smi::FromInt(static_cast<int>(number));
6472 }
6473
6474 double double_value = DoubleToInteger(number);
6475 // Map both -0 and +0 to +0.
6476 if (double_value == 0) double_value = 0;
6477
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006478 return isolate->heap()->NumberFromDouble(double_value);
ricow@chromium.org30ce4112010-05-31 10:38:25 +00006479}
6480
6481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006482RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSUint32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006483 NoHandleAllocation ha;
6484 ASSERT(args.length() == 1);
6485
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006486 CONVERT_NUMBER_CHECKED(int32_t, number, Uint32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006487 return isolate->heap()->NumberFromUint32(number);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006488}
6489
6490
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006491RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToJSInt32) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006492 NoHandleAllocation ha;
6493 ASSERT(args.length() == 1);
6494
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006495 CONVERT_DOUBLE_ARG_CHECKED(number, 0);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00006496
6497 // We do not include 0 so that we don't have to treat +0 / -0 cases.
6498 if (number > 0 && number <= Smi::kMaxValue) {
6499 return Smi::FromInt(static_cast<int>(number));
6500 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006501 return isolate->heap()->NumberFromInt32(DoubleToInt32(number));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006502}
6503
6504
ager@chromium.org870a0b62008-11-04 11:43:05 +00006505// Converts a Number to a Smi, if possible. Returns NaN if the number is not
6506// a small integer.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006507RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberToSmi) {
ager@chromium.org870a0b62008-11-04 11:43:05 +00006508 NoHandleAllocation ha;
6509 ASSERT(args.length() == 1);
6510
6511 Object* obj = args[0];
6512 if (obj->IsSmi()) {
6513 return obj;
6514 }
6515 if (obj->IsHeapNumber()) {
6516 double value = HeapNumber::cast(obj)->value();
6517 int int_value = FastD2I(value);
6518 if (value == FastI2D(int_value) && Smi::IsValid(int_value)) {
6519 return Smi::FromInt(int_value);
6520 }
6521 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006522 return isolate->heap()->nan_value();
ager@chromium.org870a0b62008-11-04 11:43:05 +00006523}
6524
ager@chromium.org65dad4b2009-04-23 08:48:43 +00006525
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006526RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateHeapNumber) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006527 NoHandleAllocation ha;
6528 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006529 return isolate->heap()->AllocateHeapNumber(0);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00006530}
6531
6532
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006533RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006534 NoHandleAllocation ha;
6535 ASSERT(args.length() == 2);
6536
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006537 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6538 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006539 return isolate->heap()->NumberFromDouble(x + y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006540}
6541
6542
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006543RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSub) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006544 NoHandleAllocation ha;
6545 ASSERT(args.length() == 2);
6546
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006547 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6548 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006549 return isolate->heap()->NumberFromDouble(x - y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006550}
6551
6552
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006553RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMul) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006554 NoHandleAllocation ha;
6555 ASSERT(args.length() == 2);
6556
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006557 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6558 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006559 return isolate->heap()->NumberFromDouble(x * y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006560}
6561
6562
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006563RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberUnaryMinus) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006564 NoHandleAllocation ha;
6565 ASSERT(args.length() == 1);
6566
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006567 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006568 return isolate->heap()->NumberFromDouble(-x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006569}
6570
6571
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006572RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAlloc) {
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006573 NoHandleAllocation ha;
6574 ASSERT(args.length() == 0);
6575
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006576 return isolate->heap()->NumberFromDouble(9876543210.0);
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +00006577}
6578
6579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006580RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberDiv) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006581 NoHandleAllocation ha;
6582 ASSERT(args.length() == 2);
6583
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006584 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6585 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006586 return isolate->heap()->NumberFromDouble(x / y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006587}
6588
6589
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006590RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberMod) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006591 NoHandleAllocation ha;
6592 ASSERT(args.length() == 2);
6593
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006594 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
6595 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006596
ager@chromium.org3811b432009-10-28 14:53:37 +00006597 x = modulo(x, y);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00006598 // NumberFromDouble may return a Smi instead of a Number object
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006599 return isolate->heap()->NumberFromDouble(x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006600}
6601
6602
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006603RUNTIME_FUNCTION(MaybeObject*, Runtime_StringAdd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006604 NoHandleAllocation ha;
6605 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006606 CONVERT_CHECKED(String, str1, args[0]);
6607 CONVERT_CHECKED(String, str2, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006608 isolate->counters()->string_add_runtime()->Increment();
6609 return isolate->heap()->AllocateConsString(str1, str2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006610}
6611
6612
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006613template <typename sinkchar>
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006614static inline void StringBuilderConcatHelper(String* special,
6615 sinkchar* sink,
6616 FixedArray* fixed_array,
6617 int array_length) {
6618 int position = 0;
6619 for (int i = 0; i < array_length; i++) {
6620 Object* element = fixed_array->get(i);
6621 if (element->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006622 // Smi encoding of position and length.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006623 int encoded_slice = Smi::cast(element)->value();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006624 int pos;
6625 int len;
6626 if (encoded_slice > 0) {
6627 // Position and length encoded in one smi.
6628 pos = StringBuilderSubstringPosition::decode(encoded_slice);
6629 len = StringBuilderSubstringLength::decode(encoded_slice);
6630 } else {
6631 // Position and length encoded in two smis.
6632 Object* obj = fixed_array->get(++i);
6633 ASSERT(obj->IsSmi());
6634 pos = Smi::cast(obj)->value();
6635 len = -encoded_slice;
6636 }
ager@chromium.org870a0b62008-11-04 11:43:05 +00006637 String::WriteToFlat(special,
ager@chromium.org870a0b62008-11-04 11:43:05 +00006638 sink + position,
6639 pos,
6640 pos + len);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006641 position += len;
6642 } else {
6643 String* string = String::cast(element);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006644 int element_length = string->length();
6645 String::WriteToFlat(string, sink + position, 0, element_length);
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006646 position += element_length;
6647 }
6648 }
6649}
6650
6651
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006652RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderConcat) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006653 NoHandleAllocation ha;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006654 ASSERT(args.length() == 3);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006655 CONVERT_CHECKED(JSArray, array, args[0]);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006656 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006657 isolate->context()->mark_out_of_memory();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006658 return Failure::OutOfMemoryException();
6659 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006660 int array_length = args.smi_at(1);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006661 CONVERT_CHECKED(String, special, args[2]);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006662
6663 // This assumption is used by the slice encoding in one or two smis.
6664 ASSERT(Smi::kMaxValue >= String::kMaxLength);
6665
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00006666 MaybeObject* maybe_result = array->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006667 if (maybe_result->IsFailure()) return maybe_result;
6668
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006669 int special_length = special->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006670 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006671 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006672 }
6673 FixedArray* fixed_array = FixedArray::cast(array->elements());
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006674 if (fixed_array->length() < array_length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006675 array_length = fixed_array->length();
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006676 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006677
6678 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006679 return isolate->heap()->empty_string();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006680 } else if (array_length == 1) {
6681 Object* first = fixed_array->get(0);
6682 if (first->IsString()) return first;
6683 }
6684
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006685 bool ascii = special->HasOnlyAsciiChars();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006686 int position = 0;
6687 for (int i = 0; i < array_length; i++) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006688 int increment = 0;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006689 Object* elt = fixed_array->get(i);
6690 if (elt->IsSmi()) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006691 // Smi encoding of position and length.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006692 int smi_value = Smi::cast(elt)->value();
6693 int pos;
6694 int len;
6695 if (smi_value > 0) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006696 // Position and length encoded in one smi.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006697 pos = StringBuilderSubstringPosition::decode(smi_value);
6698 len = StringBuilderSubstringLength::decode(smi_value);
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006699 } else {
6700 // Position and length encoded in two smis.
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006701 len = -smi_value;
6702 // Get the position and check that it is a positive smi.
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006703 i++;
6704 if (i >= array_length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006705 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006706 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006707 Object* next_smi = fixed_array->get(i);
6708 if (!next_smi->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006709 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006710 }
6711 pos = Smi::cast(next_smi)->value();
6712 if (pos < 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006713 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ager@chromium.orgc4c92722009-11-18 14:12:51 +00006714 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006715 }
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006716 ASSERT(pos >= 0);
6717 ASSERT(len >= 0);
6718 if (pos > special_length || len > special_length - pos) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006719 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
ricow@chromium.orgc9c80822010-04-21 08:22:37 +00006720 }
6721 increment = len;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006722 } else if (elt->IsString()) {
6723 String* element = String::cast(elt);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00006724 int element_length = element->length();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006725 increment = element_length;
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +00006726 if (ascii && !element->HasOnlyAsciiChars()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006727 ascii = false;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00006728 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006729 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006730 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006731 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006732 if (increment > String::kMaxLength - position) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006733 isolate->context()->mark_out_of_memory();
christian.plesner.hansen@gmail.com9d58c2b2009-10-16 11:48:38 +00006734 return Failure::OutOfMemoryException();
6735 }
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00006736 position += increment;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006737 }
6738
6739 int length = position;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006740 Object* object;
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006741
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006742 if (ascii) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006743 { MaybeObject* maybe_object =
6744 isolate->heap()->AllocateRawAsciiString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006745 if (!maybe_object->ToObject(&object)) return maybe_object;
6746 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006747 SeqAsciiString* answer = SeqAsciiString::cast(object);
6748 StringBuilderConcatHelper(special,
6749 answer->GetChars(),
6750 fixed_array,
6751 array_length);
6752 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006753 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006754 { MaybeObject* maybe_object =
6755 isolate->heap()->AllocateRawTwoByteString(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00006756 if (!maybe_object->ToObject(&object)) return maybe_object;
6757 }
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00006758 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6759 StringBuilderConcatHelper(special,
6760 answer->GetChars(),
6761 fixed_array,
6762 array_length);
6763 return answer;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006764 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006765}
6766
6767
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006768RUNTIME_FUNCTION(MaybeObject*, Runtime_StringBuilderJoin) {
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006769 NoHandleAllocation ha;
6770 ASSERT(args.length() == 3);
6771 CONVERT_CHECKED(JSArray, array, args[0]);
6772 if (!args[1]->IsSmi()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006773 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006774 return Failure::OutOfMemoryException();
6775 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00006776 int array_length = args.smi_at(1);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006777 CONVERT_CHECKED(String, separator, args[2]);
6778
6779 if (!array->HasFastElements()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006780 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006781 }
6782 FixedArray* fixed_array = FixedArray::cast(array->elements());
6783 if (fixed_array->length() < array_length) {
6784 array_length = fixed_array->length();
6785 }
6786
6787 if (array_length == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006788 return isolate->heap()->empty_string();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006789 } else if (array_length == 1) {
6790 Object* first = fixed_array->get(0);
6791 if (first->IsString()) return first;
6792 }
6793
6794 int separator_length = separator->length();
6795 int max_nof_separators =
6796 (String::kMaxLength + separator_length - 1) / separator_length;
6797 if (max_nof_separators < (array_length - 1)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006798 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006799 return Failure::OutOfMemoryException();
6800 }
6801 int length = (array_length - 1) * separator_length;
6802 for (int i = 0; i < array_length; i++) {
6803 Object* element_obj = fixed_array->get(i);
6804 if (!element_obj->IsString()) {
6805 // TODO(1161): handle this case.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006806 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006807 }
6808 String* element = String::cast(element_obj);
6809 int increment = element->length();
6810 if (increment > String::kMaxLength - length) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006811 isolate->context()->mark_out_of_memory();
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006812 return Failure::OutOfMemoryException();
6813 }
6814 length += increment;
6815 }
6816
6817 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006818 { MaybeObject* maybe_object =
6819 isolate->heap()->AllocateRawTwoByteString(length);
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006820 if (!maybe_object->ToObject(&object)) return maybe_object;
6821 }
6822 SeqTwoByteString* answer = SeqTwoByteString::cast(object);
6823
6824 uc16* sink = answer->GetChars();
6825#ifdef DEBUG
6826 uc16* end = sink + length;
6827#endif
6828
6829 String* first = String::cast(fixed_array->get(0));
6830 int first_length = first->length();
6831 String::WriteToFlat(first, sink, 0, first_length);
6832 sink += first_length;
6833
6834 for (int i = 1; i < array_length; i++) {
6835 ASSERT(sink + separator_length <= end);
6836 String::WriteToFlat(separator, sink, 0, separator_length);
6837 sink += separator_length;
6838
6839 String* element = String::cast(fixed_array->get(i));
6840 int element_length = element->length();
6841 ASSERT(sink + element_length <= end);
6842 String::WriteToFlat(element, sink, 0, element_length);
6843 sink += element_length;
6844 }
6845 ASSERT(sink == end);
6846
6847 ASSERT(!answer->HasOnlyAsciiChars()); // Use %_FastAsciiArrayJoin instead.
6848 return answer;
6849}
6850
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006851template <typename Char>
6852static void JoinSparseArrayWithSeparator(FixedArray* elements,
6853 int elements_length,
6854 uint32_t array_length,
6855 String* separator,
6856 Vector<Char> buffer) {
6857 int previous_separator_position = 0;
6858 int separator_length = separator->length();
6859 int cursor = 0;
6860 for (int i = 0; i < elements_length; i += 2) {
6861 int position = NumberToInt32(elements->get(i));
6862 String* string = String::cast(elements->get(i + 1));
6863 int string_length = string->length();
6864 if (string->length() > 0) {
6865 while (previous_separator_position < position) {
6866 String::WriteToFlat<Char>(separator, &buffer[cursor],
6867 0, separator_length);
6868 cursor += separator_length;
6869 previous_separator_position++;
6870 }
6871 String::WriteToFlat<Char>(string, &buffer[cursor],
6872 0, string_length);
6873 cursor += string->length();
6874 }
6875 }
6876 if (separator_length > 0) {
6877 // Array length must be representable as a signed 32-bit number,
6878 // otherwise the total string length would have been too large.
6879 ASSERT(array_length <= 0x7fffffff); // Is int32_t.
6880 int last_array_index = static_cast<int>(array_length - 1);
6881 while (previous_separator_position < last_array_index) {
6882 String::WriteToFlat<Char>(separator, &buffer[cursor],
6883 0, separator_length);
6884 cursor += separator_length;
6885 previous_separator_position++;
6886 }
6887 }
6888 ASSERT(cursor <= buffer.length());
6889}
6890
6891
6892RUNTIME_FUNCTION(MaybeObject*, Runtime_SparseJoinWithSeparator) {
6893 NoHandleAllocation ha;
6894 ASSERT(args.length() == 3);
6895 CONVERT_CHECKED(JSArray, elements_array, args[0]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00006896 RUNTIME_ASSERT(elements_array->HasFastElements() ||
6897 elements_array->HasFastSmiOnlyElements());
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006898 CONVERT_NUMBER_CHECKED(uint32_t, array_length, Uint32, args[1]);
6899 CONVERT_CHECKED(String, separator, args[2]);
6900 // elements_array is fast-mode JSarray of alternating positions
6901 // (increasing order) and strings.
6902 // array_length is length of original array (used to add separators);
6903 // separator is string to put between elements. Assumed to be non-empty.
6904
6905 // Find total length of join result.
6906 int string_length = 0;
danno@chromium.orgc612e022011-11-10 11:38:15 +00006907 bool is_ascii = separator->IsAsciiRepresentation();
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00006908 int max_string_length;
6909 if (is_ascii) {
6910 max_string_length = SeqAsciiString::kMaxLength;
6911 } else {
6912 max_string_length = SeqTwoByteString::kMaxLength;
6913 }
sgjesse@chromium.org8e8294a2011-05-02 14:30:53 +00006914 bool overflow = false;
6915 CONVERT_NUMBER_CHECKED(int, elements_length,
6916 Int32, elements_array->length());
6917 RUNTIME_ASSERT((elements_length & 1) == 0); // Even length.
6918 FixedArray* elements = FixedArray::cast(elements_array->elements());
6919 for (int i = 0; i < elements_length; i += 2) {
6920 RUNTIME_ASSERT(elements->get(i)->IsNumber());
6921 CONVERT_CHECKED(String, string, elements->get(i + 1));
6922 int length = string->length();
6923 if (is_ascii && !string->IsAsciiRepresentation()) {
6924 is_ascii = false;
6925 max_string_length = SeqTwoByteString::kMaxLength;
6926 }
6927 if (length > max_string_length ||
6928 max_string_length - length < string_length) {
6929 overflow = true;
6930 break;
6931 }
6932 string_length += length;
6933 }
6934 int separator_length = separator->length();
6935 if (!overflow && separator_length > 0) {
6936 if (array_length <= 0x7fffffffu) {
6937 int separator_count = static_cast<int>(array_length) - 1;
6938 int remaining_length = max_string_length - string_length;
6939 if ((remaining_length / separator_length) >= separator_count) {
6940 string_length += separator_length * (array_length - 1);
6941 } else {
6942 // Not room for the separators within the maximal string length.
6943 overflow = true;
6944 }
6945 } else {
6946 // Nonempty separator and at least 2^31-1 separators necessary
6947 // means that the string is too large to create.
6948 STATIC_ASSERT(String::kMaxLength < 0x7fffffff);
6949 overflow = true;
6950 }
6951 }
6952 if (overflow) {
6953 // Throw OutOfMemory exception for creating too large a string.
6954 V8::FatalProcessOutOfMemory("Array join result too large.");
6955 }
6956
6957 if (is_ascii) {
6958 MaybeObject* result_allocation =
6959 isolate->heap()->AllocateRawAsciiString(string_length);
6960 if (result_allocation->IsFailure()) return result_allocation;
6961 SeqAsciiString* result_string =
6962 SeqAsciiString::cast(result_allocation->ToObjectUnchecked());
6963 JoinSparseArrayWithSeparator<char>(elements,
6964 elements_length,
6965 array_length,
6966 separator,
6967 Vector<char>(result_string->GetChars(),
6968 string_length));
6969 return result_string;
6970 } else {
6971 MaybeObject* result_allocation =
6972 isolate->heap()->AllocateRawTwoByteString(string_length);
6973 if (result_allocation->IsFailure()) return result_allocation;
6974 SeqTwoByteString* result_string =
6975 SeqTwoByteString::cast(result_allocation->ToObjectUnchecked());
6976 JoinSparseArrayWithSeparator<uc16>(elements,
6977 elements_length,
6978 array_length,
6979 separator,
6980 Vector<uc16>(result_string->GetChars(),
6981 string_length));
6982 return result_string;
6983 }
6984}
6985
kmillikin@chromium.org49edbdf2011-02-16 12:32:18 +00006986
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006987RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberOr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006988 NoHandleAllocation ha;
6989 ASSERT(args.length() == 2);
6990
6991 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
6992 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00006993 return isolate->heap()->NumberFromInt32(x | y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006994}
6995
6996
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00006997RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberAnd) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00006998 NoHandleAllocation ha;
6999 ASSERT(args.length() == 2);
7000
7001 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7002 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007003 return isolate->heap()->NumberFromInt32(x & y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007004}
7005
7006
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007007RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberXor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007008 NoHandleAllocation ha;
7009 ASSERT(args.length() == 2);
7010
7011 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7012 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007013 return isolate->heap()->NumberFromInt32(x ^ y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007014}
7015
7016
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007017RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberNot) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007018 NoHandleAllocation ha;
7019 ASSERT(args.length() == 1);
7020
7021 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007022 return isolate->heap()->NumberFromInt32(~x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007023}
7024
7025
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007026RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShl) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007027 NoHandleAllocation ha;
7028 ASSERT(args.length() == 2);
7029
7030 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7031 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007032 return isolate->heap()->NumberFromInt32(x << (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007033}
7034
7035
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007036RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberShr) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007037 NoHandleAllocation ha;
7038 ASSERT(args.length() == 2);
7039
7040 CONVERT_NUMBER_CHECKED(uint32_t, x, Uint32, args[0]);
7041 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007042 return isolate->heap()->NumberFromUint32(x >> (y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007043}
7044
7045
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007046RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberSar) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007047 NoHandleAllocation ha;
7048 ASSERT(args.length() == 2);
7049
7050 CONVERT_NUMBER_CHECKED(int32_t, x, Int32, args[0]);
7051 CONVERT_NUMBER_CHECKED(int32_t, y, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007052 return isolate->heap()->NumberFromInt32(ArithmeticShiftRight(x, y & 0x1f));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007053}
7054
7055
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007056RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007057 NoHandleAllocation ha;
7058 ASSERT(args.length() == 2);
7059
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007060 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7061 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007062 if (isnan(x)) return Smi::FromInt(NOT_EQUAL);
7063 if (isnan(y)) return Smi::FromInt(NOT_EQUAL);
7064 if (x == y) return Smi::FromInt(EQUAL);
7065 Object* result;
7066 if ((fpclassify(x) == FP_ZERO) && (fpclassify(y) == FP_ZERO)) {
7067 result = Smi::FromInt(EQUAL);
7068 } else {
7069 result = Smi::FromInt(NOT_EQUAL);
7070 }
7071 return result;
7072}
7073
7074
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007075RUNTIME_FUNCTION(MaybeObject*, Runtime_StringEquals) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007076 NoHandleAllocation ha;
7077 ASSERT(args.length() == 2);
7078
7079 CONVERT_CHECKED(String, x, args[0]);
7080 CONVERT_CHECKED(String, y, args[1]);
7081
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00007082 bool not_equal = !x->Equals(y);
7083 // This is slightly convoluted because the value that signifies
7084 // equality is 0 and inequality is 1 so we have to negate the result
7085 // from String::Equals.
7086 ASSERT(not_equal == 0 || not_equal == 1);
7087 STATIC_CHECK(EQUAL == 0);
7088 STATIC_CHECK(NOT_EQUAL == 1);
7089 return Smi::FromInt(not_equal);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007090}
7091
7092
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007093RUNTIME_FUNCTION(MaybeObject*, Runtime_NumberCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007094 NoHandleAllocation ha;
7095 ASSERT(args.length() == 3);
7096
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007097 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7098 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007099 if (isnan(x) || isnan(y)) return args[2];
7100 if (x == y) return Smi::FromInt(EQUAL);
7101 if (isless(x, y)) return Smi::FromInt(LESS);
7102 return Smi::FromInt(GREATER);
7103}
7104
7105
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007106// Compare two Smis as if they were converted to strings and then
7107// compared lexicographically.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007108RUNTIME_FUNCTION(MaybeObject*, Runtime_SmiLexicographicCompare) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007109 NoHandleAllocation ha;
7110 ASSERT(args.length() == 2);
7111
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007112 // Extract the integer values from the Smis.
7113 CONVERT_CHECKED(Smi, x, args[0]);
7114 CONVERT_CHECKED(Smi, y, args[1]);
7115 int x_value = x->value();
7116 int y_value = y->value();
7117
7118 // If the integers are equal so are the string representations.
7119 if (x_value == y_value) return Smi::FromInt(EQUAL);
7120
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007121 // If one of the integers is zero the normal integer order is the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007122 // same as the lexicographic order of the string representations.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007123 if (x_value == 0 || y_value == 0)
7124 return Smi::FromInt(x_value < y_value ? LESS : GREATER);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007125
ager@chromium.org32912102009-01-16 10:38:43 +00007126 // If only one of the integers is negative the negative number is
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007127 // smallest because the char code of '-' is less than the char code
7128 // of any digit. Otherwise, we make both values positive.
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007129
7130 // Use unsigned values otherwise the logic is incorrect for -MIN_INT on
7131 // architectures using 32-bit Smis.
7132 uint32_t x_scaled = x_value;
7133 uint32_t y_scaled = y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007134 if (x_value < 0 || y_value < 0) {
7135 if (y_value >= 0) return Smi::FromInt(LESS);
7136 if (x_value >= 0) return Smi::FromInt(GREATER);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007137 x_scaled = -x_value;
7138 y_scaled = -y_value;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007139 }
7140
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007141 static const uint32_t kPowersOf10[] = {
7142 1, 10, 100, 1000, 10*1000, 100*1000,
7143 1000*1000, 10*1000*1000, 100*1000*1000,
7144 1000*1000*1000
7145 };
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007146
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007147 // If the integers have the same number of decimal digits they can be
7148 // compared directly as the numeric order is the same as the
7149 // lexicographic order. If one integer has fewer digits, it is scaled
7150 // by some power of 10 to have the same number of digits as the longer
7151 // integer. If the scaled integers are equal it means the shorter
7152 // integer comes first in the lexicographic order.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007153
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007154 // From http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
7155 int x_log2 = IntegerLog2(x_scaled);
7156 int x_log10 = ((x_log2 + 1) * 1233) >> 12;
7157 x_log10 -= x_scaled < kPowersOf10[x_log10];
7158
7159 int y_log2 = IntegerLog2(y_scaled);
7160 int y_log10 = ((y_log2 + 1) * 1233) >> 12;
7161 y_log10 -= y_scaled < kPowersOf10[y_log10];
7162
7163 int tie = EQUAL;
7164
7165 if (x_log10 < y_log10) {
7166 // X has fewer digits. We would like to simply scale up X but that
7167 // might overflow, e.g when comparing 9 with 1_000_000_000, 9 would
7168 // be scaled up to 9_000_000_000. So we scale up by the next
7169 // smallest power and scale down Y to drop one digit. It is OK to
7170 // drop one digit from the longer integer since the final digit is
7171 // past the length of the shorter integer.
7172 x_scaled *= kPowersOf10[y_log10 - x_log10 - 1];
7173 y_scaled /= 10;
7174 tie = LESS;
7175 } else if (y_log10 < x_log10) {
7176 y_scaled *= kPowersOf10[x_log10 - y_log10 - 1];
7177 x_scaled /= 10;
7178 tie = GREATER;
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007179 }
7180
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00007181 if (x_scaled < y_scaled) return Smi::FromInt(LESS);
7182 if (x_scaled > y_scaled) return Smi::FromInt(GREATER);
7183 return Smi::FromInt(tie);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00007184}
7185
7186
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007187static Object* StringInputBufferCompare(RuntimeState* state,
7188 String* x,
7189 String* y) {
7190 StringInputBuffer& bufx = *state->string_input_buffer_compare_bufx();
7191 StringInputBuffer& bufy = *state->string_input_buffer_compare_bufy();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007192 bufx.Reset(x);
7193 bufy.Reset(y);
7194 while (bufx.has_more() && bufy.has_more()) {
7195 int d = bufx.GetNext() - bufy.GetNext();
7196 if (d < 0) return Smi::FromInt(LESS);
7197 else if (d > 0) return Smi::FromInt(GREATER);
7198 }
7199
7200 // x is (non-trivial) prefix of y:
7201 if (bufy.has_more()) return Smi::FromInt(LESS);
7202 // y is prefix of x:
7203 return Smi::FromInt(bufx.has_more() ? GREATER : EQUAL);
7204}
7205
7206
7207static Object* FlatStringCompare(String* x, String* y) {
7208 ASSERT(x->IsFlat());
7209 ASSERT(y->IsFlat());
7210 Object* equal_prefix_result = Smi::FromInt(EQUAL);
7211 int prefix_length = x->length();
7212 if (y->length() < prefix_length) {
7213 prefix_length = y->length();
7214 equal_prefix_result = Smi::FromInt(GREATER);
7215 } else if (y->length() > prefix_length) {
7216 equal_prefix_result = Smi::FromInt(LESS);
7217 }
7218 int r;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007219 String::FlatContent x_content = x->GetFlatContent();
7220 String::FlatContent y_content = y->GetFlatContent();
7221 if (x_content.IsAscii()) {
7222 Vector<const char> x_chars = x_content.ToAsciiVector();
7223 if (y_content.IsAscii()) {
7224 Vector<const char> y_chars = y_content.ToAsciiVector();
fschneider@chromium.org086aac62010-03-17 13:18:24 +00007225 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007226 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007227 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007228 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7229 }
7230 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007231 Vector<const uc16> x_chars = x_content.ToUC16Vector();
7232 if (y_content.IsAscii()) {
7233 Vector<const char> y_chars = y_content.ToAsciiVector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007234 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7235 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00007236 Vector<const uc16> y_chars = y_content.ToUC16Vector();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007237 r = CompareChars(x_chars.start(), y_chars.start(), prefix_length);
7238 }
7239 }
7240 Object* result;
7241 if (r == 0) {
7242 result = equal_prefix_result;
7243 } else {
7244 result = (r < 0) ? Smi::FromInt(LESS) : Smi::FromInt(GREATER);
7245 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007246 ASSERT(result ==
7247 StringInputBufferCompare(Isolate::Current()->runtime_state(), x, y));
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007248 return result;
7249}
7250
7251
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007252RUNTIME_FUNCTION(MaybeObject*, Runtime_StringCompare) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007253 NoHandleAllocation ha;
7254 ASSERT(args.length() == 2);
7255
7256 CONVERT_CHECKED(String, x, args[0]);
7257 CONVERT_CHECKED(String, y, args[1]);
7258
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007259 isolate->counters()->string_compare_runtime()->Increment();
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00007260
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007261 // A few fast case tests before we flatten.
7262 if (x == y) return Smi::FromInt(EQUAL);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007263 if (y->length() == 0) {
7264 if (x->length() == 0) return Smi::FromInt(EQUAL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007265 return Smi::FromInt(GREATER);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007266 } else if (x->length() == 0) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007267 return Smi::FromInt(LESS);
7268 }
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007269
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00007270 int d = x->Get(0) - y->Get(0);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00007271 if (d < 0) return Smi::FromInt(LESS);
7272 else if (d > 0) return Smi::FromInt(GREATER);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007273
lrn@chromium.org303ada72010-10-27 09:33:13 +00007274 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007275 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(x);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007276 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7277 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007278 { MaybeObject* maybe_obj = isolate->heap()->PrepareForCompare(y);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007279 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7280 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007281
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007282 return (x->IsFlat() && y->IsFlat()) ? FlatStringCompare(x, y)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007283 : StringInputBufferCompare(isolate->runtime_state(), x, y);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007284}
7285
7286
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007287RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_acos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007288 NoHandleAllocation ha;
7289 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007290 isolate->counters()->math_acos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007291
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007292 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007293 return isolate->transcendental_cache()->Get(TranscendentalCache::ACOS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007294}
7295
7296
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007297RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_asin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007298 NoHandleAllocation ha;
7299 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007300 isolate->counters()->math_asin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007301
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007302 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007303 return isolate->transcendental_cache()->Get(TranscendentalCache::ASIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007304}
7305
7306
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007307RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007308 NoHandleAllocation ha;
7309 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007310 isolate->counters()->math_atan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007311
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007312 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007313 return isolate->transcendental_cache()->Get(TranscendentalCache::ATAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007314}
7315
7316
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007317static const double kPiDividedBy4 = 0.78539816339744830962;
7318
7319
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007320RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_atan2) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007321 NoHandleAllocation ha;
7322 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007323 isolate->counters()->math_atan2()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007324
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007325 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7326 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007327 double result;
7328 if (isinf(x) && isinf(y)) {
7329 // Make sure that the result in case of two infinite arguments
7330 // is a multiple of Pi / 4. The sign of the result is determined
7331 // by the first argument (x) and the sign of the second argument
7332 // determines the multiplier: one or three.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007333 int multiplier = (x < 0) ? -1 : 1;
7334 if (y < 0) multiplier *= 3;
7335 result = multiplier * kPiDividedBy4;
7336 } else {
7337 result = atan2(x, y);
7338 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007339 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007340}
7341
7342
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007343RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_ceil) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007344 NoHandleAllocation ha;
7345 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007346 isolate->counters()->math_ceil()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007347
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007348 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007349 return isolate->heap()->NumberFromDouble(ceiling(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007350}
7351
7352
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007353RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_cos) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007354 NoHandleAllocation ha;
7355 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007356 isolate->counters()->math_cos()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007357
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007358 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007359 return isolate->transcendental_cache()->Get(TranscendentalCache::COS, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007360}
7361
7362
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007363RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_exp) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007364 NoHandleAllocation ha;
7365 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007366 isolate->counters()->math_exp()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007367
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007368 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007369 return isolate->transcendental_cache()->Get(TranscendentalCache::EXP, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007370}
7371
7372
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007373RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_floor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007374 NoHandleAllocation ha;
7375 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007376 isolate->counters()->math_floor()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007377
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007378 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007379 return isolate->heap()->NumberFromDouble(floor(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007380}
7381
7382
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007383RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_log) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007384 NoHandleAllocation ha;
7385 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007386 isolate->counters()->math_log()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007387
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007388 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007389 return isolate->transcendental_cache()->Get(TranscendentalCache::LOG, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007390}
7391
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007392// Slow version of Math.pow. We check for fast paths for special cases.
7393// Used if SSE2/VFP3 is not available.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007394RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007395 NoHandleAllocation ha;
7396 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007397 isolate->counters()->math_pow()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007398
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007399 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007400
7401 // If the second argument is a smi, it is much faster to call the
7402 // custom powi() function than the generic pow().
7403 if (args[1]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007404 int y = args.smi_at(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007405 return isolate->heap()->NumberFromDouble(power_double_int(x, y));
ager@chromium.org5aa501c2009-06-23 07:57:28 +00007406 }
7407
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007408 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007409 int y_int = static_cast<int>(y);
7410 double result;
7411 if (y == y_int) {
7412 result = power_double_int(x, y_int); // Returns 1 if exponent is 0.
7413 } else if (y == 0.5) {
7414 result = (isinf(x)) ? V8_INFINITY : sqrt(x + 0.0); // Convert -0 to +0.
7415 } else if (y == -0.5) {
7416 result = (isinf(x)) ? 0 : 1.0 / sqrt(x + 0.0); // Convert -0 to +0.
7417 } else {
7418 result = power_double_double(x, y);
7419 }
7420 if (isnan(result)) return isolate->heap()->nan_value();
7421 return isolate->heap()->AllocateHeapNumber(result);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007422}
7423
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007424// Fast version of Math.pow if we know that y is not an integer and y is not
7425// -0.5 or 0.5. Used as slow case from fullcodegen.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007426RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_pow_cfunction) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007427 NoHandleAllocation ha;
7428 ASSERT(args.length() == 2);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007429 isolate->counters()->math_pow()->Increment();
7430
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007431 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
7432 CONVERT_DOUBLE_ARG_CHECKED(y, 1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007433 if (y == 0) {
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00007434 return Smi::FromInt(1);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007435 } else {
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00007436 double result = power_double_double(x, y);
7437 if (isnan(result)) return isolate->heap()->nan_value();
7438 return isolate->heap()->AllocateHeapNumber(result);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007439 }
7440}
7441
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007442
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007443RUNTIME_FUNCTION(MaybeObject*, Runtime_RoundNumber) {
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_round()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007447
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007448 if (!args[0]->IsHeapNumber()) {
7449 // Must be smi. Return the argument unchanged for all the other types
7450 // to make fuzz-natives test happy.
7451 return args[0];
7452 }
7453
7454 HeapNumber* number = reinterpret_cast<HeapNumber*>(args[0]);
7455
7456 double value = number->value();
7457 int exponent = number->get_exponent();
7458 int sign = number->get_sign();
7459
danno@chromium.org160a7b02011-04-18 15:51:38 +00007460 if (exponent < -1) {
7461 // Number in range ]-0.5..0.5[. These always round to +/-zero.
7462 if (sign) return isolate->heap()->minus_zero_value();
7463 return Smi::FromInt(0);
7464 }
7465
7466 // We compare with kSmiValueSize - 2 because (2^30 - 0.1) has exponent 29 and
7467 // should be rounded to 2^30, which is not smi (for 31-bit smis, similar
7468 // agument holds for 32-bit smis).
7469 if (!sign && exponent < kSmiValueSize - 2) {
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007470 return Smi::FromInt(static_cast<int>(value + 0.5));
7471 }
7472
7473 // If the magnitude is big enough, there's no place for fraction part. If we
7474 // try to add 0.5 to this number, 1.0 will be added instead.
7475 if (exponent >= 52) {
7476 return number;
7477 }
7478
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007479 if (sign && value >= -0.5) return isolate->heap()->minus_zero_value();
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007480
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00007481 // Do not call NumberFromDouble() to avoid extra checks.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007482 return isolate->heap()->AllocateHeapNumber(floor(value + 0.5));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007483}
7484
7485
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007486RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sin) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007487 NoHandleAllocation ha;
7488 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007489 isolate->counters()->math_sin()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007490
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007491 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007492 return isolate->transcendental_cache()->Get(TranscendentalCache::SIN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007493}
7494
7495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007496RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_sqrt) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007497 NoHandleAllocation ha;
7498 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007499 isolate->counters()->math_sqrt()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007500
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007501 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007502 return isolate->heap()->AllocateHeapNumber(sqrt(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007503}
7504
7505
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007506RUNTIME_FUNCTION(MaybeObject*, Runtime_Math_tan) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007507 NoHandleAllocation ha;
7508 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007509 isolate->counters()->math_tan()->Increment();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007510
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007511 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007512 return isolate->transcendental_cache()->Get(TranscendentalCache::TAN, x);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00007513}
7514
7515
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007516static int MakeDay(int year, int month) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007517 static const int day_from_month[] = {0, 31, 59, 90, 120, 151,
7518 181, 212, 243, 273, 304, 334};
7519 static const int day_from_month_leap[] = {0, 31, 60, 91, 121, 152,
7520 182, 213, 244, 274, 305, 335};
7521
7522 year += month / 12;
7523 month %= 12;
7524 if (month < 0) {
7525 year--;
7526 month += 12;
7527 }
7528
7529 ASSERT(month >= 0);
7530 ASSERT(month < 12);
7531
7532 // year_delta is an arbitrary number such that:
7533 // a) year_delta = -1 (mod 400)
7534 // b) year + year_delta > 0 for years in the range defined by
7535 // ECMA 262 - 15.9.1.1, i.e. upto 100,000,000 days on either side of
7536 // Jan 1 1970. This is required so that we don't run into integer
7537 // division of negative numbers.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007538 // c) there shouldn't be an overflow for 32-bit integers in the following
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007539 // operations.
7540 static const int year_delta = 399999;
7541 static const int base_day = 365 * (1970 + year_delta) +
7542 (1970 + year_delta) / 4 -
7543 (1970 + year_delta) / 100 +
7544 (1970 + year_delta) / 400;
7545
7546 int year1 = year + year_delta;
7547 int day_from_year = 365 * year1 +
7548 year1 / 4 -
7549 year1 / 100 +
7550 year1 / 400 -
7551 base_day;
7552
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007553 if ((year % 4 != 0) || (year % 100 == 0 && year % 400 != 0)) {
7554 return day_from_year + day_from_month[month];
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007555 }
7556
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007557 return day_from_year + day_from_month_leap[month];
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007558}
7559
7560
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007561RUNTIME_FUNCTION(MaybeObject*, Runtime_DateMakeDay) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007562 NoHandleAllocation ha;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007563 ASSERT(args.length() == 2);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007564
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007565 CONVERT_SMI_ARG_CHECKED(year, 0);
7566 CONVERT_SMI_ARG_CHECKED(month, 1);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007567
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007568 return Smi::FromInt(MakeDay(year, month));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007569}
7570
7571
7572static const int kDays4Years[] = {0, 365, 2 * 365, 3 * 365 + 1};
7573static const int kDaysIn4Years = 4 * 365 + 1;
7574static const int kDaysIn100Years = 25 * kDaysIn4Years - 1;
7575static const int kDaysIn400Years = 4 * kDaysIn100Years + 1;
7576static const int kDays1970to2000 = 30 * 365 + 7;
7577static const int kDaysOffset = 1000 * kDaysIn400Years + 5 * kDaysIn400Years -
7578 kDays1970to2000;
7579static const int kYearsOffset = 400000;
7580
7581static const char kDayInYear[] = {
7582 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7583 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7584 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7585 22, 23, 24, 25, 26, 27, 28,
7586 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7587 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7588 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7589 22, 23, 24, 25, 26, 27, 28, 29, 30,
7590 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7591 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7592 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7593 22, 23, 24, 25, 26, 27, 28, 29, 30,
7594 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7595 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7596 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7597 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7598 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7599 22, 23, 24, 25, 26, 27, 28, 29, 30,
7600 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7601 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7602 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7603 22, 23, 24, 25, 26, 27, 28, 29, 30,
7604 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7605 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7606
7607 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7608 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7609 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7610 22, 23, 24, 25, 26, 27, 28,
7611 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7612 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7613 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7614 22, 23, 24, 25, 26, 27, 28, 29, 30,
7615 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7616 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7617 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7618 22, 23, 24, 25, 26, 27, 28, 29, 30,
7619 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7620 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7621 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7622 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7623 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7624 22, 23, 24, 25, 26, 27, 28, 29, 30,
7625 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7626 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7627 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7628 22, 23, 24, 25, 26, 27, 28, 29, 30,
7629 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7630 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7631
7632 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7633 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7634 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7635 22, 23, 24, 25, 26, 27, 28, 29,
7636 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7637 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7638 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7639 22, 23, 24, 25, 26, 27, 28, 29, 30,
7640 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7641 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7642 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7643 22, 23, 24, 25, 26, 27, 28, 29, 30,
7644 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7645 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7646 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7647 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7648 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7649 22, 23, 24, 25, 26, 27, 28, 29, 30,
7650 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7651 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7652 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7653 22, 23, 24, 25, 26, 27, 28, 29, 30,
7654 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7655 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7656
7657 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7658 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7659 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7660 22, 23, 24, 25, 26, 27, 28,
7661 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7662 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7663 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7664 22, 23, 24, 25, 26, 27, 28, 29, 30,
7665 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7666 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7667 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7668 22, 23, 24, 25, 26, 27, 28, 29, 30,
7669 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7670 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7671 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7672 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7673 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7674 22, 23, 24, 25, 26, 27, 28, 29, 30,
7675 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7676 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
7677 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7678 22, 23, 24, 25, 26, 27, 28, 29, 30,
7679 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
7680 22, 23, 24, 25, 26, 27, 28, 29, 30, 31};
7681
7682static const char kMonthInYear[] = {
7683 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,
7684 0, 0, 0, 0, 0, 0,
7685 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,
7686 1, 1, 1,
7687 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,
7688 2, 2, 2, 2, 2, 2,
7689 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,
7690 3, 3, 3, 3, 3,
7691 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,
7692 4, 4, 4, 4, 4, 4,
7693 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,
7694 5, 5, 5, 5, 5,
7695 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,
7696 6, 6, 6, 6, 6, 6,
7697 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,
7698 7, 7, 7, 7, 7, 7,
7699 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,
7700 8, 8, 8, 8, 8,
7701 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,
7702 9, 9, 9, 9, 9, 9,
7703 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7704 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7705 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7706 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7707
7708 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,
7709 0, 0, 0, 0, 0, 0,
7710 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,
7711 1, 1, 1,
7712 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,
7713 2, 2, 2, 2, 2, 2,
7714 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,
7715 3, 3, 3, 3, 3,
7716 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,
7717 4, 4, 4, 4, 4, 4,
7718 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,
7719 5, 5, 5, 5, 5,
7720 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,
7721 6, 6, 6, 6, 6, 6,
7722 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,
7723 7, 7, 7, 7, 7, 7,
7724 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,
7725 8, 8, 8, 8, 8,
7726 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,
7727 9, 9, 9, 9, 9, 9,
7728 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7729 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7730 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7731 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7732
7733 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,
7734 0, 0, 0, 0, 0, 0,
7735 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,
7736 1, 1, 1, 1,
7737 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,
7738 2, 2, 2, 2, 2, 2,
7739 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,
7740 3, 3, 3, 3, 3,
7741 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,
7742 4, 4, 4, 4, 4, 4,
7743 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,
7744 5, 5, 5, 5, 5,
7745 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,
7746 6, 6, 6, 6, 6, 6,
7747 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,
7748 7, 7, 7, 7, 7, 7,
7749 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,
7750 8, 8, 8, 8, 8,
7751 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,
7752 9, 9, 9, 9, 9, 9,
7753 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7754 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7755 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7756 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7757
7758 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,
7759 0, 0, 0, 0, 0, 0,
7760 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,
7761 1, 1, 1,
7762 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,
7763 2, 2, 2, 2, 2, 2,
7764 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,
7765 3, 3, 3, 3, 3,
7766 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,
7767 4, 4, 4, 4, 4, 4,
7768 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,
7769 5, 5, 5, 5, 5,
7770 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,
7771 6, 6, 6, 6, 6, 6,
7772 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,
7773 7, 7, 7, 7, 7, 7,
7774 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,
7775 8, 8, 8, 8, 8,
7776 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,
7777 9, 9, 9, 9, 9, 9,
7778 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7779 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
7780 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
7781 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11};
7782
7783
7784// This function works for dates from 1970 to 2099.
7785static inline void DateYMDFromTimeAfter1970(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007786 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007787#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007788 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007789#endif
7790
7791 year = 1970 + (4 * date + 2) / kDaysIn4Years;
7792 date %= kDaysIn4Years;
7793
7794 month = kMonthInYear[date];
7795 day = kDayInYear[date];
7796
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007797 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007798}
7799
7800
7801static inline void DateYMDFromTimeSlow(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007802 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007803#ifdef DEBUG
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +00007804 int save_date = date; // Need this for ASSERT in the end.
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007805#endif
7806
7807 date += kDaysOffset;
7808 year = 400 * (date / kDaysIn400Years) - kYearsOffset;
7809 date %= kDaysIn400Years;
7810
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007811 ASSERT(MakeDay(year, 0) + date == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007812
7813 date--;
7814 int yd1 = date / kDaysIn100Years;
7815 date %= kDaysIn100Years;
7816 year += 100 * yd1;
7817
7818 date++;
7819 int yd2 = date / kDaysIn4Years;
7820 date %= kDaysIn4Years;
7821 year += 4 * yd2;
7822
7823 date--;
7824 int yd3 = date / 365;
7825 date %= 365;
7826 year += yd3;
7827
7828 bool is_leap = (!yd1 || yd2) && !yd3;
7829
7830 ASSERT(date >= -1);
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007831 ASSERT(is_leap || (date >= 0));
7832 ASSERT((date < 365) || (is_leap && (date < 366)));
7833 ASSERT(is_leap == ((year % 4 == 0) && (year % 100 || (year % 400 == 0))));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007834 ASSERT(is_leap || ((MakeDay(year, 0) + date) == save_date));
7835 ASSERT(!is_leap || ((MakeDay(year, 0) + date + 1) == save_date));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007836
7837 if (is_leap) {
7838 day = kDayInYear[2*365 + 1 + date];
7839 month = kMonthInYear[2*365 + 1 + date];
7840 } else {
7841 day = kDayInYear[date];
7842 month = kMonthInYear[date];
7843 }
7844
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007845 ASSERT(MakeDay(year, month) + day - 1 == save_date);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007846}
7847
7848
7849static inline void DateYMDFromTime(int date,
whesse@chromium.orgcec079d2010-03-22 14:44:04 +00007850 int& year, int& month, int& day) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007851 if (date >= 0 && date < 32 * kDaysIn4Years) {
7852 DateYMDFromTimeAfter1970(date, year, month, day);
7853 } else {
7854 DateYMDFromTimeSlow(date, year, month, day);
7855 }
7856}
7857
7858
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007859RUNTIME_FUNCTION(MaybeObject*, Runtime_DateYMDFromTime) {
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007860 NoHandleAllocation ha;
7861 ASSERT(args.length() == 2);
7862
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007863 CONVERT_DOUBLE_ARG_CHECKED(t, 0);
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007864 CONVERT_CHECKED(JSArray, res_array, args[1]);
7865
7866 int year, month, day;
7867 DateYMDFromTime(static_cast<int>(floor(t / 86400000)), year, month, day);
7868
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00007869 FixedArrayBase* elms_base = FixedArrayBase::cast(res_array->elements());
7870 RUNTIME_ASSERT(elms_base->length() == 3);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007871 RUNTIME_ASSERT(res_array->HasFastTypeElements());
ricow@chromium.org0b9f8502010-08-18 07:45:01 +00007872
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007873 MaybeObject* maybe = res_array->EnsureWritableFastElements();
7874 if (maybe->IsFailure()) return maybe;
7875 FixedArray* elms = FixedArray::cast(res_array->elements());
7876 elms->set(0, Smi::FromInt(year));
7877 elms->set(1, Smi::FromInt(month));
7878 elms->set(2, Smi::FromInt(day));
vegorov@chromium.orgf8372902010-03-15 10:26:20 +00007879
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007880 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00007881}
7882
7883
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00007884RUNTIME_FUNCTION(MaybeObject*, Runtime_NewArgumentsFast) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007885 HandleScope scope(isolate);
7886 ASSERT(args.length() == 3);
7887
7888 Handle<JSFunction> callee = args.at<JSFunction>(0);
7889 Object** parameters = reinterpret_cast<Object**>(args[1]);
7890 const int argument_count = Smi::cast(args[2])->value();
7891
7892 Handle<JSObject> result =
7893 isolate->factory()->NewArgumentsObject(callee, argument_count);
7894 // Allocate the elements if needed.
7895 int parameter_count = callee->shared()->formal_parameter_count();
7896 if (argument_count > 0) {
7897 if (parameter_count > 0) {
7898 int mapped_count = Min(argument_count, parameter_count);
7899 Handle<FixedArray> parameter_map =
7900 isolate->factory()->NewFixedArray(mapped_count + 2, NOT_TENURED);
7901 parameter_map->set_map(
7902 isolate->heap()->non_strict_arguments_elements_map());
7903
7904 Handle<Map> old_map(result->map());
7905 Handle<Map> new_map =
7906 isolate->factory()->CopyMapDropTransitions(old_map);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00007907 new_map->set_elements_kind(NON_STRICT_ARGUMENTS_ELEMENTS);
whesse@chromium.org7b260152011-06-20 15:33:18 +00007908
7909 result->set_map(*new_map);
7910 result->set_elements(*parameter_map);
7911
7912 // Store the context and the arguments array at the beginning of the
7913 // parameter map.
7914 Handle<Context> context(isolate->context());
7915 Handle<FixedArray> arguments =
7916 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7917 parameter_map->set(0, *context);
7918 parameter_map->set(1, *arguments);
7919
7920 // Loop over the actual parameters backwards.
7921 int index = argument_count - 1;
7922 while (index >= mapped_count) {
7923 // These go directly in the arguments array and have no
7924 // corresponding slot in the parameter map.
7925 arguments->set(index, *(parameters - index - 1));
7926 --index;
7927 }
7928
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007929 Handle<ScopeInfo> scope_info(callee->shared()->scope_info());
whesse@chromium.org7b260152011-06-20 15:33:18 +00007930 while (index >= 0) {
7931 // Detect duplicate names to the right in the parameter list.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007932 Handle<String> name(scope_info->ParameterName(index));
7933 int context_local_count = scope_info->ContextLocalCount();
whesse@chromium.org7b260152011-06-20 15:33:18 +00007934 bool duplicate = false;
7935 for (int j = index + 1; j < parameter_count; ++j) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007936 if (scope_info->ParameterName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007937 duplicate = true;
7938 break;
7939 }
7940 }
7941
7942 if (duplicate) {
7943 // This goes directly in the arguments array with a hole in the
7944 // parameter map.
7945 arguments->set(index, *(parameters - index - 1));
7946 parameter_map->set_the_hole(index + 2);
7947 } else {
7948 // The context index goes in the parameter map with a hole in the
7949 // arguments array.
7950 int context_index = -1;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007951 for (int j = 0; j < context_local_count; ++j) {
7952 if (scope_info->ContextLocalName(j) == *name) {
whesse@chromium.org7b260152011-06-20 15:33:18 +00007953 context_index = j;
7954 break;
7955 }
7956 }
7957 ASSERT(context_index >= 0);
7958 arguments->set_the_hole(index);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00007959 parameter_map->set(index + 2, Smi::FromInt(
7960 Context::MIN_CONTEXT_SLOTS + context_index));
whesse@chromium.org7b260152011-06-20 15:33:18 +00007961 }
7962
7963 --index;
7964 }
7965 } else {
7966 // If there is no aliasing, the arguments object elements are not
7967 // special in any way.
7968 Handle<FixedArray> elements =
7969 isolate->factory()->NewFixedArray(argument_count, NOT_TENURED);
7970 result->set_elements(*elements);
7971 for (int i = 0; i < argument_count; ++i) {
7972 elements->set(i, *(parameters - i - 1));
7973 }
7974 }
7975 }
7976 return *result;
7977}
7978
7979
7980RUNTIME_FUNCTION(MaybeObject*, Runtime_NewStrictArgumentsFast) {
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007981 NoHandleAllocation ha;
7982 ASSERT(args.length() == 3);
7983
7984 JSFunction* callee = JSFunction::cast(args[0]);
7985 Object** parameters = reinterpret_cast<Object**>(args[1]);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00007986 const int length = args.smi_at(2);
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00007987
lrn@chromium.org303ada72010-10-27 09:33:13 +00007988 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007989 { MaybeObject* maybe_result =
7990 isolate->heap()->AllocateArgumentsObject(callee, length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007991 if (!maybe_result->ToObject(&result)) return maybe_result;
7992 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00007993 // Allocate the elements if needed.
7994 if (length > 0) {
7995 // Allocate the fixed array.
lrn@chromium.org303ada72010-10-27 09:33:13 +00007996 Object* obj;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00007997 { MaybeObject* maybe_obj = isolate->heap()->AllocateRawFixedArray(length);
lrn@chromium.org303ada72010-10-27 09:33:13 +00007998 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
7999 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008000
8001 AssertNoAllocation no_gc;
ricow@chromium.org30ce4112010-05-31 10:38:25 +00008002 FixedArray* array = reinterpret_cast<FixedArray*>(obj);
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008003 array->set_map_no_write_barrier(isolate->heap()->fixed_array_map());
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008004 array->set_length(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +00008005
8006 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008007 for (int i = 0; i < length; i++) {
8008 array->set(i, *--parameters, mode);
8009 }
ager@chromium.orgc4c92722009-11-18 14:12:51 +00008010 JSObject::cast(result)->set_elements(FixedArray::cast(obj));
kasperl@chromium.org41044eb2008-10-06 08:24:46 +00008011 }
8012 return result;
8013}
8014
8015
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008016RUNTIME_FUNCTION(MaybeObject*, Runtime_NewClosure) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008017 HandleScope scope(isolate);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008018 ASSERT(args.length() == 3);
ager@chromium.org3811b432009-10-28 14:53:37 +00008019 CONVERT_ARG_CHECKED(Context, context, 0);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00008020 CONVERT_ARG_CHECKED(SharedFunctionInfo, shared, 1);
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008021 CONVERT_BOOLEAN_CHECKED(pretenure, args[2]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008022
whesse@chromium.org7b260152011-06-20 15:33:18 +00008023 // The caller ensures that we pretenure closures that are assigned
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008024 // directly to properties.
vegorov@chromium.org21b5e952010-11-23 10:24:40 +00008025 PretenureFlag pretenure_flag = pretenure ? TENURED : NOT_TENURED;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008026 Handle<JSFunction> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008027 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
8028 context,
8029 pretenure_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008030 return *result;
8031}
8032
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008033
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008034// Find the arguments of the JavaScript function invocation that called
8035// into C++ code. Collect these in a newly allocated array of handles (possibly
8036// prefixed by a number of empty handles).
8037static SmartArrayPointer<Handle<Object> > GetCallerArguments(
8038 int prefix_argc,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008039 int* total_argc) {
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008040 // Find frame containing arguments passed to the caller.
8041 JavaScriptFrameIterator it;
8042 JavaScriptFrame* frame = it.frame();
8043 List<JSFunction*> functions(2);
8044 frame->GetFunctions(&functions);
8045 if (functions.length() > 1) {
8046 int inlined_frame_index = functions.length() - 1;
8047 JSFunction* inlined_function = functions[inlined_frame_index];
8048 int args_count = inlined_function->shared()->formal_parameter_count();
8049 ScopedVector<SlotRef> args_slots(args_count);
8050 SlotRef::ComputeSlotMappingForArguments(frame,
8051 inlined_frame_index,
8052 &args_slots);
8053
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008054 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008055 SmartArrayPointer<Handle<Object> > param_data(
8056 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008057 for (int i = 0; i < args_count; i++) {
8058 Handle<Object> val = args_slots[i].GetValue();
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008059 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008060 }
8061 return param_data;
8062 } else {
8063 it.AdvanceToArgumentsFrame();
8064 frame = it.frame();
8065 int args_count = frame->ComputeParametersCount();
8066
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008067 *total_argc = prefix_argc + args_count;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008068 SmartArrayPointer<Handle<Object> > param_data(
8069 NewArray<Handle<Object> >(*total_argc));
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008070 for (int i = 0; i < args_count; i++) {
8071 Handle<Object> val = Handle<Object>(frame->GetParameter(i));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008072 param_data[prefix_argc + i] = val;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008073 }
8074 return param_data;
8075 }
8076}
8077
8078
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008079RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionBindArguments) {
8080 HandleScope scope(isolate);
8081 ASSERT(args.length() == 4);
8082 CONVERT_ARG_CHECKED(JSFunction, bound_function, 0);
8083 RUNTIME_ASSERT(args[3]->IsNumber());
8084 Handle<Object> bindee = args.at<Object>(1);
8085
8086 // TODO(lrn): Create bound function in C++ code from premade shared info.
8087 bound_function->shared()->set_bound(true);
8088 // Get all arguments of calling function (Function.prototype.bind).
8089 int argc = 0;
8090 SmartArrayPointer<Handle<Object> > arguments = GetCallerArguments(0, &argc);
8091 // Don't count the this-arg.
8092 if (argc > 0) {
8093 ASSERT(*arguments[0] == args[2]);
8094 argc--;
8095 } else {
8096 ASSERT(args[2]->IsUndefined());
8097 }
8098 // Initialize array of bindings (function, this, and any existing arguments
8099 // if the function was already bound).
8100 Handle<FixedArray> new_bindings;
8101 int i;
8102 if (bindee->IsJSFunction() && JSFunction::cast(*bindee)->shared()->bound()) {
8103 Handle<FixedArray> old_bindings(
8104 JSFunction::cast(*bindee)->function_bindings());
8105 new_bindings =
8106 isolate->factory()->NewFixedArray(old_bindings->length() + argc);
8107 bindee = Handle<Object>(old_bindings->get(JSFunction::kBoundFunctionIndex));
8108 i = 0;
8109 for (int n = old_bindings->length(); i < n; i++) {
8110 new_bindings->set(i, old_bindings->get(i));
8111 }
8112 } else {
8113 int array_size = JSFunction::kBoundArgumentsStartIndex + argc;
8114 new_bindings = isolate->factory()->NewFixedArray(array_size);
8115 new_bindings->set(JSFunction::kBoundFunctionIndex, *bindee);
8116 new_bindings->set(JSFunction::kBoundThisIndex, args[2]);
8117 i = 2;
8118 }
8119 // Copy arguments, skipping the first which is "this_arg".
8120 for (int j = 0; j < argc; j++, i++) {
8121 new_bindings->set(i, *arguments[j + 1]);
8122 }
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00008123 new_bindings->set_map_no_write_barrier(
8124 isolate->heap()->fixed_cow_array_map());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008125 bound_function->set_function_bindings(*new_bindings);
8126
8127 // Update length.
8128 Handle<String> length_symbol = isolate->factory()->length_symbol();
8129 Handle<Object> new_length(args.at<Object>(3));
8130 PropertyAttributes attr =
8131 static_cast<PropertyAttributes>(DONT_DELETE | DONT_ENUM | READ_ONLY);
8132 ForceSetProperty(bound_function, length_symbol, new_length, attr);
8133 return *bound_function;
8134}
8135
8136
8137RUNTIME_FUNCTION(MaybeObject*, Runtime_BoundFunctionGetBindings) {
8138 HandleScope handles(isolate);
8139 ASSERT(args.length() == 1);
danno@chromium.org2c456792011-11-11 12:00:53 +00008140 CONVERT_ARG_CHECKED(JSReceiver, callable, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008141 if (callable->IsJSFunction()) {
8142 Handle<JSFunction> function = Handle<JSFunction>::cast(callable);
8143 if (function->shared()->bound()) {
8144 Handle<FixedArray> bindings(function->function_bindings());
8145 ASSERT(bindings->map() == isolate->heap()->fixed_cow_array_map());
8146 return *isolate->factory()->NewJSArrayWithElements(bindings);
8147 }
8148 }
8149 return isolate->heap()->undefined_value();
8150}
8151
8152
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008153RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObjectFromBound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008154 HandleScope scope(isolate);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008155 ASSERT(args.length() == 1);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008156 // First argument is a function to use as a constructor.
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008157 CONVERT_ARG_CHECKED(JSFunction, function, 0);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008158 RUNTIME_ASSERT(function->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008159
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008160 // The argument is a bound function. Extract its bound arguments
8161 // and callable.
8162 Handle<FixedArray> bound_args =
8163 Handle<FixedArray>(FixedArray::cast(function->function_bindings()));
8164 int bound_argc = bound_args->length() - JSFunction::kBoundArgumentsStartIndex;
8165 Handle<Object> bound_function(
8166 JSReceiver::cast(bound_args->get(JSFunction::kBoundFunctionIndex)));
8167 ASSERT(!bound_function->IsJSFunction() ||
8168 !Handle<JSFunction>::cast(bound_function)->shared()->bound());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008169
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008170 int total_argc = 0;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008171 SmartArrayPointer<Handle<Object> > param_data =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008172 GetCallerArguments(bound_argc, &total_argc);
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008173 for (int i = 0; i < bound_argc; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008174 param_data[i] = Handle<Object>(bound_args->get(
8175 JSFunction::kBoundArgumentsStartIndex + i));
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008176 }
8177
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008178 if (!bound_function->IsJSFunction()) {
8179 bool exception_thrown;
8180 bound_function = Execution::TryGetConstructorDelegate(bound_function,
8181 &exception_thrown);
8182 if (exception_thrown) return Failure::Exception();
8183 }
8184 ASSERT(bound_function->IsJSFunction());
8185
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008186 bool exception = false;
erik.corry@gmail.comd91075f2011-02-10 07:45:38 +00008187 Handle<Object> result =
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008188 Execution::New(Handle<JSFunction>::cast(bound_function),
8189 total_argc, *param_data, &exception);
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008190 if (exception) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008191 return Failure::Exception();
whesse@chromium.orge90029b2010-08-02 11:52:17 +00008192 }
8193 ASSERT(!result.is_null());
whesse@chromium.orgba5a61b2010-07-26 11:44:40 +00008194 return *result;
8195}
8196
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008197
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008198static void TrySettingInlineConstructStub(Isolate* isolate,
8199 Handle<JSFunction> function) {
8200 Handle<Object> prototype = isolate->factory()->null_value();
ager@chromium.org5c838252010-02-19 08:53:10 +00008201 if (function->has_instance_prototype()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008202 prototype = Handle<Object>(function->instance_prototype(), isolate);
ager@chromium.org5c838252010-02-19 08:53:10 +00008203 }
8204 if (function->shared()->CanGenerateInlineConstructor(*prototype)) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008205 ConstructStubCompiler compiler(isolate);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008206 Handle<Code> code = compiler.CompileConstructStub(function);
8207 function->shared()->set_construct_stub(*code);
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008208 }
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008209}
8210
8211
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008212RUNTIME_FUNCTION(MaybeObject*, Runtime_NewObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008213 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008214 ASSERT(args.length() == 1);
8215
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008216 Handle<Object> constructor = args.at<Object>(0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008217
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008218 // If the constructor isn't a proper function we throw a type error.
8219 if (!constructor->IsJSFunction()) {
8220 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8221 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008222 isolate->factory()->NewTypeError("not_constructor", arguments);
8223 return isolate->Throw(*type_error);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008224 }
8225
8226 Handle<JSFunction> function = Handle<JSFunction>::cast(constructor);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008227
8228 // If function should not have prototype, construction is not allowed. In this
8229 // case generated code bailouts here, since function has no initial_map.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008230 if (!function->should_have_prototype() && !function->shared()->bound()) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008231 Vector< Handle<Object> > arguments = HandleVector(&constructor, 1);
8232 Handle<Object> type_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008233 isolate->factory()->NewTypeError("not_constructor", arguments);
8234 return isolate->Throw(*type_error);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +00008235 }
8236
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008237#ifdef ENABLE_DEBUGGER_SUPPORT
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008238 Debug* debug = isolate->debug();
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008239 // Handle stepping into constructors if step into is active.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008240 if (debug->StepInActive()) {
8241 debug->HandleStepIn(function, Handle<Object>::null(), 0, true);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008242 }
ager@chromium.org65dad4b2009-04-23 08:48:43 +00008243#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008244
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008245 if (function->has_initial_map()) {
8246 if (function->initial_map()->instance_type() == JS_FUNCTION_TYPE) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008247 // The 'Function' function ignores the receiver object when
8248 // called using 'new' and creates a new JSFunction object that
8249 // is returned. The receiver object is only used for error
8250 // reporting if an error occurs when constructing the new
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008251 // JSFunction. FACTORY->NewJSObject() should not be used to
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008252 // allocate JSFunctions since it does not properly initialize
8253 // the shared part of the function. Since the receiver is
8254 // ignored anyway, we use the global object as the receiver
8255 // instead of a new JSFunction object. This way, errors are
8256 // reported the same way whether or not 'Function' is called
8257 // using 'new'.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008258 return isolate->context()->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008259 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008260 }
8261
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008262 // The function should be compiled for the optimization hints to be
8263 // available. We cannot use EnsureCompiled because that forces a
8264 // compilation through the shared function info which makes it
8265 // impossible for us to optimize.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008266 if (!function->is_compiled()) {
8267 JSFunction::CompileLazy(function, CLEAR_EXCEPTION);
8268 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008269
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008270 Handle<SharedFunctionInfo> shared(function->shared(), isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008271 if (!function->has_initial_map() &&
8272 shared->IsInobjectSlackTrackingInProgress()) {
8273 // The tracking is already in progress for another function. We can only
8274 // track one initial_map at a time, so we force the completion before the
8275 // function is called as a constructor for the first time.
8276 shared->CompleteInobjectSlackTracking();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008277 }
8278
8279 bool first_allocation = !shared->live_objects_may_exist();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008280 Handle<JSObject> result = isolate->factory()->NewJSObject(function);
8281 RETURN_IF_EMPTY_HANDLE(isolate, result);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008282 // Delay setting the stub if inobject slack tracking is in progress.
8283 if (first_allocation && !shared->IsInobjectSlackTrackingInProgress()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008284 TrySettingInlineConstructStub(isolate, function);
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008285 }
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008286
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008287 isolate->counters()->constructed_objects()->Increment();
8288 isolate->counters()->constructed_objects_runtime()->Increment();
ager@chromium.org18ad94b2009-09-02 08:22:29 +00008289
ager@chromium.org5aa501c2009-06-23 07:57:28 +00008290 return *result;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008291}
8292
8293
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008294RUNTIME_FUNCTION(MaybeObject*, Runtime_FinalizeInstanceSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008295 HandleScope scope(isolate);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008296 ASSERT(args.length() == 1);
8297
8298 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8299 function->shared()->CompleteInobjectSlackTracking();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008300 TrySettingInlineConstructStub(isolate, function);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008301
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008302 return isolate->heap()->undefined_value();
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +00008303}
8304
8305
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008306RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyCompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008307 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008308 ASSERT(args.length() == 1);
8309
8310 Handle<JSFunction> function = args.at<JSFunction>(0);
8311#ifdef DEBUG
vegorov@chromium.org26c16f82010-08-11 13:41:03 +00008312 if (FLAG_trace_lazy && !function->shared()->is_compiled()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008313 PrintF("[lazy: ");
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008314 function->PrintName();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008315 PrintF("]\n");
8316 }
8317#endif
8318
lrn@chromium.org34e60782011-09-15 07:25:40 +00008319 // Compile the target function.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008320 ASSERT(!function->is_compiled());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008321 if (!JSFunction::CompileLazy(function, KEEP_EXCEPTION)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008322 return Failure::Exception();
8323 }
8324
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008325 // All done. Return the compiled code.
8326 ASSERT(function->is_compiled());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008327 return function->code();
8328}
8329
8330
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008331RUNTIME_FUNCTION(MaybeObject*, Runtime_LazyRecompile) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008332 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008333 ASSERT(args.length() == 1);
8334 Handle<JSFunction> function = args.at<JSFunction>(0);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008335
8336 // If the function is not compiled ignore the lazy
8337 // recompilation. This can happen if the debugger is activated and
8338 // the function is returned to the not compiled state.
8339 if (!function->shared()->is_compiled()) {
8340 function->ReplaceCode(function->shared()->code());
8341 return function->code();
8342 }
8343
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008344 // If the function is not optimizable or debugger is active continue using the
8345 // code from the full compiler.
8346 if (!function->shared()->code()->optimizable() ||
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008347 isolate->DebuggerHasBreakPoints()) {
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008348 if (FLAG_trace_opt) {
8349 PrintF("[failed to optimize ");
8350 function->PrintName();
8351 PrintF(": is code optimizable: %s, is debugger enabled: %s]\n",
8352 function->shared()->code()->optimizable() ? "T" : "F",
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00008353 isolate->DebuggerHasBreakPoints() ? "T" : "F");
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008354 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008355 function->ReplaceCode(function->shared()->code());
8356 return function->code();
8357 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008358 if (JSFunction::CompileOptimized(function,
8359 AstNode::kNoNumber,
8360 CLEAR_EXCEPTION)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008361 return function->code();
8362 }
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +00008363 if (FLAG_trace_opt) {
8364 PrintF("[failed to optimize ");
8365 function->PrintName();
8366 PrintF(": optimized compilation failed]\n");
8367 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008368 function->ReplaceCode(function->shared()->code());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008369 return function->code();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008370}
8371
8372
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008373class ActivationsFinder : public ThreadVisitor {
8374 public:
8375 explicit ActivationsFinder(JSFunction* function)
8376 : function_(function), has_activations_(false) {}
8377
8378 void VisitThread(Isolate* isolate, ThreadLocalTop* top) {
8379 if (has_activations_) return;
8380
8381 for (JavaScriptFrameIterator it(isolate, top); !it.done(); it.Advance()) {
8382 JavaScriptFrame* frame = it.frame();
8383 if (frame->is_optimized() && frame->function() == function_) {
8384 has_activations_ = true;
8385 return;
8386 }
8387 }
8388 }
8389
8390 bool has_activations() { return has_activations_; }
8391
8392 private:
8393 JSFunction* function_;
8394 bool has_activations_;
8395};
8396
8397
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008398RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyDeoptimized) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008399 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008400 ASSERT(args.length() == 1);
8401 RUNTIME_ASSERT(args[0]->IsSmi());
8402 Deoptimizer::BailoutType type =
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008403 static_cast<Deoptimizer::BailoutType>(args.smi_at(0));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008404 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
8405 ASSERT(isolate->heap()->IsAllocationAllowed());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008406 int frames = deoptimizer->output_count();
8407
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008408 deoptimizer->MaterializeHeapNumbers();
8409 delete deoptimizer;
8410
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008411 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008412 JavaScriptFrame* frame = NULL;
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00008413 for (int i = 0; i < frames - 1; i++) it.Advance();
8414 frame = it.frame();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008415
8416 RUNTIME_ASSERT(frame->function()->IsJSFunction());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008417 Handle<JSFunction> function(JSFunction::cast(frame->function()), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008418 Handle<Object> arguments;
8419 for (int i = frame->ComputeExpressionsCount() - 1; i >= 0; --i) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008420 if (frame->GetExpression(i) == isolate->heap()->arguments_marker()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008421 if (arguments.is_null()) {
8422 // FunctionGetArguments can't throw an exception, so cast away the
8423 // doubt with an assert.
8424 arguments = Handle<Object>(
8425 Accessors::FunctionGetArguments(*function,
8426 NULL)->ToObjectUnchecked());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008427 ASSERT(*arguments != isolate->heap()->null_value());
8428 ASSERT(*arguments != isolate->heap()->undefined_value());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008429 }
8430 frame->SetExpression(i, *arguments);
8431 }
8432 }
8433
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008434 if (type == Deoptimizer::EAGER) {
8435 RUNTIME_ASSERT(function->IsOptimized());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008436 }
8437
8438 // Avoid doing too much work when running with --always-opt and keep
8439 // the optimized code around.
8440 if (FLAG_always_opt || type == Deoptimizer::LAZY) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008441 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008442 }
8443
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008444 // Find other optimized activations of the function.
8445 bool has_other_activations = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008446 while (!it.done()) {
8447 JavaScriptFrame* frame = it.frame();
8448 if (frame->is_optimized() && frame->function() == *function) {
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008449 has_other_activations = true;
8450 break;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008451 }
8452 it.Advance();
8453 }
8454
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +00008455 if (!has_other_activations) {
8456 ActivationsFinder activations_finder(*function);
8457 isolate->thread_manager()->IterateArchivedThreads(&activations_finder);
8458 has_other_activations = activations_finder.has_activations();
8459 }
8460
8461 if (!has_other_activations) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008462 if (FLAG_trace_deopt) {
8463 PrintF("[removing optimized code for: ");
8464 function->PrintName();
8465 PrintF("]\n");
8466 }
8467 function->ReplaceCode(function->shared()->code());
lrn@chromium.org34e60782011-09-15 07:25:40 +00008468 } else {
8469 Deoptimizer::DeoptimizeFunction(*function);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008470 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008471 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008472}
8473
8474
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008475RUNTIME_FUNCTION(MaybeObject*, Runtime_NotifyOSR) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008476 Deoptimizer* deoptimizer = Deoptimizer::Grab(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008477 delete deoptimizer;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008478 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008479}
8480
8481
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008482RUNTIME_FUNCTION(MaybeObject*, Runtime_DeoptimizeFunction) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008483 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008484 ASSERT(args.length() == 1);
8485 CONVERT_ARG_CHECKED(JSFunction, function, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008486 if (!function->IsOptimized()) return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008487
8488 Deoptimizer::DeoptimizeFunction(*function);
8489
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008490 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008491}
8492
8493
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008494RUNTIME_FUNCTION(MaybeObject*, Runtime_RunningInSimulator) {
8495#if defined(USE_SIMULATOR)
8496 return isolate->heap()->true_value();
8497#else
8498 return isolate->heap()->false_value();
8499#endif
8500}
8501
8502
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00008503RUNTIME_FUNCTION(MaybeObject*, Runtime_OptimizeFunctionOnNextCall) {
8504 HandleScope scope(isolate);
8505 ASSERT(args.length() == 1);
8506 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8507 if (!function->IsOptimizable()) return isolate->heap()->undefined_value();
8508 function->MarkForLazyRecompilation();
8509 return isolate->heap()->undefined_value();
8510}
8511
8512
lrn@chromium.org1c092762011-05-09 09:42:16 +00008513RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationStatus) {
8514 HandleScope scope(isolate);
8515 ASSERT(args.length() == 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008516 // The least significant bit (after untagging) indicates whether the
8517 // function is currently optimized, regardless of reason.
lrn@chromium.org1c092762011-05-09 09:42:16 +00008518 if (!V8::UseCrankshaft()) {
8519 return Smi::FromInt(4); // 4 == "never".
8520 }
8521 if (FLAG_always_opt) {
8522 return Smi::FromInt(3); // 3 == "always".
8523 }
8524 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8525 return function->IsOptimized() ? Smi::FromInt(1) // 1 == "yes".
8526 : Smi::FromInt(2); // 2 == "no".
8527}
8528
8529
8530RUNTIME_FUNCTION(MaybeObject*, Runtime_GetOptimizationCount) {
8531 HandleScope scope(isolate);
8532 ASSERT(args.length() == 1);
8533 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8534 return Smi::FromInt(function->shared()->opt_count());
8535}
8536
8537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008538RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileForOnStackReplacement) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008539 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008540 ASSERT(args.length() == 1);
8541 CONVERT_ARG_CHECKED(JSFunction, function, 0);
8542
8543 // We're not prepared to handle a function with arguments object.
whesse@chromium.org7b260152011-06-20 15:33:18 +00008544 ASSERT(!function->shared()->uses_arguments());
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008545
8546 // We have hit a back edge in an unoptimized frame for a function that was
8547 // selected for on-stack replacement. Find the unoptimized code object.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008548 Handle<Code> unoptimized(function->shared()->code(), isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008549 // Keep track of whether we've succeeded in optimizing.
8550 bool succeeded = unoptimized->optimizable();
8551 if (succeeded) {
8552 // If we are trying to do OSR when there are already optimized
8553 // activations of the function, it means (a) the function is directly or
8554 // indirectly recursive and (b) an optimized invocation has been
8555 // deoptimized so that we are currently in an unoptimized activation.
8556 // Check for optimized activations of this function.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008557 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008558 while (succeeded && !it.done()) {
8559 JavaScriptFrame* frame = it.frame();
8560 succeeded = !frame->is_optimized() || frame->function() != *function;
8561 it.Advance();
8562 }
8563 }
8564
8565 int ast_id = AstNode::kNoNumber;
8566 if (succeeded) {
8567 // The top JS function is this one, the PC is somewhere in the
8568 // unoptimized code.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008569 JavaScriptFrameIterator it(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008570 JavaScriptFrame* frame = it.frame();
8571 ASSERT(frame->function() == *function);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00008572 ASSERT(frame->LookupCode() == *unoptimized);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008573 ASSERT(unoptimized->contains(frame->pc()));
8574
8575 // Use linear search of the unoptimized code's stack check table to find
8576 // the AST id matching the PC.
8577 Address start = unoptimized->instruction_start();
8578 unsigned target_pc_offset = static_cast<unsigned>(frame->pc() - start);
ricow@chromium.org83aa5492011-02-07 12:42:56 +00008579 Address table_cursor = start + unoptimized->stack_check_table_offset();
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008580 uint32_t table_length = Memory::uint32_at(table_cursor);
8581 table_cursor += kIntSize;
8582 for (unsigned i = 0; i < table_length; ++i) {
8583 // Table entries are (AST id, pc offset) pairs.
8584 uint32_t pc_offset = Memory::uint32_at(table_cursor + kIntSize);
8585 if (pc_offset == target_pc_offset) {
8586 ast_id = static_cast<int>(Memory::uint32_at(table_cursor));
8587 break;
8588 }
8589 table_cursor += 2 * kIntSize;
8590 }
8591 ASSERT(ast_id != AstNode::kNoNumber);
8592 if (FLAG_trace_osr) {
8593 PrintF("[replacing on-stack at AST id %d in ", ast_id);
8594 function->PrintName();
8595 PrintF("]\n");
8596 }
8597
8598 // Try to compile the optimized code. A true return value from
8599 // CompileOptimized means that compilation succeeded, not necessarily
8600 // that optimization succeeded.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008601 if (JSFunction::CompileOptimized(function, ast_id, CLEAR_EXCEPTION) &&
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008602 function->IsOptimized()) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008603 DeoptimizationInputData* data = DeoptimizationInputData::cast(
8604 function->code()->deoptimization_data());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008605 if (data->OsrPcOffset()->value() >= 0) {
8606 if (FLAG_trace_osr) {
8607 PrintF("[on-stack replacement offset %d in optimized code]\n",
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008608 data->OsrPcOffset()->value());
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00008609 }
8610 ASSERT(data->OsrAstId()->value() == ast_id);
8611 } else {
8612 // We may never generate the desired OSR entry if we emit an
8613 // early deoptimize.
8614 succeeded = false;
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008615 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008616 } else {
8617 succeeded = false;
8618 }
8619 }
8620
8621 // Revert to the original stack checks in the original unoptimized code.
8622 if (FLAG_trace_osr) {
8623 PrintF("[restoring original stack checks in ");
8624 function->PrintName();
8625 PrintF("]\n");
8626 }
8627 StackCheckStub check_stub;
8628 Handle<Code> check_code = check_stub.GetCode();
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +00008629 Handle<Code> replacement_code = isolate->builtins()->OnStackReplacement();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008630 Deoptimizer::RevertStackCheckCode(*unoptimized,
8631 *check_code,
8632 *replacement_code);
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008633
8634 // Allow OSR only at nesting level zero again.
8635 unoptimized->set_allow_osr_at_loop_nesting_level(0);
8636
8637 // If the optimization attempt succeeded, return the AST id tagged as a
8638 // smi. This tells the builtin that we need to translate the unoptimized
8639 // frame to an optimized one.
8640 if (succeeded) {
8641 ASSERT(function->code()->kind() == Code::OPTIMIZED_FUNCTION);
8642 return Smi::FromInt(ast_id);
8643 } else {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00008644 if (function->IsMarkedForLazyRecompilation()) {
8645 function->ReplaceCode(function->shared()->code());
8646 }
kasperl@chromium.orga5551262010-12-07 12:49:48 +00008647 return Smi::FromInt(-1);
8648 }
8649}
8650
8651
fschneider@chromium.org1805e212011-09-05 10:49:12 +00008652RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckIsBootstrapping) {
8653 RUNTIME_ASSERT(isolate->bootstrapper()->IsActive());
8654 return isolate->heap()->undefined_value();
8655}
8656
8657
danno@chromium.orgc612e022011-11-10 11:38:15 +00008658RUNTIME_FUNCTION(MaybeObject*, Runtime_Call) {
8659 HandleScope scope(isolate);
8660 ASSERT(args.length() >= 2);
8661 CONVERT_CHECKED(JSReceiver, fun, args[args.length() - 1]);
8662 Object* receiver = args[0];
8663 int argc = args.length() - 2;
8664
8665 // If there are too many arguments, allocate argv via malloc.
8666 const int argv_small_size = 10;
8667 Handle<Object> argv_small_buffer[argv_small_size];
8668 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8669 Handle<Object>* argv = argv_small_buffer;
8670 if (argc > argv_small_size) {
8671 argv = new Handle<Object>[argc];
8672 if (argv == NULL) return isolate->StackOverflow();
8673 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8674 }
8675
8676 for (int i = 0; i < argc; ++i) {
8677 MaybeObject* maybe = args[1 + i];
8678 Object* object;
8679 if (!maybe->To<Object>(&object)) return maybe;
8680 argv[i] = Handle<Object>(object);
8681 }
8682
8683 bool threw;
8684 Handle<JSReceiver> hfun(fun);
8685 Handle<Object> hreceiver(receiver);
8686 Handle<Object> result =
8687 Execution::Call(hfun, hreceiver, argc, argv, &threw, true);
8688
8689 if (threw) return Failure::Exception();
8690 return *result;
8691}
8692
8693
lrn@chromium.org34e60782011-09-15 07:25:40 +00008694RUNTIME_FUNCTION(MaybeObject*, Runtime_Apply) {
8695 HandleScope scope(isolate);
8696 ASSERT(args.length() == 5);
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008697 CONVERT_ARG_CHECKED(JSReceiver, fun, 0);
8698 Handle<Object> receiver = args.at<Object>(1);
8699 CONVERT_ARG_CHECKED(JSObject, arguments, 2);
8700 CONVERT_SMI_ARG_CHECKED(offset, 3);
8701 CONVERT_SMI_ARG_CHECKED(argc, 4);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008702 ASSERT(offset >= 0);
8703 ASSERT(argc >= 0);
8704
8705 // If there are too many arguments, allocate argv via malloc.
8706 const int argv_small_size = 10;
8707 Handle<Object> argv_small_buffer[argv_small_size];
8708 SmartArrayPointer<Handle<Object> > argv_large_buffer;
8709 Handle<Object>* argv = argv_small_buffer;
8710 if (argc > argv_small_size) {
8711 argv = new Handle<Object>[argc];
8712 if (argv == NULL) return isolate->StackOverflow();
8713 argv_large_buffer = SmartArrayPointer<Handle<Object> >(argv);
8714 }
8715
8716 for (int i = 0; i < argc; ++i) {
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008717 argv[i] = Object::GetElement(arguments, offset + i);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008718 }
8719
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008720 bool threw;
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +00008721 Handle<Object> result =
rossberg@chromium.orgfab14982012-01-05 15:02:15 +00008722 Execution::Call(fun, receiver, argc, argv, &threw, true);
lrn@chromium.org34e60782011-09-15 07:25:40 +00008723
8724 if (threw) return Failure::Exception();
8725 return *result;
8726}
8727
8728
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008729RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008730 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008731 ASSERT(args.length() == 1);
8732 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8733 return *Execution::GetFunctionDelegate(args.at<Object>(0));
8734}
8735
8736
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008737RUNTIME_FUNCTION(MaybeObject*, Runtime_GetConstructorDelegate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008738 HandleScope scope(isolate);
sgjesse@chromium.org05521fc2009-05-21 07:37:44 +00008739 ASSERT(args.length() == 1);
8740 RUNTIME_ASSERT(!args[0]->IsJSFunction());
8741 return *Execution::GetConstructorDelegate(args.at<Object>(0));
8742}
8743
8744
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008745RUNTIME_FUNCTION(MaybeObject*, Runtime_NewFunctionContext) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008746 NoHandleAllocation ha;
kasper.lund7276f142008-07-30 08:49:36 +00008747 ASSERT(args.length() == 1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008748
kasper.lund7276f142008-07-30 08:49:36 +00008749 CONVERT_CHECKED(JSFunction, function, args[0]);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008750 int length = function->shared()->scope_info()->ContextLength();
lrn@chromium.org303ada72010-10-27 09:33:13 +00008751 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008752 { MaybeObject* maybe_result =
8753 isolate->heap()->AllocateFunctionContext(length, function);
lrn@chromium.org303ada72010-10-27 09:33:13 +00008754 if (!maybe_result->ToObject(&result)) return maybe_result;
8755 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008756
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008757 isolate->set_context(Context::cast(result));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008758
kasper.lund7276f142008-07-30 08:49:36 +00008759 return result; // non-failure
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008760}
8761
lrn@chromium.org303ada72010-10-27 09:33:13 +00008762
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008763RUNTIME_FUNCTION(MaybeObject*, Runtime_PushWithContext) {
8764 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008765 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008766 JSObject* extension_object;
8767 if (args[0]->IsJSObject()) {
8768 extension_object = JSObject::cast(args[0]);
8769 } else {
8770 // Convert the object to a proper JavaScript object.
8771 MaybeObject* maybe_js_object = args[0]->ToObject();
8772 if (!maybe_js_object->To(&extension_object)) {
8773 if (Failure::cast(maybe_js_object)->IsInternalError()) {
8774 HandleScope scope(isolate);
8775 Handle<Object> handle = args.at<Object>(0);
8776 Handle<Object> result =
8777 isolate->factory()->NewTypeError("with_expression",
8778 HandleVector(&handle, 1));
8779 return isolate->Throw(*result);
8780 } else {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008781 return maybe_js_object;
8782 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008783 }
8784 }
8785
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008786 JSFunction* function;
8787 if (args[1]->IsSmi()) {
8788 // A smi sentinel indicates a context nested inside global code rather
8789 // than some function. There is a canonical empty function that can be
8790 // gotten from the global context.
8791 function = isolate->context()->global_context()->closure();
8792 } else {
8793 function = JSFunction::cast(args[1]);
8794 }
8795
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008796 Context* context;
8797 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008798 isolate->heap()->AllocateWithContext(function,
8799 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008800 extension_object);
8801 if (!maybe_context->To(&context)) return maybe_context;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008802 isolate->set_context(context);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008803 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008804}
8805
8806
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008807RUNTIME_FUNCTION(MaybeObject*, Runtime_PushCatchContext) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008808 NoHandleAllocation ha;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008809 ASSERT(args.length() == 3);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008810 String* name = String::cast(args[0]);
8811 Object* thrown_object = args[1];
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008812 JSFunction* function;
8813 if (args[2]->IsSmi()) {
8814 // A smi sentinel indicates a context nested inside global code rather
8815 // than some function. There is a canonical empty function that can be
8816 // gotten from the global context.
8817 function = isolate->context()->global_context()->closure();
8818 } else {
8819 function = JSFunction::cast(args[2]);
8820 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008821 Context* context;
8822 MaybeObject* maybe_context =
vegorov@chromium.org3cf47312011-06-29 13:20:01 +00008823 isolate->heap()->AllocateCatchContext(function,
8824 isolate->context(),
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00008825 name,
8826 thrown_object);
8827 if (!maybe_context->To(&context)) return maybe_context;
8828 isolate->set_context(context);
8829 return context;
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00008830}
8831
8832
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008833RUNTIME_FUNCTION(MaybeObject*, Runtime_PushBlockContext) {
8834 NoHandleAllocation ha;
8835 ASSERT(args.length() == 2);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00008836 ScopeInfo* scope_info = ScopeInfo::cast(args[0]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +00008837 JSFunction* function;
8838 if (args[1]->IsSmi()) {
8839 // A smi sentinel indicates a context nested inside global code rather
8840 // than some function. There is a canonical empty function that can be
8841 // gotten from the global context.
8842 function = isolate->context()->global_context()->closure();
8843 } else {
8844 function = JSFunction::cast(args[1]);
8845 }
8846 Context* context;
8847 MaybeObject* maybe_context =
8848 isolate->heap()->AllocateBlockContext(function,
8849 isolate->context(),
8850 scope_info);
8851 if (!maybe_context->To(&context)) return maybe_context;
8852 isolate->set_context(context);
8853 return context;
8854}
8855
8856
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00008857RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008858 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008859 ASSERT(args.length() == 2);
8860
8861 CONVERT_ARG_CHECKED(Context, context, 0);
8862 CONVERT_ARG_CHECKED(String, name, 1);
8863
8864 int index;
8865 PropertyAttributes attributes;
8866 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008867 BindingFlags binding_flags;
8868 Handle<Object> holder = context->Lookup(name,
8869 flags,
8870 &index,
8871 &attributes,
8872 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008873
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008874 // If the slot was not found the result is true.
8875 if (holder.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008876 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008877 }
8878
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008879 // If the slot was found in a context, it should be DONT_DELETE.
8880 if (holder->IsContext()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008881 return isolate->heap()->false_value();
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008882 }
8883
8884 // The slot was found in a JSObject, either a context extension object,
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008885 // the global object, or the subject of a with. Try to delete it
8886 // (respecting DONT_DELETE).
ager@chromium.org0ee099b2011-01-25 14:06:47 +00008887 Handle<JSObject> object = Handle<JSObject>::cast(holder);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008888 return object->DeleteProperty(*name, JSReceiver::NORMAL_DELETION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008889}
8890
8891
ager@chromium.orga1645e22009-09-09 19:27:10 +00008892// A mechanism to return a pair of Object pointers in registers (if possible).
8893// How this is achieved is calling convention-dependent.
8894// All currently supported x86 compiles uses calling conventions that are cdecl
8895// variants where a 64-bit value is returned in two 32-bit registers
8896// (edx:eax on ia32, r1:r0 on ARM).
8897// In AMD-64 calling convention a struct of two pointers is returned in rdx:rax.
8898// In Win64 calling convention, a struct of two pointers is returned in memory,
8899// allocated by the caller, and passed as a pointer in a hidden first parameter.
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008900#ifdef V8_HOST_ARCH_64_BIT
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008901struct ObjectPair {
lrn@chromium.org303ada72010-10-27 09:33:13 +00008902 MaybeObject* x;
8903 MaybeObject* y;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008904};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008905
lrn@chromium.org303ada72010-10-27 09:33:13 +00008906static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008907 ObjectPair result = {x, y};
ager@chromium.orga1645e22009-09-09 19:27:10 +00008908 // Pointers x and y returned in rax and rdx, in AMD-x64-abi.
8909 // In Win64 they are assigned to a hidden first argument.
8910 return result;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008911}
8912#else
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008913typedef uint64_t ObjectPair;
lrn@chromium.org303ada72010-10-27 09:33:13 +00008914static inline ObjectPair MakePair(MaybeObject* x, MaybeObject* y) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008915 return reinterpret_cast<uint32_t>(x) |
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008916 (reinterpret_cast<ObjectPair>(y) << 32);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008917}
kasperl@chromium.org2abc4502009-07-02 07:00:29 +00008918#endif
8919
8920
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008921static inline MaybeObject* Unhole(Heap* heap,
8922 MaybeObject* x,
lrn@chromium.org303ada72010-10-27 09:33:13 +00008923 PropertyAttributes attributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008924 ASSERT(!x->IsTheHole() || (attributes & READ_ONLY) != 0);
8925 USE(attributes);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008926 return x->IsTheHole() ? heap->undefined_value() : x;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008927}
8928
8929
danno@chromium.org40cb8782011-05-25 07:58:50 +00008930static Object* ComputeReceiverForNonGlobal(Isolate* isolate,
8931 JSObject* holder) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008932 ASSERT(!holder->IsGlobalObject());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008933 Context* top = isolate->context();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008934 // Get the context extension function.
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008935 JSFunction* context_extension_function =
8936 top->global_context()->context_extension_function();
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008937 // If the holder isn't a context extension object, we just return it
8938 // as the receiver. This allows arguments objects to be used as
8939 // receivers, but only if they are put in the context scope chain
8940 // explicitly via a with-statement.
8941 Object* constructor = holder->map()->constructor();
8942 if (constructor != context_extension_function) return holder;
danno@chromium.org40cb8782011-05-25 07:58:50 +00008943 // Fall back to using the global object as the implicit receiver if
8944 // the property turns out to be a local variable allocated in a
8945 // context extension object - introduced via eval. Implicit global
8946 // receivers are indicated with the hole value.
8947 return isolate->heap()->the_hole_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00008948}
8949
8950
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008951static ObjectPair LoadContextSlotHelper(Arguments args,
8952 Isolate* isolate,
8953 bool throw_error) {
8954 HandleScope scope(isolate);
ager@chromium.orga1645e22009-09-09 19:27:10 +00008955 ASSERT_EQ(2, args.length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008956
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008957 if (!args[0]->IsContext() || !args[1]->IsString()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00008958 return MakePair(isolate->ThrowIllegalOperation(), NULL);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008959 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008960 Handle<Context> context = args.at<Context>(0);
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00008961 Handle<String> name = args.at<String>(1);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008962
8963 int index;
8964 PropertyAttributes attributes;
8965 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008966 BindingFlags binding_flags;
8967 Handle<Object> holder = context->Lookup(name,
8968 flags,
8969 &index,
8970 &attributes,
8971 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008972
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008973 // If the index is non-negative, the slot has been found in a context.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00008974 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008975 ASSERT(holder->IsContext());
8976 // If the "property" we were looking for is a local variable, the
8977 // receiver is the global object; see ECMA-262, 3rd., 10.1.6 and 10.2.3.
danno@chromium.org40cb8782011-05-25 07:58:50 +00008978 //
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008979 // Use the hole as the receiver to signal that the receiver is implicit
8980 // and that the global receiver should be used (as distinguished from an
8981 // explicit receiver that happens to be a global object).
danno@chromium.org40cb8782011-05-25 07:58:50 +00008982 Handle<Object> receiver = isolate->factory()->the_hole_value();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00008983 Object* value = Context::cast(*holder)->get(index);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00008984 // Check for uninitialized bindings.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00008985 switch (binding_flags) {
8986 case MUTABLE_CHECK_INITIALIZED:
8987 case IMMUTABLE_CHECK_INITIALIZED_HARMONY:
8988 if (value->IsTheHole()) {
8989 Handle<Object> reference_error =
8990 isolate->factory()->NewReferenceError("not_defined",
8991 HandleVector(&name, 1));
8992 return MakePair(isolate->Throw(*reference_error), NULL);
8993 }
8994 // FALLTHROUGH
8995 case MUTABLE_IS_INITIALIZED:
8996 case IMMUTABLE_IS_INITIALIZED:
8997 case IMMUTABLE_IS_INITIALIZED_HARMONY:
8998 ASSERT(!value->IsTheHole());
8999 return MakePair(value, *receiver);
9000 case IMMUTABLE_CHECK_INITIALIZED:
9001 return MakePair(Unhole(isolate->heap(), value, attributes), *receiver);
9002 case MISSING_BINDING:
9003 UNREACHABLE();
9004 return MakePair(NULL, NULL);
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009005 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009006 }
9007
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009008 // Otherwise, if the slot was found the holder is a context extension
9009 // object, subject of a with, or a global object. We read the named
9010 // property from it.
9011 if (!holder.is_null()) {
9012 Handle<JSObject> object = Handle<JSObject>::cast(holder);
9013 ASSERT(object->HasProperty(*name));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009014 // GetProperty below can cause GC.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009015 Handle<Object> receiver_handle(object->IsGlobalObject()
9016 ? GlobalObject::cast(*object)->global_receiver()
9017 : ComputeReceiverForNonGlobal(isolate, *object));
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009018
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009019 // No need to unhole the value here. This is taken care of by the
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009020 // GetProperty function.
lrn@chromium.org303ada72010-10-27 09:33:13 +00009021 MaybeObject* value = object->GetProperty(*name);
vegorov@chromium.org7304bca2011-05-16 12:14:13 +00009022 return MakePair(value, *receiver_handle);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009023 }
9024
9025 if (throw_error) {
9026 // The property doesn't exist - throw exception.
9027 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009028 isolate->factory()->NewReferenceError("not_defined",
9029 HandleVector(&name, 1));
9030 return MakePair(isolate->Throw(*reference_error), NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009031 } else {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009032 // The property doesn't exist - return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009033 return MakePair(isolate->heap()->undefined_value(),
9034 isolate->heap()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009035 }
9036}
9037
9038
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009039RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009040 return LoadContextSlotHelper(args, isolate, true);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009041}
9042
9043
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009044RUNTIME_FUNCTION(ObjectPair, Runtime_LoadContextSlotNoReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009045 return LoadContextSlotHelper(args, isolate, false);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009046}
9047
9048
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009049RUNTIME_FUNCTION(MaybeObject*, Runtime_StoreContextSlot) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009050 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009051 ASSERT(args.length() == 4);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009052
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009053 Handle<Object> value(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009054 CONVERT_ARG_CHECKED(Context, context, 1);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +00009055 CONVERT_ARG_CHECKED(String, name, 2);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009056 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
9057 StrictModeFlag strict_mode = (language_mode == CLASSIC_MODE)
9058 ? kNonStrictMode : kStrictMode;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009059
9060 int index;
9061 PropertyAttributes attributes;
9062 ContextLookupFlags flags = FOLLOW_CHAINS;
yangguo@chromium.org80c42ed2011-08-31 09:03:56 +00009063 BindingFlags binding_flags;
9064 Handle<Object> holder = context->Lookup(name,
9065 flags,
9066 &index,
9067 &attributes,
9068 &binding_flags);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009069
9070 if (index >= 0) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009071 // The property was found in a context slot.
9072 Handle<Context> context = Handle<Context>::cast(holder);
9073 if (binding_flags == MUTABLE_CHECK_INITIALIZED &&
9074 context->get(index)->IsTheHole()) {
9075 Handle<Object> error =
9076 isolate->factory()->NewReferenceError("not_defined",
9077 HandleVector(&name, 1));
9078 return isolate->Throw(*error);
9079 }
9080 // Ignore if read_only variable.
9081 if ((attributes & READ_ONLY) == 0) {
9082 // Context is a fixed array and set cannot fail.
9083 context->set(index, *value);
9084 } else if (strict_mode == kStrictMode) {
9085 // Setting read only property in strict mode.
9086 Handle<Object> error =
9087 isolate->factory()->NewTypeError("strict_cannot_assign",
9088 HandleVector(&name, 1));
9089 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009090 }
9091 return *value;
9092 }
9093
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009094 // Slow case: The property is not in a context slot. It is either in a
9095 // context extension object, a property of the subject of a with, or a
9096 // property of the global object.
9097 Handle<JSObject> object;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009098
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009099 if (!holder.is_null()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009100 // The property exists on the holder.
9101 object = Handle<JSObject>::cast(holder);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009102 } else {
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009103 // The property was not found.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009104 ASSERT(attributes == ABSENT);
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009105
9106 if (strict_mode == kStrictMode) {
9107 // Throw in strict mode (assignment to undefined variable).
9108 Handle<Object> error =
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009109 isolate->factory()->NewReferenceError(
9110 "not_defined", HandleVector(&name, 1));
karlklose@chromium.org44bc7082011-04-11 12:33:05 +00009111 return isolate->Throw(*error);
9112 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009113 // In non-strict mode, the property is added to the global object.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009114 attributes = NONE;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009115 object = Handle<JSObject>(isolate->context()->global());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009116 }
9117
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009118 // Set the property if it's not read only or doesn't yet exist.
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009119 if ((attributes & READ_ONLY) == 0 ||
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009120 (object->GetLocalPropertyAttribute(*name) == ABSENT)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009121 RETURN_IF_EMPTY_HANDLE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009122 isolate,
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009123 JSReceiver::SetProperty(object, name, value, NONE, strict_mode));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009124 } else if (strict_mode == kStrictMode && (attributes & READ_ONLY) != 0) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009125 // Setting read only property in strict mode.
9126 Handle<Object> error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009127 isolate->factory()->NewTypeError(
9128 "strict_cannot_assign", HandleVector(&name, 1));
9129 return isolate->Throw(*error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009130 }
9131 return *value;
9132}
9133
9134
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009135RUNTIME_FUNCTION(MaybeObject*, Runtime_Throw) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009136 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009137 ASSERT(args.length() == 1);
9138
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009139 return isolate->Throw(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009140}
9141
9142
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009143RUNTIME_FUNCTION(MaybeObject*, Runtime_ReThrow) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009144 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009145 ASSERT(args.length() == 1);
9146
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009147 return isolate->ReThrow(args[0]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009148}
9149
9150
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009151RUNTIME_FUNCTION(MaybeObject*, Runtime_PromoteScheduledException) {
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009152 ASSERT_EQ(0, args.length());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009153 return isolate->PromoteScheduledException();
ager@chromium.orgc4c92722009-11-18 14:12:51 +00009154}
9155
9156
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009157RUNTIME_FUNCTION(MaybeObject*, Runtime_ThrowReferenceError) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009158 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009159 ASSERT(args.length() == 1);
9160
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009161 Handle<Object> name(args[0], isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009162 Handle<Object> reference_error =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009163 isolate->factory()->NewReferenceError("not_defined",
9164 HandleVector(&name, 1));
9165 return isolate->Throw(*reference_error);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009166}
9167
9168
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009169RUNTIME_FUNCTION(MaybeObject*, Runtime_StackGuard) {
whesse@chromium.org4a5224e2010-10-20 12:37:07 +00009170 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009171
9172 // First check if this is a real stack overflow.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009173 if (isolate->stack_guard()->IsStackOverflow()) {
9174 NoHandleAllocation na;
9175 return isolate->StackOverflow();
ager@chromium.orgddb913d2009-01-27 10:01:48 +00009176 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009177
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +00009178 return Execution::HandleStackGuardInterrupt();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009179}
9180
9181
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009182static int StackSize() {
9183 int n = 0;
9184 for (JavaScriptFrameIterator it; !it.done(); it.Advance()) n++;
9185 return n;
9186}
9187
9188
9189static void PrintTransition(Object* result) {
9190 // indentation
9191 { const int nmax = 80;
9192 int n = StackSize();
9193 if (n <= nmax)
9194 PrintF("%4d:%*s", n, n, "");
9195 else
9196 PrintF("%4d:%*s", n, nmax, "...");
9197 }
9198
9199 if (result == NULL) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009200 JavaScriptFrame::PrintTop(stdout, true, false);
9201 PrintF(" {\n");
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009202 } else {
9203 // function result
9204 PrintF("} -> ");
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009205 result->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009206 PrintF("\n");
9207 }
9208}
9209
9210
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009211RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceEnter) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009212 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009213 NoHandleAllocation ha;
9214 PrintTransition(NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009215 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009216}
9217
9218
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009219RUNTIME_FUNCTION(MaybeObject*, Runtime_TraceExit) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009220 NoHandleAllocation ha;
9221 PrintTransition(args[0]);
9222 return args[0]; // return TOS
9223}
9224
9225
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009226RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009227 NoHandleAllocation ha;
9228 ASSERT(args.length() == 1);
9229
9230#ifdef DEBUG
9231 if (args[0]->IsString()) {
9232 // If we have a string, assume it's a code "marker"
9233 // and print some interesting cpu debugging info.
vegorov@chromium.org74f333b2011-04-06 11:17:46 +00009234 JavaScriptFrameIterator it(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009235 JavaScriptFrame* frame = it.frame();
ager@chromium.orgeadaf222009-06-16 09:43:10 +00009236 PrintF("fp = %p, sp = %p, caller_sp = %p: ",
9237 frame->fp(), frame->sp(), frame->caller_sp());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009238 } else {
9239 PrintF("DebugPrint: ");
9240 }
9241 args[0]->Print();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009242 if (args[0]->IsHeapObject()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +00009243 PrintF("\n");
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +00009244 HeapObject::cast(args[0])->map()->Print();
9245 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009246#else
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009247 // ShortPrint is available in release mode. Print is not.
9248 args[0]->ShortPrint();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009249#endif
9250 PrintF("\n");
ager@chromium.org236ad962008-09-25 09:45:57 +00009251 Flush();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009252
9253 return args[0]; // return TOS
9254}
9255
9256
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009257RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugTrace) {
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +00009258 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009259 NoHandleAllocation ha;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009260 isolate->PrintStack();
9261 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009262}
9263
9264
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009265RUNTIME_FUNCTION(MaybeObject*, Runtime_DateCurrentTime) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009266 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009267 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009268
9269 // According to ECMA-262, section 15.9.1, page 117, the precision of
9270 // the number in a Date object representing a particular instant in
9271 // time is milliseconds. Therefore, we floor the result of getting
9272 // the OS time.
9273 double millis = floor(OS::TimeCurrentMillis());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009274 return isolate->heap()->NumberFromDouble(millis);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009275}
9276
9277
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009278RUNTIME_FUNCTION(MaybeObject*, Runtime_DateParseString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009279 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009280 ASSERT(args.length() == 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009281
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009282 CONVERT_ARG_CHECKED(String, str, 0);
9283 FlattenString(str);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009284
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009285 CONVERT_ARG_CHECKED(JSArray, output, 1);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009286
9287 MaybeObject* maybe_result_array =
ricow@chromium.org64e3a4b2011-12-13 08:07:27 +00009288 output->EnsureCanContainHeapObjectElements();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009289 if (maybe_result_array->IsFailure()) return maybe_result_array;
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009290 RUNTIME_ASSERT(output->HasFastElements());
9291
9292 AssertNoAllocation no_allocation;
9293
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009294 FixedArray* output_array = FixedArray::cast(output->elements());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009295 RUNTIME_ASSERT(output_array->length() >= DateParser::OUTPUT_SIZE);
9296 bool result;
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009297 String::FlatContent str_content = str->GetFlatContent();
9298 if (str_content.IsAscii()) {
9299 result = DateParser::Parse(str_content.ToAsciiVector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009300 output_array,
9301 isolate->unicode_cache());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009302 } else {
ricow@chromium.orgddd545c2011-08-24 12:02:41 +00009303 ASSERT(str_content.IsTwoByte());
9304 result = DateParser::Parse(str_content.ToUC16Vector(),
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +00009305 output_array,
9306 isolate->unicode_cache());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +00009307 }
9308
9309 if (result) {
9310 return *output;
9311 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009312 return isolate->heap()->null_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009313 }
9314}
9315
9316
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009317RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimezone) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009318 NoHandleAllocation ha;
9319 ASSERT(args.length() == 1);
9320
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009321 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgb9d7da12009-08-05 08:38:10 +00009322 const char* zone = OS::LocalTimezone(x);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009323 return isolate->heap()->AllocateStringFromUtf8(CStrVector(zone));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009324}
9325
9326
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009327RUNTIME_FUNCTION(MaybeObject*, Runtime_DateLocalTimeOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009328 NoHandleAllocation ha;
mads.s.ager31e71382008-08-13 09:32:07 +00009329 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009330
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009331 return isolate->heap()->NumberFromDouble(OS::LocalTimeOffset());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009332}
9333
9334
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009335RUNTIME_FUNCTION(MaybeObject*, Runtime_DateDaylightSavingsOffset) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009336 NoHandleAllocation ha;
9337 ASSERT(args.length() == 1);
9338
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +00009339 CONVERT_DOUBLE_ARG_CHECKED(x, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009340 return isolate->heap()->NumberFromDouble(OS::DaylightSavingsOffset(x));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009341}
9342
9343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009344RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalReceiver) {
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009345 ASSERT(args.length() == 1);
9346 Object* global = args[0];
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009347 if (!global->IsJSGlobalObject()) return isolate->heap()->null_value();
kasperl@chromium.org5a8ca6c2008-10-23 13:57:19 +00009348 return JSGlobalObject::cast(global)->global_receiver();
9349}
9350
9351
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009352RUNTIME_FUNCTION(MaybeObject*, Runtime_ParseJson) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009353 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009354 ASSERT_EQ(1, args.length());
9355 CONVERT_ARG_CHECKED(String, source, 0);
9356
jkummerow@chromium.orge297f592011-06-08 10:05:15 +00009357 source = Handle<String>(source->TryFlattenGetString());
9358 // Optimized fast case where we only have ascii characters.
9359 Handle<Object> result;
9360 if (source->IsSeqAsciiString()) {
9361 result = JsonParser<true>::Parse(source);
9362 } else {
9363 result = JsonParser<false>::Parse(source);
9364 }
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009365 if (result.is_null()) {
9366 // Syntax error or stack overflow in scanner.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009367 ASSERT(isolate->has_pending_exception());
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009368 return Failure::Exception();
9369 }
9370 return *result;
9371}
9372
9373
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009374bool CodeGenerationFromStringsAllowed(Isolate* isolate,
9375 Handle<Context> context) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009376 ASSERT(context->allow_code_gen_from_strings()->IsFalse());
9377 // Check with callback if set.
9378 AllowCodeGenerationFromStringsCallback callback =
9379 isolate->allow_code_gen_callback();
9380 if (callback == NULL) {
9381 // No callback set and code generation disallowed.
9382 return false;
9383 } else {
9384 // Callback set. Let it decide if code generation is allowed.
9385 VMState state(isolate, EXTERNAL);
9386 return callback(v8::Utils::ToLocal(context));
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009387 }
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009388}
9389
9390
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009391RUNTIME_FUNCTION(MaybeObject*, Runtime_CompileString) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009392 HandleScope scope(isolate);
fschneider@chromium.orge03fb642010-11-01 12:34:09 +00009393 ASSERT_EQ(1, args.length());
kasperl@chromium.orgb9123622008-09-17 14:05:56 +00009394 CONVERT_ARG_CHECKED(String, source, 0);
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009395
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009396 // Extract global context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009397 Handle<Context> context(isolate->context()->global_context());
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009398
9399 // Check if global context allows code generation from
9400 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009401 if (context->allow_code_gen_from_strings()->IsFalse() &&
9402 !CodeGenerationFromStringsAllowed(isolate, context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009403 return isolate->Throw(*isolate->factory()->NewError(
9404 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9405 }
9406
9407 // Compile source string in the global context.
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009408 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009409 source, context, true, CLASSIC_MODE, RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +00009410 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009411 Handle<JSFunction> fun =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009412 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
9413 context,
9414 NOT_TENURED);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009415 return *fun;
9416}
9417
9418
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009419static ObjectPair CompileGlobalEval(Isolate* isolate,
9420 Handle<String> source,
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009421 Handle<Object> receiver,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009422 LanguageMode language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009423 int scope_position) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009424 Handle<Context> context = Handle<Context>(isolate->context());
9425 Handle<Context> global_context = Handle<Context>(context->global_context());
9426
9427 // Check if global context allows code generation from
9428 // strings. Throw an exception if it doesn't.
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009429 if (global_context->allow_code_gen_from_strings()->IsFalse() &&
9430 !CodeGenerationFromStringsAllowed(isolate, global_context)) {
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009431 isolate->Throw(*isolate->factory()->NewError(
9432 "code_gen_from_strings", HandleVector<Object>(NULL, 0)));
9433 return MakePair(Failure::Exception(), NULL);
9434 }
9435
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009436 // Deal with a normal eval call with a string argument. Compile it
9437 // and return the compiled function bound in the local context.
9438 Handle<SharedFunctionInfo> shared = Compiler::CompileEval(
9439 source,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009440 Handle<Context>(isolate->context()),
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009441 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009442 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009443 scope_position);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009444 if (shared.is_null()) return MakePair(Failure::Exception(), NULL);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009445 Handle<JSFunction> compiled =
9446 isolate->factory()->NewFunctionFromSharedFunctionInfo(
fschneider@chromium.orgfb144a02011-05-04 12:43:48 +00009447 shared, context, NOT_TENURED);
lrn@chromium.org1af7e1b2010-06-07 11:12:01 +00009448 return MakePair(*compiled, *receiver);
9449}
9450
9451
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009452RUNTIME_FUNCTION(ObjectPair, Runtime_ResolvePossiblyDirectEval) {
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009453 ASSERT(args.length() == 5);
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009454
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009455 HandleScope scope(isolate);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009456 Handle<Object> callee = args.at<Object>(0);
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009457
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009458 // If "eval" didn't refer to the original GlobalEval, it's not a
9459 // direct call to eval.
9460 // (And even if it is, but the first argument isn't a string, just let
9461 // execution default to an indirect call to eval, which will also return
9462 // the first argument without doing anything).
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009463 if (*callee != isolate->global_context()->global_eval_fun() ||
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009464 !args[1]->IsString()) {
danno@chromium.org40cb8782011-05-25 07:58:50 +00009465 return MakePair(*callee, isolate->heap()->the_hole_value());
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009466 }
9467
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009468 CONVERT_LANGUAGE_MODE_ARG(language_mode, 3);
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009469 ASSERT(args[4]->IsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009470 return CompileGlobalEval(isolate,
9471 args.at<String>(1),
ricow@chromium.org83aa5492011-02-07 12:42:56 +00009472 args.at<Object>(2),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009473 language_mode,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +00009474 args.smi_at(4));
ager@chromium.orga74f0da2008-12-03 16:05:52 +00009475}
9476
9477
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009478RUNTIME_FUNCTION(MaybeObject*, Runtime_SetNewFunctionAttributes) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009479 // This utility adjusts the property attributes for newly created Function
9480 // object ("new Function(...)") by changing the map.
9481 // All it does is changing the prototype property to enumerable
9482 // as specified in ECMA262, 15.3.5.2.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009483 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009484 ASSERT(args.length() == 1);
9485 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009486
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +00009487 Handle<Map> map = func->shared()->is_classic_mode()
9488 ? isolate->function_instance_map()
9489 : isolate->strict_mode_function_instance_map();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009490
9491 ASSERT(func->map()->instance_type() == map->instance_type());
9492 ASSERT(func->map()->instance_size() == map->instance_size());
9493 func->set_map(*map);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +00009494 return *func;
9495}
9496
9497
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009498RUNTIME_FUNCTION(MaybeObject*, Runtime_AllocateInNewSpace) {
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009499 // Allocate a block of memory in NewSpace (filled with a filler).
9500 // Use as fallback for allocation in generated code when NewSpace
9501 // is full.
9502 ASSERT(args.length() == 1);
9503 CONVERT_ARG_CHECKED(Smi, size_smi, 0);
9504 int size = size_smi->value();
9505 RUNTIME_ASSERT(IsAligned(size, kPointerSize));
9506 RUNTIME_ASSERT(size > 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009507 Heap* heap = isolate->heap();
9508 const int kMinFreeNewSpaceAfterGC = heap->InitialSemiSpaceSize() * 3/4;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009509 RUNTIME_ASSERT(size <= kMinFreeNewSpaceAfterGC);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009510 Object* allocation;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009511 { MaybeObject* maybe_allocation = heap->new_space()->AllocateRaw(size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009512 if (maybe_allocation->ToObject(&allocation)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009513 heap->CreateFillerObjectAt(HeapObject::cast(allocation)->address(), size);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009514 }
9515 return maybe_allocation;
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009516 }
lrn@chromium.orgc4e51ac2010-08-09 09:47:21 +00009517}
9518
9519
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009520// Push an object unto an array of objects if it is not already in the
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009521// array. Returns true if the element was pushed on the stack and
9522// false otherwise.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +00009523RUNTIME_FUNCTION(MaybeObject*, Runtime_PushIfAbsent) {
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009524 ASSERT(args.length() == 2);
9525 CONVERT_CHECKED(JSArray, array, args[0]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +00009526 CONVERT_CHECKED(JSObject, element, args[1]);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009527 RUNTIME_ASSERT(array->HasFastElements() || array->HasFastSmiOnlyElements());
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009528 int length = Smi::cast(array->length())->value();
9529 FixedArray* elements = FixedArray::cast(array->elements());
9530 for (int i = 0; i < length; i++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009531 if (elements->get(i) == element) return isolate->heap()->false_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009532 }
lrn@chromium.org303ada72010-10-27 09:33:13 +00009533 Object* obj;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009534 // Strict not needed. Used for cycle detection in Array join implementation.
whesse@chromium.org7b260152011-06-20 15:33:18 +00009535 { MaybeObject* maybe_obj =
9536 array->SetFastElement(length, element, kNonStrictMode, true);
lrn@chromium.org303ada72010-10-27 09:33:13 +00009537 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
9538 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009539 return isolate->heap()->true_value();
ager@chromium.org9258b6b2008-09-11 09:11:10 +00009540}
9541
9542
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009543/**
9544 * A simple visitor visits every element of Array's.
9545 * The backend storage can be a fixed array for fast elements case,
9546 * or a dictionary for sparse array. Since Dictionary is a subtype
9547 * of FixedArray, the class can be used by both fast and slow cases.
9548 * The second parameter of the constructor, fast_elements, specifies
9549 * whether the storage is a FixedArray or Dictionary.
9550 *
9551 * An index limit is used to deal with the situation that a result array
9552 * length overflows 32-bit non-negative integer.
9553 */
9554class ArrayConcatVisitor {
9555 public:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009556 ArrayConcatVisitor(Isolate* isolate,
9557 Handle<FixedArray> storage,
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009558 bool fast_elements) :
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009559 isolate_(isolate),
9560 storage_(Handle<FixedArray>::cast(
9561 isolate->global_handles()->Create(*storage))),
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009562 index_offset_(0u),
9563 fast_elements_(fast_elements) { }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009564
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009565 ~ArrayConcatVisitor() {
9566 clear_storage();
9567 }
9568
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009569 void visit(uint32_t i, Handle<Object> elm) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009570 if (i >= JSObject::kMaxElementCount - index_offset_) return;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009571 uint32_t index = index_offset_ + i;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009572
9573 if (fast_elements_) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009574 if (index < static_cast<uint32_t>(storage_->length())) {
9575 storage_->set(index, *elm);
9576 return;
9577 }
9578 // Our initial estimate of length was foiled, possibly by
9579 // getters on the arrays increasing the length of later arrays
9580 // during iteration.
9581 // This shouldn't happen in anything but pathological cases.
9582 SetDictionaryMode(index);
9583 // Fall-through to dictionary mode.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009584 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009585 ASSERT(!fast_elements_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009586 Handle<SeededNumberDictionary> dict(
9587 SeededNumberDictionary::cast(*storage_));
9588 Handle<SeededNumberDictionary> result =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009589 isolate_->factory()->DictionaryAtNumberPut(dict, index, elm);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009590 if (!result.is_identical_to(dict)) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009591 // Dictionary needed to grow.
9592 clear_storage();
9593 set_storage(*result);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009594 }
9595}
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009596
9597 void increase_index_offset(uint32_t delta) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009598 if (JSObject::kMaxElementCount - index_offset_ < delta) {
9599 index_offset_ = JSObject::kMaxElementCount;
fschneider@chromium.org0c20e672010-01-14 15:28:53 +00009600 } else {
9601 index_offset_ += delta;
9602 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009603 }
9604
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009605 Handle<JSArray> ToArray() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009606 Handle<JSArray> array = isolate_->factory()->NewJSArray(0);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009607 Handle<Object> length =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009608 isolate_->factory()->NewNumber(static_cast<double>(index_offset_));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009609 Handle<Map> map;
9610 if (fast_elements_) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009611 map = isolate_->factory()->GetElementsTransitionMap(array,
9612 FAST_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009613 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009614 map = isolate_->factory()->GetElementsTransitionMap(array,
9615 DICTIONARY_ELEMENTS);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009616 }
9617 array->set_map(*map);
9618 array->set_length(*length);
9619 array->set_elements(*storage_);
9620 return array;
9621 }
kasperl@chromium.orgedf0cd12010-01-05 13:29:12 +00009622
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009623 private:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009624 // Convert storage to dictionary mode.
9625 void SetDictionaryMode(uint32_t index) {
9626 ASSERT(fast_elements_);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009627 Handle<FixedArray> current_storage(*storage_);
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009628 Handle<SeededNumberDictionary> slow_storage(
9629 isolate_->factory()->NewSeededNumberDictionary(
9630 current_storage->length()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009631 uint32_t current_length = static_cast<uint32_t>(current_storage->length());
9632 for (uint32_t i = 0; i < current_length; i++) {
9633 HandleScope loop_scope;
9634 Handle<Object> element(current_storage->get(i));
9635 if (!element->IsTheHole()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009636 Handle<SeededNumberDictionary> new_storage =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009637 isolate_->factory()->DictionaryAtNumberPut(slow_storage, i, element);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009638 if (!new_storage.is_identical_to(slow_storage)) {
9639 slow_storage = loop_scope.CloseAndEscape(new_storage);
9640 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009641 }
9642 }
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009643 clear_storage();
9644 set_storage(*slow_storage);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009645 fast_elements_ = false;
9646 }
9647
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009648 inline void clear_storage() {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009649 isolate_->global_handles()->Destroy(
9650 Handle<Object>::cast(storage_).location());
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009651 }
9652
9653 inline void set_storage(FixedArray* storage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009654 storage_ = Handle<FixedArray>::cast(
9655 isolate_->global_handles()->Create(storage));
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009656 }
9657
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009658 Isolate* isolate_;
ager@chromium.org9ee27ae2011-03-02 13:43:26 +00009659 Handle<FixedArray> storage_; // Always a global handle.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009660 // Index after last seen index. Always less than or equal to
9661 // JSObject::kMaxElementCount.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009662 uint32_t index_offset_;
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009663 bool fast_elements_;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009664};
9665
9666
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009667static uint32_t EstimateElementCount(Handle<JSArray> array) {
9668 uint32_t length = static_cast<uint32_t>(array->length()->Number());
9669 int element_count = 0;
9670 switch (array->GetElementsKind()) {
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009671 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009672 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009673 // Fast elements can't have lengths that are not representable by
9674 // a 32-bit signed integer.
9675 ASSERT(static_cast<int32_t>(FixedArray::kMaxLength) >= 0);
9676 int fast_length = static_cast<int>(length);
9677 Handle<FixedArray> elements(FixedArray::cast(array->elements()));
9678 for (int i = 0; i < fast_length; i++) {
9679 if (!elements->get(i)->IsTheHole()) element_count++;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +00009680 }
ager@chromium.org3811b432009-10-28 14:53:37 +00009681 break;
9682 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009683 case FAST_DOUBLE_ELEMENTS:
9684 // TODO(1810): Decide if it's worthwhile to implement this.
9685 UNREACHABLE();
9686 break;
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009687 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009688 Handle<SeededNumberDictionary> dictionary(
9689 SeededNumberDictionary::cast(array->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009690 int capacity = dictionary->Capacity();
9691 for (int i = 0; i < capacity; i++) {
9692 Handle<Object> key(dictionary->KeyAt(i));
9693 if (dictionary->IsKey(*key)) {
9694 element_count++;
9695 }
9696 }
9697 break;
9698 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009699 case NON_STRICT_ARGUMENTS_ELEMENTS:
9700 case EXTERNAL_BYTE_ELEMENTS:
9701 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS:
9702 case EXTERNAL_SHORT_ELEMENTS:
9703 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS:
9704 case EXTERNAL_INT_ELEMENTS:
9705 case EXTERNAL_UNSIGNED_INT_ELEMENTS:
9706 case EXTERNAL_FLOAT_ELEMENTS:
9707 case EXTERNAL_DOUBLE_ELEMENTS:
9708 case EXTERNAL_PIXEL_ELEMENTS:
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009709 // External arrays are always dense.
9710 return length;
9711 }
9712 // As an estimate, we assume that the prototype doesn't contain any
9713 // inherited elements.
9714 return element_count;
9715}
9716
9717
9718
9719template<class ExternalArrayClass, class ElementType>
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009720static void IterateExternalArrayElements(Isolate* isolate,
9721 Handle<JSObject> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009722 bool elements_are_ints,
9723 bool elements_are_guaranteed_smis,
9724 ArrayConcatVisitor* visitor) {
9725 Handle<ExternalArrayClass> array(
9726 ExternalArrayClass::cast(receiver->elements()));
9727 uint32_t len = static_cast<uint32_t>(array->length());
9728
9729 ASSERT(visitor != NULL);
9730 if (elements_are_ints) {
9731 if (elements_are_guaranteed_smis) {
9732 for (uint32_t j = 0; j < len; j++) {
9733 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009734 Handle<Smi> e(Smi::FromInt(static_cast<int>(array->get_scalar(j))));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009735 visitor->visit(j, e);
9736 }
9737 } else {
9738 for (uint32_t j = 0; j < len; j++) {
9739 HandleScope loop_scope;
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009740 int64_t val = static_cast<int64_t>(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009741 if (Smi::IsValid(static_cast<intptr_t>(val))) {
9742 Handle<Smi> e(Smi::FromInt(static_cast<int>(val)));
9743 visitor->visit(j, e);
9744 } else {
9745 Handle<Object> e =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009746 isolate->factory()->NewNumber(static_cast<ElementType>(val));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009747 visitor->visit(j, e);
9748 }
9749 }
9750 }
9751 } else {
9752 for (uint32_t j = 0; j < len; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009753 HandleScope loop_scope(isolate);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009754 Handle<Object> e = isolate->factory()->NewNumber(array->get_scalar(j));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009755 visitor->visit(j, e);
9756 }
9757 }
9758}
9759
9760
9761// Used for sorting indices in a List<uint32_t>.
9762static int compareUInt32(const uint32_t* ap, const uint32_t* bp) {
9763 uint32_t a = *ap;
9764 uint32_t b = *bp;
9765 return (a == b) ? 0 : (a < b) ? -1 : 1;
9766}
9767
9768
9769static void CollectElementIndices(Handle<JSObject> object,
9770 uint32_t range,
9771 List<uint32_t>* indices) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009772 ElementsKind kind = object->GetElementsKind();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009773 switch (kind) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009774 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009775 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009776 Handle<FixedArray> elements(FixedArray::cast(object->elements()));
9777 uint32_t length = static_cast<uint32_t>(elements->length());
9778 if (range < length) length = range;
9779 for (uint32_t i = 0; i < length; i++) {
9780 if (!elements->get(i)->IsTheHole()) {
9781 indices->Add(i);
9782 }
9783 }
9784 break;
9785 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009786 case FAST_DOUBLE_ELEMENTS: {
9787 // TODO(1810): Decide if it's worthwhile to implement this.
9788 UNREACHABLE();
9789 break;
9790 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009791 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009792 Handle<SeededNumberDictionary> dict(
9793 SeededNumberDictionary::cast(object->elements()));
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009794 uint32_t capacity = dict->Capacity();
9795 for (uint32_t j = 0; j < capacity; j++) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009796 HandleScope loop_scope;
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009797 Handle<Object> k(dict->KeyAt(j));
9798 if (dict->IsKey(*k)) {
9799 ASSERT(k->IsNumber());
9800 uint32_t index = static_cast<uint32_t>(k->Number());
9801 if (index < range) {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009802 indices->Add(index);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009803 }
9804 }
9805 }
9806 break;
9807 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009808 default: {
9809 int dense_elements_length;
9810 switch (kind) {
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009811 case EXTERNAL_PIXEL_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009812 dense_elements_length =
9813 ExternalPixelArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009814 break;
9815 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009816 case EXTERNAL_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009817 dense_elements_length =
9818 ExternalByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009819 break;
9820 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009821 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009822 dense_elements_length =
9823 ExternalUnsignedByteArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009824 break;
9825 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009826 case EXTERNAL_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009827 dense_elements_length =
9828 ExternalShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009829 break;
9830 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009831 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009832 dense_elements_length =
9833 ExternalUnsignedShortArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009834 break;
9835 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009836 case EXTERNAL_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009837 dense_elements_length =
9838 ExternalIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009839 break;
9840 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009841 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009842 dense_elements_length =
9843 ExternalUnsignedIntArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009844 break;
9845 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009846 case EXTERNAL_FLOAT_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009847 dense_elements_length =
9848 ExternalFloatArray::cast(object->elements())->length();
9849 break;
9850 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009851 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009852 dense_elements_length =
9853 ExternalDoubleArray::cast(object->elements())->length();
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009854 break;
9855 }
9856 default:
9857 UNREACHABLE();
9858 dense_elements_length = 0;
9859 break;
9860 }
9861 uint32_t length = static_cast<uint32_t>(dense_elements_length);
9862 if (range <= length) {
9863 length = range;
9864 // We will add all indices, so we might as well clear it first
9865 // and avoid duplicates.
9866 indices->Clear();
9867 }
9868 for (uint32_t i = 0; i < length; i++) {
9869 indices->Add(i);
9870 }
9871 if (length == range) return; // All indices accounted for already.
9872 break;
9873 }
9874 }
9875
9876 Handle<Object> prototype(object->GetPrototype());
9877 if (prototype->IsJSObject()) {
9878 // The prototype will usually have no inherited element indices,
9879 // but we have to check.
9880 CollectElementIndices(Handle<JSObject>::cast(prototype), range, indices);
9881 }
9882}
9883
9884
9885/**
9886 * A helper function that visits elements of a JSArray in numerical
9887 * order.
9888 *
9889 * The visitor argument called for each existing element in the array
9890 * with the element index and the element's value.
9891 * Afterwards it increments the base-index of the visitor by the array
9892 * length.
karlklose@chromium.org8f806e82011-03-07 14:06:08 +00009893 * Returns false if any access threw an exception, otherwise true.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009894 */
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009895static bool IterateElements(Isolate* isolate,
9896 Handle<JSArray> receiver,
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009897 ArrayConcatVisitor* visitor) {
9898 uint32_t length = static_cast<uint32_t>(receiver->length()->Number());
9899 switch (receiver->GetElementsKind()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +00009900 case FAST_SMI_ONLY_ELEMENTS:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009901 case FAST_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009902 // Run through the elements FixedArray and use HasElement and GetElement
9903 // to check the prototype for missing elements.
9904 Handle<FixedArray> elements(FixedArray::cast(receiver->elements()));
9905 int fast_length = static_cast<int>(length);
9906 ASSERT(fast_length <= elements->length());
9907 for (int j = 0; j < fast_length; j++) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009908 HandleScope loop_scope(isolate);
9909 Handle<Object> element_value(elements->get(j), isolate);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009910 if (!element_value->IsTheHole()) {
9911 visitor->visit(j, element_value);
9912 } else if (receiver->HasElement(j)) {
9913 // Call GetElement on receiver, not its prototype, or getters won't
9914 // have the correct receiver.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009915 element_value = Object::GetElement(receiver, j);
9916 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element_value, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009917 visitor->visit(j, element_value);
9918 }
9919 }
9920 break;
9921 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +00009922 case FAST_DOUBLE_ELEMENTS: {
9923 // TODO(1810): Decide if it's worthwhile to implement this.
9924 UNREACHABLE();
9925 break;
9926 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009927 case DICTIONARY_ELEMENTS: {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +00009928 Handle<SeededNumberDictionary> dict(receiver->element_dictionary());
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009929 List<uint32_t> indices(dict->Capacity() / 2);
9930 // Collect all indices in the object and the prototypes less
9931 // than length. This might introduce duplicates in the indices list.
9932 CollectElementIndices(receiver, length, &indices);
9933 indices.Sort(&compareUInt32);
9934 int j = 0;
9935 int n = indices.length();
9936 while (j < n) {
9937 HandleScope loop_scope;
9938 uint32_t index = indices[j];
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +00009939 Handle<Object> element = Object::GetElement(receiver, index);
9940 RETURN_IF_EMPTY_HANDLE_VALUE(isolate, element, false);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009941 visitor->visit(index, element);
9942 // Skip to next different index (i.e., omit duplicates).
9943 do {
9944 j++;
9945 } while (j < n && indices[j] == index);
9946 }
9947 break;
9948 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009949 case EXTERNAL_PIXEL_ELEMENTS: {
danno@chromium.org4d3fe4e2011-03-10 10:14:28 +00009950 Handle<ExternalPixelArray> pixels(ExternalPixelArray::cast(
9951 receiver->elements()));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009952 for (uint32_t j = 0; j < length; j++) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +00009953 Handle<Smi> e(Smi::FromInt(pixels->get_scalar(j)));
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009954 visitor->visit(j, e);
9955 }
9956 break;
9957 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009958 case EXTERNAL_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009959 IterateExternalArrayElements<ExternalByteArray, int8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009960 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009961 break;
9962 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009963 case EXTERNAL_UNSIGNED_BYTE_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009964 IterateExternalArrayElements<ExternalUnsignedByteArray, uint8_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009965 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009966 break;
9967 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009968 case EXTERNAL_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009969 IterateExternalArrayElements<ExternalShortArray, int16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009970 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009971 break;
9972 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009973 case EXTERNAL_UNSIGNED_SHORT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009974 IterateExternalArrayElements<ExternalUnsignedShortArray, uint16_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009975 isolate, receiver, true, true, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009976 break;
9977 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009978 case EXTERNAL_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009979 IterateExternalArrayElements<ExternalIntArray, int32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009980 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009981 break;
9982 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009983 case EXTERNAL_UNSIGNED_INT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009984 IterateExternalArrayElements<ExternalUnsignedIntArray, uint32_t>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009985 isolate, receiver, true, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009986 break;
9987 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009988 case EXTERNAL_FLOAT_ELEMENTS: {
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009989 IterateExternalArrayElements<ExternalFloatArray, float>(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +00009990 isolate, receiver, false, false, visitor);
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +00009991 break;
9992 }
kmillikin@chromium.org83e16822011-09-13 08:21:47 +00009993 case EXTERNAL_DOUBLE_ELEMENTS: {
erik.corry@gmail.com3847bd52011-04-27 10:38:56 +00009994 IterateExternalArrayElements<ExternalDoubleArray, double>(
9995 isolate, receiver, false, false, visitor);
9996 break;
9997 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +00009998 default:
9999 UNREACHABLE();
10000 break;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010001 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010002 visitor->increase_index_offset(length);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010003 return true;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010004}
10005
10006
10007/**
10008 * Array::concat implementation.
10009 * See ECMAScript 262, 15.4.4.4.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010010 * TODO(581): Fix non-compliance for very large concatenations and update to
fschneider@chromium.org0c20e672010-01-14 15:28:53 +000010011 * following the ECMAScript 5 specification.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010012 */
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010013RUNTIME_FUNCTION(MaybeObject*, Runtime_ArrayConcat) {
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010014 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010015 HandleScope handle_scope(isolate);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010016
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010017 CONVERT_ARG_CHECKED(JSArray, arguments, 0);
10018 int argument_count = static_cast<int>(arguments->length()->Number());
10019 RUNTIME_ASSERT(arguments->HasFastElements());
10020 Handle<FixedArray> elements(FixedArray::cast(arguments->elements()));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010021
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010022 // Pass 1: estimate the length and number of elements of the result.
10023 // The actual length can be larger if any of the arguments have getters
10024 // that mutate other arguments (but will otherwise be precise).
10025 // The number of elements is precise if there are no inherited elements.
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010026
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010027 uint32_t estimate_result_length = 0;
10028 uint32_t estimate_nof_elements = 0;
10029 {
10030 for (int i = 0; i < argument_count; i++) {
10031 HandleScope loop_scope;
10032 Handle<Object> obj(elements->get(i));
10033 uint32_t length_estimate;
10034 uint32_t element_estimate;
10035 if (obj->IsJSArray()) {
10036 Handle<JSArray> array(Handle<JSArray>::cast(obj));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010037 // TODO(1810): Find out if it's worthwhile to properly support
10038 // arbitrary ElementsKinds. For now, pessimistically transition to
10039 // FAST_ELEMENTS.
10040 if (array->HasFastDoubleElements()) {
10041 array = Handle<JSArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010042 JSObject::TransitionElementsKind(array, FAST_ELEMENTS));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010043 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010044 length_estimate =
10045 static_cast<uint32_t>(array->length()->Number());
10046 element_estimate =
10047 EstimateElementCount(array);
10048 } else {
10049 length_estimate = 1;
10050 element_estimate = 1;
10051 }
10052 // Avoid overflows by capping at kMaxElementCount.
10053 if (JSObject::kMaxElementCount - estimate_result_length <
10054 length_estimate) {
10055 estimate_result_length = JSObject::kMaxElementCount;
10056 } else {
10057 estimate_result_length += length_estimate;
10058 }
10059 if (JSObject::kMaxElementCount - estimate_nof_elements <
10060 element_estimate) {
10061 estimate_nof_elements = JSObject::kMaxElementCount;
10062 } else {
10063 estimate_nof_elements += element_estimate;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010064 }
10065 }
10066 }
10067
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010068 // If estimated number of elements is more than half of length, a
10069 // fixed array (fast case) is more time and space-efficient than a
10070 // dictionary.
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010071 bool fast_case = (estimate_nof_elements * 2) >= estimate_result_length;
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010072
10073 Handle<FixedArray> storage;
10074 if (fast_case) {
10075 // The backing storage array must have non-existing elements to
10076 // preserve holes across concat operations.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010077 storage = isolate->factory()->NewFixedArrayWithHoles(
10078 estimate_result_length);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010079 } else {
10080 // TODO(126): move 25% pre-allocation logic into Dictionary::Allocate
10081 uint32_t at_least_space_for = estimate_nof_elements +
10082 (estimate_nof_elements >> 2);
10083 storage = Handle<FixedArray>::cast(
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010084 isolate->factory()->NewSeededNumberDictionary(at_least_space_for));
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010085 }
10086
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010087 ArrayConcatVisitor visitor(isolate, storage, fast_case);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010088
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010089 for (int i = 0; i < argument_count; i++) {
10090 Handle<Object> obj(elements->get(i));
10091 if (obj->IsJSArray()) {
10092 Handle<JSArray> array = Handle<JSArray>::cast(obj);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010093 if (!IterateElements(isolate, array, &visitor)) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000010094 return Failure::Exception();
10095 }
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010096 } else {
10097 visitor.visit(0, obj);
10098 visitor.increase_index_offset(1);
10099 }
10100 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010101
vegorov@chromium.org5d6c1f52011-02-28 13:13:38 +000010102 return *visitor.ToArray();
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000010103}
10104
10105
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010106// This will not allocate (flatten the string), but it may run
10107// very slowly for very deeply nested ConsStrings. For debugging use only.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010108RUNTIME_FUNCTION(MaybeObject*, Runtime_GlobalPrint) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010109 NoHandleAllocation ha;
10110 ASSERT(args.length() == 1);
10111
10112 CONVERT_CHECKED(String, string, args[0]);
10113 StringInputBuffer buffer(string);
10114 while (buffer.has_more()) {
10115 uint16_t character = buffer.GetNext();
10116 PrintF("%c", character);
10117 }
10118 return string;
10119}
10120
ager@chromium.org5ec48922009-05-05 07:25:34 +000010121// Moves all own elements of an object, that are below a limit, to positions
10122// starting at zero. All undefined values are placed after non-undefined values,
10123// and are followed by non-existing element. Does not change the length
10124// property.
10125// Returns the number of non-undefined elements collected.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010126RUNTIME_FUNCTION(MaybeObject*, Runtime_RemoveArrayHoles) {
ager@chromium.org5ec48922009-05-05 07:25:34 +000010127 ASSERT(args.length() == 2);
10128 CONVERT_CHECKED(JSObject, object, args[0]);
10129 CONVERT_NUMBER_CHECKED(uint32_t, limit, Uint32, args[1]);
10130 return object->PrepareElementsForSort(limit);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010131}
10132
10133
10134// Move contents of argument 0 (an array) to argument 1 (an array)
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010135RUNTIME_FUNCTION(MaybeObject*, Runtime_MoveArrayContents) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010136 ASSERT(args.length() == 2);
10137 CONVERT_CHECKED(JSArray, from, args[0]);
10138 CONVERT_CHECKED(JSArray, to, args[1]);
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000010139 FixedArrayBase* new_elements = from->elements();
lrn@chromium.org303ada72010-10-27 09:33:13 +000010140 MaybeObject* maybe_new_map;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010141 ElementsKind elements_kind;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010142 if (new_elements->map() == isolate->heap()->fixed_array_map() ||
10143 new_elements->map() == isolate->heap()->fixed_cow_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010144 elements_kind = FAST_ELEMENTS;
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010145 } else if (new_elements->map() ==
10146 isolate->heap()->fixed_double_array_map()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010147 elements_kind = FAST_DOUBLE_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010148 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010149 elements_kind = DICTIONARY_ELEMENTS;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010150 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010151 maybe_new_map = to->GetElementsTransitionMap(elements_kind);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010152 Object* new_map;
10153 if (!maybe_new_map->ToObject(&new_map)) return maybe_new_map;
fschneider@chromium.org40b9da32010-06-28 11:29:21 +000010154 to->set_map(Map::cast(new_map));
10155 to->set_elements(new_elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010156 to->set_length(from->length());
lrn@chromium.org303ada72010-10-27 09:33:13 +000010157 Object* obj;
10158 { MaybeObject* maybe_obj = from->ResetElements();
10159 if (!maybe_obj->ToObject(&obj)) return maybe_obj;
10160 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010161 from->set_length(Smi::FromInt(0));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010162 return to;
10163}
10164
10165
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010166// How many elements does this object/array have?
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010167RUNTIME_FUNCTION(MaybeObject*, Runtime_EstimateNumberOfElements) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010168 ASSERT(args.length() == 1);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010169 CONVERT_CHECKED(JSObject, object, args[0]);
10170 HeapObject* elements = object->elements();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010171 if (elements->IsDictionary()) {
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010172 int result = SeededNumberDictionary::cast(elements)->NumberOfElements();
10173 return Smi::FromInt(result);
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010174 } else if (object->IsJSArray()) {
10175 return JSArray::cast(object)->length();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010176 } else {
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010177 return Smi::FromInt(FixedArray::cast(elements)->length());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010178 }
10179}
10180
10181
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010182RUNTIME_FUNCTION(MaybeObject*, Runtime_SwapElements) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010183 HandleScope handle_scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010184
10185 ASSERT_EQ(3, args.length());
10186
ager@chromium.orgac091b72010-05-05 07:34:42 +000010187 CONVERT_ARG_CHECKED(JSObject, object, 0);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010188 Handle<Object> key1 = args.at<Object>(1);
10189 Handle<Object> key2 = args.at<Object>(2);
10190
10191 uint32_t index1, index2;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010192 if (!key1->ToArrayIndex(&index1)
10193 || !key2->ToArrayIndex(&index2)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010194 return isolate->ThrowIllegalOperation();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010195 }
10196
ager@chromium.orgac091b72010-05-05 07:34:42 +000010197 Handle<JSObject> jsobject = Handle<JSObject>::cast(object);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010198 Handle<Object> tmp1 = Object::GetElement(jsobject, index1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010199 RETURN_IF_EMPTY_HANDLE(isolate, tmp1);
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010200 Handle<Object> tmp2 = Object::GetElement(jsobject, index2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010201 RETURN_IF_EMPTY_HANDLE(isolate, tmp2);
ager@chromium.orgac091b72010-05-05 07:34:42 +000010202
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010203 RETURN_IF_EMPTY_HANDLE(
10204 isolate, JSObject::SetElement(jsobject, index1, tmp2, kStrictMode));
10205 RETURN_IF_EMPTY_HANDLE(
10206 isolate, JSObject::SetElement(jsobject, index2, tmp1, kStrictMode));
ager@chromium.orgac091b72010-05-05 07:34:42 +000010207
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010208 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000010209}
10210
10211
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010212// Returns an array that tells you where in the [0, length) interval an array
sgjesse@chromium.org2ec107f2010-09-13 09:19:46 +000010213// might have elements. Can either return keys (positive integers) or
10214// intervals (pair of a negative integer (-start-1) followed by a
10215// positive (length)) or undefined values.
10216// Intervals can span over some keys that are not in the object.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010217RUNTIME_FUNCTION(MaybeObject*, Runtime_GetArrayKeys) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010218 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010219 HandleScope scope(isolate);
ager@chromium.org5ec48922009-05-05 07:25:34 +000010220 CONVERT_ARG_CHECKED(JSObject, array, 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010221 CONVERT_NUMBER_CHECKED(uint32_t, length, Uint32, args[1]);
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010222 if (array->elements()->IsDictionary()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010223 // Create an array and get all the keys into it, then remove all the
10224 // keys that are not integers in the range 0 to length-1.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010225 bool threw = false;
10226 Handle<FixedArray> keys =
10227 GetKeysInFixedArrayFor(array, INCLUDE_PROTOS, &threw);
10228 if (threw) return Failure::Exception();
10229
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010230 int keys_length = keys->length();
10231 for (int i = 0; i < keys_length; i++) {
10232 Object* key = keys->get(i);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010233 uint32_t index = 0;
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010234 if (!key->ToArrayIndex(&index) || index >= length) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010235 // Zap invalid keys.
10236 keys->set_undefined(i);
10237 }
10238 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010239 return *isolate->factory()->NewJSArrayWithElements(keys);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010240 } else {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010241 ASSERT(array->HasFastElements() ||
10242 array->HasFastSmiOnlyElements() ||
10243 array->HasFastDoubleElements());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010244 Handle<FixedArray> single_interval = isolate->factory()->NewFixedArray(2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010245 // -1 means start of array.
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000010246 single_interval->set(0, Smi::FromInt(-1));
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010247 FixedArrayBase* elements = FixedArrayBase::cast(array->elements());
ricow@chromium.org30ce4112010-05-31 10:38:25 +000010248 uint32_t actual_length =
lrn@chromium.orgd4e9e222011-08-03 12:01:58 +000010249 static_cast<uint32_t>(elements->length());
ager@chromium.org5ec48922009-05-05 07:25:34 +000010250 uint32_t min_length = actual_length < length ? actual_length : length;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010251 Handle<Object> length_object =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010252 isolate->factory()->NewNumber(static_cast<double>(min_length));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010253 single_interval->set(1, *length_object);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010254 return *isolate->factory()->NewJSArrayWithElements(single_interval);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010255 }
10256}
10257
10258
10259// DefineAccessor takes an optional final argument which is the
10260// property attributes (eg, DONT_ENUM, DONT_DELETE). IMPORTANT: due
10261// to the way accessors are implemented, it is set for both the getter
10262// and setter on the first call to DefineAccessor and ignored on
10263// subsequent calls.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010264RUNTIME_FUNCTION(MaybeObject*, Runtime_DefineAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010265 RUNTIME_ASSERT(args.length() == 4 || args.length() == 5);
10266 // Compute attributes.
10267 PropertyAttributes attributes = NONE;
10268 if (args.length() == 5) {
10269 CONVERT_CHECKED(Smi, attrs, args[4]);
10270 int value = attrs->value();
10271 // Only attribute bits should be set.
10272 ASSERT((value & ~(READ_ONLY | DONT_ENUM | DONT_DELETE)) == 0);
10273 attributes = static_cast<PropertyAttributes>(value);
10274 }
10275
10276 CONVERT_CHECKED(JSObject, obj, args[0]);
10277 CONVERT_CHECKED(String, name, args[1]);
10278 CONVERT_CHECKED(Smi, flag, args[2]);
10279 CONVERT_CHECKED(JSFunction, fun, args[3]);
10280 return obj->DefineAccessor(name, flag->value() == 0, fun, attributes);
10281}
10282
10283
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010284RUNTIME_FUNCTION(MaybeObject*, Runtime_LookupAccessor) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010285 ASSERT(args.length() == 3);
10286 CONVERT_CHECKED(JSObject, obj, args[0]);
10287 CONVERT_CHECKED(String, name, args[1]);
10288 CONVERT_CHECKED(Smi, flag, args[2]);
10289 return obj->LookupAccessor(name, flag->value() == 0);
10290}
10291
10292
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010293#ifdef ENABLE_DEBUGGER_SUPPORT
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010294RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugBreak) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000010295 ASSERT(args.length() == 0);
10296 return Execution::DebugBreakHelper();
10297}
10298
10299
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010300// Helper functions for wrapping and unwrapping stack frame ids.
10301static Smi* WrapFrameId(StackFrame::Id id) {
kasperl@chromium.org71affb52009-05-26 05:44:31 +000010302 ASSERT(IsAligned(OffsetFrom(id), static_cast<intptr_t>(4)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010303 return Smi::FromInt(id >> 2);
10304}
10305
10306
10307static StackFrame::Id UnwrapFrameId(Smi* wrapped) {
10308 return static_cast<StackFrame::Id>(wrapped->value() << 2);
10309}
10310
10311
10312// Adds a JavaScript function as a debug event listener.
iposva@chromium.org245aa852009-02-10 00:49:54 +000010313// args[0]: debug event listener function to set or null or undefined for
10314// clearing the event listener function
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010315// args[1]: object supplied during callback
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010316RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDebugEventListener) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010317 ASSERT(args.length() == 2);
iposva@chromium.org245aa852009-02-10 00:49:54 +000010318 RUNTIME_ASSERT(args[0]->IsJSFunction() ||
10319 args[0]->IsUndefined() ||
10320 args[0]->IsNull());
10321 Handle<Object> callback = args.at<Object>(0);
10322 Handle<Object> data = args.at<Object>(1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010323 isolate->debugger()->SetEventListener(callback, data);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010324
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010325 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010326}
10327
10328
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010329RUNTIME_FUNCTION(MaybeObject*, Runtime_Break) {
mads.s.ager31e71382008-08-13 09:32:07 +000010330 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010331 isolate->stack_guard()->DebugBreak();
10332 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010333}
10334
10335
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010336static MaybeObject* DebugLookupResultValue(Heap* heap,
10337 Object* receiver,
10338 String* name,
lrn@chromium.org303ada72010-10-27 09:33:13 +000010339 LookupResult* result,
10340 bool* caught_exception) {
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010341 Object* value;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010342 switch (result->type()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000010343 case NORMAL:
10344 value = result->holder()->GetNormalizedProperty(result);
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010345 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010346 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010347 }
10348 return value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010349 case FIELD:
10350 value =
10351 JSObject::cast(
10352 result->holder())->FastPropertyAt(result->GetFieldIndex());
10353 if (value->IsTheHole()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010354 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010355 }
10356 return value;
10357 case CONSTANT_FUNCTION:
10358 return result->GetConstantFunction();
10359 case CALLBACKS: {
10360 Object* structure = result->GetCallbackObject();
ager@chromium.orgea91cc52011-05-23 06:06:11 +000010361 if (structure->IsForeign() || structure->IsAccessorInfo()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000010362 MaybeObject* maybe_value = result->holder()->GetPropertyWithCallback(
10363 receiver, structure, name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010364 if (!maybe_value->ToObject(&value)) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010365 if (maybe_value->IsRetryAfterGC()) return maybe_value;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010366 ASSERT(maybe_value->IsException());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010367 maybe_value = heap->isolate()->pending_exception();
10368 heap->isolate()->clear_pending_exception();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010369 if (caught_exception != NULL) {
10370 *caught_exception = true;
10371 }
lrn@chromium.org303ada72010-10-27 09:33:13 +000010372 return maybe_value;
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010373 }
10374 return value;
10375 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010376 return heap->undefined_value();
sgjesse@chromium.org715915b2009-01-19 16:08:47 +000010377 }
10378 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010379 case INTERCEPTOR:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010380 case MAP_TRANSITION:
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000010381 case ELEMENTS_TRANSITION:
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010382 case CONSTANT_TRANSITION:
10383 case NULL_DESCRIPTOR:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010384 return heap->undefined_value();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010385 case HANDLER:
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010386 UNREACHABLE();
danno@chromium.orgc612e022011-11-10 11:38:15 +000010387 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010388 }
danno@chromium.orgc612e022011-11-10 11:38:15 +000010389 UNREACHABLE(); // keep the compiler happy
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010390 return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010391}
10392
10393
ager@chromium.org32912102009-01-16 10:38:43 +000010394// Get debugger related details for an object property.
10395// args[0]: object holding property
10396// args[1]: name of the property
10397//
10398// The array returned contains the following information:
10399// 0: Property value
10400// 1: Property details
10401// 2: Property value is exception
10402// 3: Getter function if defined
10403// 4: Setter function if defined
10404// Items 2-4 are only filled if the property has either a getter or a setter
10405// defined through __defineGetter__ and/or __defineSetter__.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010406RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPropertyDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010407 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010408
10409 ASSERT(args.length() == 2);
10410
10411 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10412 CONVERT_ARG_CHECKED(String, name, 1);
10413
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010414 // Make sure to set the current context to the context before the debugger was
10415 // entered (if the debugger is entered). The reason for switching context here
10416 // is that for some property lookups (accessors and interceptors) callbacks
10417 // into the embedding application can occour, and the embedding application
10418 // could have the assumption that its own global context is the current
10419 // context and not some internal debugger context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010420 SaveContext save(isolate);
10421 if (isolate->debug()->InDebugger()) {
10422 isolate->set_context(*isolate->debug()->debugger_entry()->GetContext());
sgjesse@chromium.org755c5b12009-05-29 11:04:38 +000010423 }
10424
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010425 // Skip the global proxy as it has no properties and always delegates to the
10426 // real global object.
10427 if (obj->IsJSGlobalProxy()) {
10428 obj = Handle<JSObject>(JSObject::cast(obj->GetPrototype()));
10429 }
10430
10431
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010432 // Check if the name is trivially convertible to an index and get the element
10433 // if so.
10434 uint32_t index;
10435 if (name->AsArrayIndex(&index)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010436 Handle<FixedArray> details = isolate->factory()->NewFixedArray(2);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010437 Object* element_or_char;
10438 { MaybeObject* maybe_element_or_char =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010439 Runtime::GetElementOrCharAt(isolate, obj, index);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010440 if (!maybe_element_or_char->ToObject(&element_or_char)) {
10441 return maybe_element_or_char;
10442 }
10443 }
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000010444 details->set(0, element_or_char);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010445 details->set(1, PropertyDetails(NONE, NORMAL).AsSmi());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010446 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010447 }
10448
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010449 // Find the number of objects making up this.
10450 int length = LocalPrototypeChainLength(*obj);
10451
10452 // Try local lookup on each of the objects.
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010453 Handle<JSObject> jsproto = obj;
10454 for (int i = 0; i < length; i++) {
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010455 LookupResult result(isolate);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010456 jsproto->LocalLookup(*name, &result);
10457 if (result.IsProperty()) {
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010458 // LookupResult is not GC safe as it holds raw object pointers.
10459 // GC can happen later in this code so put the required fields into
10460 // local variables using handles when required for later use.
10461 PropertyType result_type = result.type();
10462 Handle<Object> result_callback_obj;
10463 if (result_type == CALLBACKS) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010464 result_callback_obj = Handle<Object>(result.GetCallbackObject(),
10465 isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010466 }
10467 Smi* property_details = result.GetPropertyDetails().AsSmi();
10468 // DebugLookupResultValue can cause GC so details from LookupResult needs
10469 // to be copied to handles before this.
10470 bool caught_exception = false;
lrn@chromium.org303ada72010-10-27 09:33:13 +000010471 Object* raw_value;
10472 { MaybeObject* maybe_raw_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010473 DebugLookupResultValue(isolate->heap(), *obj, *name,
10474 &result, &caught_exception);
lrn@chromium.org303ada72010-10-27 09:33:13 +000010475 if (!maybe_raw_value->ToObject(&raw_value)) return maybe_raw_value;
10476 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010477 Handle<Object> value(raw_value, isolate);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010478
10479 // If the callback object is a fixed array then it contains JavaScript
10480 // getter and/or setter.
10481 bool hasJavaScriptAccessors = result_type == CALLBACKS &&
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010482 result_callback_obj->IsAccessorPair();
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010483 Handle<FixedArray> details =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010484 isolate->factory()->NewFixedArray(hasJavaScriptAccessors ? 5 : 2);
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010485 details->set(0, *value);
10486 details->set(1, property_details);
10487 if (hasJavaScriptAccessors) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000010488 details->set(2, isolate->heap()->ToBoolean(caught_exception));
erik.corry@gmail.comf2038fb2012-01-16 11:42:08 +000010489 details->set(3, AccessorPair::cast(*result_callback_obj)->getter());
10490 details->set(4, AccessorPair::cast(*result_callback_obj)->setter());
christian.plesner.hansen@gmail.com2bc58ef2009-09-22 10:00:30 +000010491 }
10492
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010493 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgddb913d2009-01-27 10:01:48 +000010494 }
10495 if (i < length - 1) {
10496 jsproto = Handle<JSObject>(JSObject::cast(jsproto->GetPrototype()));
10497 }
10498 }
10499
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010500 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010501}
10502
10503
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010504RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetProperty) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010505 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010506
10507 ASSERT(args.length() == 2);
10508
10509 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10510 CONVERT_ARG_CHECKED(String, name, 1);
10511
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000010512 LookupResult result(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010513 obj->Lookup(*name, &result);
10514 if (result.IsProperty()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010515 return DebugLookupResultValue(isolate->heap(), *obj, *name, &result, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010516 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010517 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010518}
10519
10520
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010521// Return the property type calculated from the property details.
10522// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010523RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyTypeFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010524 ASSERT(args.length() == 1);
10525 CONVERT_CHECKED(Smi, details, args[0]);
10526 PropertyType type = PropertyDetails(details).type();
10527 return Smi::FromInt(static_cast<int>(type));
10528}
10529
10530
10531// Return the property attribute calculated from the property details.
10532// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010533RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyAttributesFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010534 ASSERT(args.length() == 1);
10535 CONVERT_CHECKED(Smi, details, args[0]);
10536 PropertyAttributes attributes = PropertyDetails(details).attributes();
10537 return Smi::FromInt(static_cast<int>(attributes));
10538}
10539
10540
10541// Return the property insertion index calculated from the property details.
10542// args[0]: smi with property details.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010543RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPropertyIndexFromDetails) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010544 ASSERT(args.length() == 1);
10545 CONVERT_CHECKED(Smi, details, args[0]);
10546 int index = PropertyDetails(details).index();
10547 return Smi::FromInt(index);
10548}
10549
10550
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010551// Return property value from named interceptor.
10552// args[0]: object
10553// args[1]: property name
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010554RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugNamedInterceptorPropertyValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010555 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010556 ASSERT(args.length() == 2);
10557 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10558 RUNTIME_ASSERT(obj->HasNamedInterceptor());
10559 CONVERT_ARG_CHECKED(String, name, 1);
10560
10561 PropertyAttributes attributes;
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010562 return obj->GetPropertyWithInterceptor(*obj, *name, &attributes);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010563}
10564
10565
10566// Return element value from indexed interceptor.
10567// args[0]: object
10568// args[1]: index
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010569RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugIndexedInterceptorElementValue) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010570 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010571 ASSERT(args.length() == 2);
10572 CONVERT_ARG_CHECKED(JSObject, obj, 0);
10573 RUNTIME_ASSERT(obj->HasIndexedInterceptor());
10574 CONVERT_NUMBER_CHECKED(uint32_t, index, Uint32, args[1]);
10575
mads.s.ager@gmail.com9a4089a2008-09-01 08:55:01 +000010576 return obj->GetElementWithInterceptor(*obj, index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010577}
10578
10579
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010580RUNTIME_FUNCTION(MaybeObject*, Runtime_CheckExecutionState) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010581 ASSERT(args.length() >= 1);
10582 CONVERT_NUMBER_CHECKED(int, break_id, Int32, args[0]);
ager@chromium.org8bb60582008-12-11 12:02:20 +000010583 // Check that the break id is valid.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010584 if (isolate->debug()->break_id() == 0 ||
10585 break_id != isolate->debug()->break_id()) {
10586 return isolate->Throw(
10587 isolate->heap()->illegal_execution_state_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010588 }
10589
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010590 return isolate->heap()->true_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010591}
10592
10593
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010594RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010595 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010596 ASSERT(args.length() == 1);
10597
10598 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010599 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010600 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
10601 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010602 if (!maybe_result->ToObject(&result)) return maybe_result;
10603 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010604
10605 // Count all frames which are relevant to debugging stack trace.
10606 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010607 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010608 if (id == StackFrame::NO_ID) {
10609 // If there is no JavaScript stack frame count is 0.
10610 return Smi::FromInt(0);
10611 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010612
10613 for (JavaScriptFrameIterator it(isolate, id); !it.done(); it.Advance()) {
10614 n += it.frame()->GetInlineCount();
10615 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010616 return Smi::FromInt(n);
10617}
10618
10619
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010620class FrameInspector {
10621 public:
10622 FrameInspector(JavaScriptFrame* frame,
10623 int inlined_frame_index,
10624 Isolate* isolate)
10625 : frame_(frame), deoptimized_frame_(NULL), isolate_(isolate) {
10626 // Calculate the deoptimized frame.
10627 if (frame->is_optimized()) {
10628 deoptimized_frame_ = Deoptimizer::DebuggerInspectableFrame(
10629 frame, inlined_frame_index, isolate);
10630 }
10631 has_adapted_arguments_ = frame_->has_adapted_arguments();
10632 is_optimized_ = frame_->is_optimized();
10633 }
10634
10635 ~FrameInspector() {
10636 // Get rid of the calculated deoptimized frame if any.
10637 if (deoptimized_frame_ != NULL) {
10638 Deoptimizer::DeleteDebuggerInspectableFrame(deoptimized_frame_,
10639 isolate_);
10640 }
10641 }
10642
10643 int GetParametersCount() {
10644 return is_optimized_
10645 ? deoptimized_frame_->parameters_count()
10646 : frame_->ComputeParametersCount();
10647 }
10648 int expression_count() { return deoptimized_frame_->expression_count(); }
10649 Object* GetFunction() {
10650 return is_optimized_
10651 ? deoptimized_frame_->GetFunction()
10652 : frame_->function();
10653 }
10654 Object* GetParameter(int index) {
10655 return is_optimized_
10656 ? deoptimized_frame_->GetParameter(index)
10657 : frame_->GetParameter(index);
10658 }
10659 Object* GetExpression(int index) {
10660 return is_optimized_
10661 ? deoptimized_frame_->GetExpression(index)
10662 : frame_->GetExpression(index);
10663 }
10664
10665 // To inspect all the provided arguments the frame might need to be
10666 // replaced with the arguments frame.
10667 void SetArgumentsFrame(JavaScriptFrame* frame) {
10668 ASSERT(has_adapted_arguments_);
10669 frame_ = frame;
10670 is_optimized_ = frame_->is_optimized();
10671 ASSERT(!is_optimized_);
10672 }
10673
10674 private:
10675 JavaScriptFrame* frame_;
10676 DeoptimizedFrameInfo* deoptimized_frame_;
10677 Isolate* isolate_;
10678 bool is_optimized_;
10679 bool has_adapted_arguments_;
10680
10681 DISALLOW_COPY_AND_ASSIGN(FrameInspector);
10682};
10683
10684
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010685static const int kFrameDetailsFrameIdIndex = 0;
10686static const int kFrameDetailsReceiverIndex = 1;
10687static const int kFrameDetailsFunctionIndex = 2;
10688static const int kFrameDetailsArgumentCountIndex = 3;
10689static const int kFrameDetailsLocalCountIndex = 4;
10690static const int kFrameDetailsSourcePositionIndex = 5;
10691static const int kFrameDetailsConstructCallIndex = 6;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010692static const int kFrameDetailsAtReturnIndex = 7;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010693static const int kFrameDetailsFlagsIndex = 8;
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010694static const int kFrameDetailsFirstDynamicIndex = 9;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010695
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010696
10697static SaveContext* FindSavedContextForFrame(Isolate* isolate,
10698 JavaScriptFrame* frame) {
10699 SaveContext* save = isolate->save_context();
10700 while (save != NULL && !save->IsBelowFrame(frame)) {
10701 save = save->prev();
10702 }
10703 ASSERT(save != NULL);
10704 return save;
10705}
10706
10707
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010708// Return an array with frame details
10709// args[0]: number: break id
10710// args[1]: number: frame index
10711//
10712// The array returned contains the following information:
10713// 0: Frame id
10714// 1: Receiver
10715// 2: Function
10716// 3: Argument count
10717// 4: Local count
10718// 5: Source position
10719// 6: Constructor call
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010720// 7: Is at return
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010721// 8: Flags
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010722// Arguments name, value
10723// Locals name, value
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010724// Return value if any
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010725RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFrameDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010726 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010727 ASSERT(args.length() == 2);
10728
10729 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000010730 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000010731 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
10732 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000010733 if (!maybe_check->ToObject(&check)) return maybe_check;
10734 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010735 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010736 Heap* heap = isolate->heap();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010737
10738 // Find the relevant frame with the requested index.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010739 StackFrame::Id id = isolate->debug()->break_frame_id();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010740 if (id == StackFrame::NO_ID) {
10741 // If there are no JavaScript stack frames return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010742 return heap->undefined_value();
ager@chromium.org8bb60582008-12-11 12:02:20 +000010743 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010744
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010745 int inlined_frame_index = 0; // Inlined frame index in optimized frame.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010746
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010747 int count = 0;
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010748 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010749 for (; !it.done(); it.Advance()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010750 if (index < count + it.frame()->GetInlineCount()) break;
10751 count += it.frame()->GetInlineCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010752 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010753 if (it.done()) return heap->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010754
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010755 if (it.frame()->is_optimized()) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010756 inlined_frame_index =
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010757 it.frame()->GetInlineCount() - (index - count) - 1;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010758 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010759 FrameInspector frame_inspector(it.frame(), inlined_frame_index, isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010760
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010761 // Traverse the saved contexts chain to find the active context for the
10762 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010763 SaveContext* save = FindSavedContextForFrame(isolate, it.frame());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010764
10765 // Get the frame id.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010766 Handle<Object> frame_id(WrapFrameId(it.frame()->id()), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010767
10768 // Find source position.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010769 int position =
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010770 it.frame()->LookupCode()->SourcePosition(it.frame()->pc());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010771
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010772 // Check for constructor frame. Inlined frames cannot be construct calls.
10773 bool inlined_frame =
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010774 it.frame()->is_optimized() && inlined_frame_index != 0;
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010775 bool constructor = !inlined_frame && it.frame()->IsConstructor();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010776
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000010777 // Get scope info and read from it for local variable information.
10778 Handle<JSFunction> function(JSFunction::cast(it.frame()->function()));
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010779 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010780 Handle<ScopeInfo> scope_info(shared->scope_info());
10781 ASSERT(*scope_info != ScopeInfo::Empty());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010782
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010783 // Get the locals names and values into a temporary array.
10784 //
10785 // TODO(1240907): Hide compiler-introduced stack variables
10786 // (e.g. .result)? For users of the debugger, they will probably be
10787 // confusing.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010788 Handle<FixedArray> locals =
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010789 isolate->factory()->NewFixedArray(scope_info->LocalCount() * 2);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010790
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010791 // Fill in the values of the locals.
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010792 int i = 0;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010793 for (; i < scope_info->StackLocalCount(); ++i) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010794 // Use the value from the stack.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010795 locals->set(i * 2, scope_info->LocalName(i));
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010796 locals->set(i * 2 + 1, frame_inspector.GetExpression(i));
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010797 }
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010798 if (i < scope_info->LocalCount()) {
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010799 // Get the context containing declarations.
10800 Handle<Context> context(
10801 Context::cast(it.frame()->context())->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010802 for (; i < scope_info->LocalCount(); ++i) {
10803 Handle<String> name(scope_info->LocalName(i));
10804 VariableMode mode;
10805 InitializationFlag init_flag;
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000010806 locals->set(i * 2, *name);
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010807 locals->set(i * 2 + 1, context->get(
10808 scope_info->ContextSlotIndex(*name, &mode, &init_flag)));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010809 }
10810 }
10811
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010812 // Check whether this frame is positioned at return. If not top
10813 // frame or if the frame is optimized it cannot be at a return.
10814 bool at_return = false;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010815 if (!it.frame()->is_optimized() && index == 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010816 at_return = isolate->debug()->IsBreakAtReturn(it.frame());
kasperl@chromium.orga5551262010-12-07 12:49:48 +000010817 }
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010818
10819 // If positioned just before return find the value to be returned and add it
10820 // to the frame information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010821 Handle<Object> return_value = isolate->factory()->undefined_value();
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010822 if (at_return) {
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000010823 StackFrameIterator it2(isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010824 Address internal_frame_sp = NULL;
10825 while (!it2.done()) {
10826 if (it2.frame()->is_internal()) {
10827 internal_frame_sp = it2.frame()->sp();
10828 } else {
10829 if (it2.frame()->is_java_script()) {
10830 if (it2.frame()->id() == it.frame()->id()) {
10831 // The internal frame just before the JavaScript frame contains the
10832 // value to return on top. A debug break at return will create an
10833 // internal frame to store the return value (eax/rax/r0) before
10834 // entering the debug break exit frame.
10835 if (internal_frame_sp != NULL) {
10836 return_value =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010837 Handle<Object>(Memory::Object_at(internal_frame_sp),
10838 isolate);
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010839 break;
10840 }
10841 }
10842 }
10843
10844 // Indicate that the previous frame was not an internal frame.
10845 internal_frame_sp = NULL;
10846 }
10847 it2.Advance();
10848 }
10849 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010850
10851 // Now advance to the arguments adapter frame (if any). It contains all
10852 // the provided parameters whereas the function frame always have the number
10853 // of arguments matching the functions parameters. The rest of the
10854 // information (except for what is collected above) is the same.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010855 if (it.frame()->has_adapted_arguments()) {
10856 it.AdvanceToArgumentsFrame();
10857 frame_inspector.SetArgumentsFrame(it.frame());
10858 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010859
10860 // Find the number of arguments to fill. At least fill the number of
10861 // parameters for the function and fill more if more parameters are provided.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010862 int argument_count = scope_info->ParameterCount();
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010863 if (argument_count < frame_inspector.GetParametersCount()) {
10864 argument_count = frame_inspector.GetParametersCount();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010865 }
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010866#ifdef DEBUG
10867 if (it.frame()->is_optimized()) {
10868 ASSERT_EQ(argument_count, frame_inspector.GetParametersCount());
10869 }
10870#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010871
10872 // Calculate the size of the result.
10873 int details_size = kFrameDetailsFirstDynamicIndex +
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010874 2 * (argument_count + scope_info->LocalCount()) +
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010875 (at_return ? 1 : 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010876 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010877
10878 // Add the frame id.
10879 details->set(kFrameDetailsFrameIdIndex, *frame_id);
10880
10881 // Add the function (same as in function frame).
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010882 details->set(kFrameDetailsFunctionIndex, frame_inspector.GetFunction());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010883
10884 // Add the arguments count.
10885 details->set(kFrameDetailsArgumentCountIndex, Smi::FromInt(argument_count));
10886
10887 // Add the locals count
10888 details->set(kFrameDetailsLocalCountIndex,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010889 Smi::FromInt(scope_info->LocalCount()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010890
10891 // Add the source position.
ager@chromium.org236ad962008-09-25 09:45:57 +000010892 if (position != RelocInfo::kNoPosition) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010893 details->set(kFrameDetailsSourcePositionIndex, Smi::FromInt(position));
10894 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010895 details->set(kFrameDetailsSourcePositionIndex, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010896 }
10897
10898 // Add the constructor information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010899 details->set(kFrameDetailsConstructCallIndex, heap->ToBoolean(constructor));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010900
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010901 // Add the at return information.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010902 details->set(kFrameDetailsAtReturnIndex, heap->ToBoolean(at_return));
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010903
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010904 // Add flags to indicate information on whether this frame is
10905 // bit 0: invoked in the debugger context.
10906 // bit 1: optimized frame.
10907 // bit 2: inlined in optimized frame
10908 int flags = 0;
10909 if (*save->context() == *isolate->debug()->debug_context()) {
10910 flags |= 1 << 0;
10911 }
10912 if (it.frame()->is_optimized()) {
10913 flags |= 1 << 1;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010914 flags |= inlined_frame_index << 2;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000010915 }
10916 details->set(kFrameDetailsFlagsIndex, Smi::FromInt(flags));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010917
10918 // Fill the dynamic part.
10919 int details_index = kFrameDetailsFirstDynamicIndex;
10920
10921 // Add arguments name and value.
10922 for (int i = 0; i < argument_count; i++) {
10923 // Name of the argument.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010924 if (i < scope_info->ParameterCount()) {
10925 details->set(details_index++, scope_info->ParameterName(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010926 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010927 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010928 }
10929
sgjesse@chromium.org6db88712011-07-11 11:41:22 +000010930 // Parameter value.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010931 if (i < it.frame()->ComputeParametersCount()) {
10932 // Get the value from the stack.
10933 details->set(details_index++, frame_inspector.GetParameter(i));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010934 } else {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000010935 details->set(details_index++, heap->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010936 }
10937 }
10938
10939 // Add locals name and value from the temporary copy from the function frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010940 for (int i = 0; i < scope_info->LocalCount() * 2; i++) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010941 details->set(details_index++, locals->get(i));
10942 }
10943
ager@chromium.org2cc82ae2010-06-14 07:35:38 +000010944 // Add the value being returned.
10945 if (at_return) {
10946 details->set(details_index++, *return_value);
10947 }
10948
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010949 // Add the receiver (same as in function frame).
10950 // THIS MUST BE DONE LAST SINCE WE MIGHT ADVANCE
10951 // THE FRAME ITERATOR TO WRAP THE RECEIVER.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010952 Handle<Object> receiver(it.frame()->receiver(), isolate);
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000010953 if (!receiver->IsJSObject() &&
10954 shared->is_classic_mode() &&
10955 !shared->native()) {
rossberg@chromium.org717967f2011-07-20 13:44:42 +000010956 // If the receiver is not a JSObject and the function is not a
10957 // builtin or strict-mode we have hit an optimization where a
10958 // value object is not converted into a wrapped JS objects. To
10959 // hide this optimization from the debugger, we wrap the receiver
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010960 // by creating correct wrapper object based on the calling frame's
10961 // global context.
10962 it.Advance();
10963 Handle<Context> calling_frames_global_context(
10964 Context::cast(Context::cast(it.frame()->context())->global_context()));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010965 receiver =
10966 isolate->factory()->ToObject(receiver, calling_frames_global_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010967 }
10968 details->set(kFrameDetailsReceiverIndex, *receiver);
10969
10970 ASSERT_EQ(details_size, details_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010971 return *isolate->factory()->NewJSArrayWithElements(details);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000010972}
10973
10974
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010975// Copy all the context locals into an object used to materialize a scope.
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010976static bool CopyContextLocalsToScopeObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000010977 Isolate* isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010978 Handle<ScopeInfo> scope_info,
ager@chromium.orgb5737492010-07-15 09:29:43 +000010979 Handle<Context> context,
10980 Handle<JSObject> scope_object) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010981 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010982 for (int i = 0; i < scope_info->ContextLocalCount(); i++) {
10983 VariableMode mode;
10984 InitializationFlag init_flag;
10985 int context_index = scope_info->ContextSlotIndex(
10986 scope_info->ContextLocalName(i), &mode, &init_flag);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010987
whesse@chromium.org7b260152011-06-20 15:33:18 +000010988 RETURN_IF_EMPTY_HANDLE_VALUE(
10989 isolate,
10990 SetProperty(scope_object,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000010991 Handle<String>(scope_info->ContextLocalName(i)),
whesse@chromium.org7b260152011-06-20 15:33:18 +000010992 Handle<Object>(context->get(context_index), isolate),
10993 NONE,
10994 kNonStrictMode),
10995 false);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010996 }
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000010997
10998 return true;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000010999}
11000
11001
11002// Create a plain JSObject which materializes the local scope for the specified
11003// frame.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011004static Handle<JSObject> MaterializeLocalScope(
11005 Isolate* isolate,
11006 JavaScriptFrame* frame,
11007 int inlined_frame_index) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011008 Handle<JSFunction> function(JSFunction::cast(frame->function()));
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011009 Handle<SharedFunctionInfo> shared(function->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011010 Handle<ScopeInfo> scope_info(shared->scope_info());
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011011 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011012
11013 // Allocate and initialize a JSObject with all the arguments, stack locals
11014 // heap locals and extension properties of the debugged function.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011015 Handle<JSObject> local_scope =
11016 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011017
11018 // First fill all parameters.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011019 for (int i = 0; i < scope_info->ParameterCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011020 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011021 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011022 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011023 Handle<String>(scope_info->ParameterName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011024 Handle<Object>(frame_inspector.GetParameter(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011025 NONE,
11026 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011027 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011028 }
11029
11030 // Second fill all stack locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011031 for (int i = 0; i < scope_info->StackLocalCount(); ++i) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011032 RETURN_IF_EMPTY_HANDLE_VALUE(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011033 isolate,
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011034 SetProperty(local_scope,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011035 Handle<String>(scope_info->StackLocalName(i)),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011036 Handle<Object>(frame_inspector.GetExpression(i)),
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011037 NONE,
11038 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011039 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011040 }
11041
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011042 if (scope_info->HasContext()) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011043 // Third fill all context locals.
11044 Handle<Context> frame_context(Context::cast(frame->context()));
11045 Handle<Context> function_context(frame_context->declaration_context());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011046 if (!CopyContextLocalsToScopeObject(
11047 isolate, scope_info, function_context, local_scope)) {
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011048 return Handle<JSObject>();
11049 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011050
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011051 // Finally copy any properties from the function context extension.
11052 // These will be variables introduced by eval.
11053 if (function_context->closure() == *function) {
11054 if (function_context->has_extension() &&
11055 !function_context->IsGlobalContext()) {
11056 Handle<JSObject> ext(JSObject::cast(function_context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011057 bool threw = false;
11058 Handle<FixedArray> keys =
11059 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11060 if (threw) return Handle<JSObject>();
11061
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011062 for (int i = 0; i < keys->length(); i++) {
11063 // Names of variables introduced by eval are strings.
11064 ASSERT(keys->get(i)->IsString());
11065 Handle<String> key(String::cast(keys->get(i)));
11066 RETURN_IF_EMPTY_HANDLE_VALUE(
11067 isolate,
11068 SetProperty(local_scope,
11069 key,
11070 GetProperty(ext, key),
11071 NONE,
11072 kNonStrictMode),
11073 Handle<JSObject>());
11074 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011075 }
11076 }
11077 }
ricow@chromium.org4f693d62011-07-04 14:01:31 +000011078
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011079 return local_scope;
11080}
11081
11082
11083// Create a plain JSObject which materializes the closure content for the
11084// context.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011085static Handle<JSObject> MaterializeClosure(Isolate* isolate,
11086 Handle<Context> context) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011087 ASSERT(context->IsFunctionContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011088
ager@chromium.org6a2b0aa2010-07-13 20:58:03 +000011089 Handle<SharedFunctionInfo> shared(context->closure()->shared());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011090 Handle<ScopeInfo> scope_info(shared->scope_info());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011091
11092 // Allocate and initialize a JSObject with all the content of theis function
11093 // closure.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011094 Handle<JSObject> closure_scope =
11095 isolate->factory()->NewJSObject(isolate->object_function());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011096
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011097 // Fill all context locals to the context extension.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011098 if (!CopyContextLocalsToScopeObject(
11099 isolate, scope_info, context, closure_scope)) {
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011100 return Handle<JSObject>();
11101 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011102
11103 // Finally copy any properties from the function context extension. This will
11104 // be variables introduced by eval.
11105 if (context->has_extension()) {
11106 Handle<JSObject> ext(JSObject::cast(context->extension()));
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011107 bool threw = false;
11108 Handle<FixedArray> keys =
11109 GetKeysInFixedArrayFor(ext, INCLUDE_PROTOS, &threw);
11110 if (threw) return Handle<JSObject>();
11111
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011112 for (int i = 0; i < keys->length(); i++) {
11113 // Names of variables introduced by eval are strings.
11114 ASSERT(keys->get(i)->IsString());
11115 Handle<String> key(String::cast(keys->get(i)));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011116 RETURN_IF_EMPTY_HANDLE_VALUE(
11117 isolate,
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000011118 SetProperty(closure_scope,
11119 key,
11120 GetProperty(ext, key),
11121 NONE,
11122 kNonStrictMode),
sgjesse@chromium.org496c03a2011-02-14 12:05:43 +000011123 Handle<JSObject>());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011124 }
11125 }
11126
11127 return closure_scope;
11128}
11129
11130
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011131// Create a plain JSObject which materializes the scope for the specified
11132// catch context.
11133static Handle<JSObject> MaterializeCatchScope(Isolate* isolate,
11134 Handle<Context> context) {
11135 ASSERT(context->IsCatchContext());
11136 Handle<String> name(String::cast(context->extension()));
11137 Handle<Object> thrown_object(context->get(Context::THROWN_OBJECT_INDEX));
11138 Handle<JSObject> catch_scope =
11139 isolate->factory()->NewJSObject(isolate->object_function());
11140 RETURN_IF_EMPTY_HANDLE_VALUE(
11141 isolate,
11142 SetProperty(catch_scope, name, thrown_object, NONE, kNonStrictMode),
11143 Handle<JSObject>());
11144 return catch_scope;
11145}
11146
11147
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011148// Create a plain JSObject which materializes the block scope for the specified
11149// block context.
11150static Handle<JSObject> MaterializeBlockScope(
11151 Isolate* isolate,
11152 Handle<Context> context) {
11153 ASSERT(context->IsBlockContext());
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011154 Handle<ScopeInfo> scope_info(ScopeInfo::cast(context->extension()));
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011155
11156 // Allocate and initialize a JSObject with all the arguments, stack locals
11157 // heap locals and extension properties of the debugged function.
11158 Handle<JSObject> block_scope =
11159 isolate->factory()->NewJSObject(isolate->object_function());
11160
11161 // Fill all context locals.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011162 if (!CopyContextLocalsToScopeObject(
11163 isolate, scope_info, context, block_scope)) {
11164 return Handle<JSObject>();
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011165 }
11166
11167 return block_scope;
11168}
11169
11170
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011171// Iterate over the actual scopes visible from a stack frame. The iteration
11172// proceeds from the innermost visible nested scope outwards. All scopes are
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011173// backed by an actual context except the local scope, which is inserted
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011174// "artificially" in the context chain.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011175class ScopeIterator {
11176 public:
11177 enum ScopeType {
11178 ScopeTypeGlobal = 0,
11179 ScopeTypeLocal,
11180 ScopeTypeWith,
ager@chromium.orga1645e22009-09-09 19:27:10 +000011181 ScopeTypeClosure,
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011182 ScopeTypeCatch,
11183 ScopeTypeBlock
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011184 };
11185
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011186 ScopeIterator(Isolate* isolate,
11187 JavaScriptFrame* frame,
11188 int inlined_frame_index)
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011189 : isolate_(isolate),
11190 frame_(frame),
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011191 inlined_frame_index_(inlined_frame_index),
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011192 function_(JSFunction::cast(frame->function())),
11193 context_(Context::cast(frame->context())),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011194 nested_scope_chain_(4) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011195
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011196 // Catch the case when the debugger stops in an internal function.
11197 Handle<SharedFunctionInfo> shared_info(function_->shared());
11198 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11199 if (shared_info->script() == isolate->heap()->undefined_value()) {
11200 while (context_->closure() == *function_) {
11201 context_ = Handle<Context>(context_->previous(), isolate_);
11202 }
11203 return;
11204 }
11205
11206 // Get the debug info (create it if it does not exist).
11207 if (!isolate->debug()->EnsureDebugInfo(shared_info)) {
11208 // Return if ensuring debug info failed.
11209 return;
11210 }
11211 Handle<DebugInfo> debug_info = Debug::GetDebugInfo(shared_info);
11212
11213 // Find the break point where execution has stopped.
11214 BreakLocationIterator break_location_iterator(debug_info,
11215 ALL_BREAK_LOCATIONS);
11216 break_location_iterator.FindBreakLocationFromAddress(frame->pc());
11217 if (break_location_iterator.IsExit()) {
11218 // We are within the return sequence. At the momemt it is not possible to
11219 // get a source position which is consistent with the current scope chain.
11220 // Thus all nested with, catch and block contexts are skipped and we only
11221 // provide the function scope.
11222 if (scope_info->HasContext()) {
11223 context_ = Handle<Context>(context_->declaration_context(), isolate_);
11224 } else {
11225 while (context_->closure() == *function_) {
11226 context_ = Handle<Context>(context_->previous(), isolate_);
11227 }
11228 }
11229 if (scope_info->Type() != EVAL_SCOPE) nested_scope_chain_.Add(scope_info);
11230 } else {
11231 // Reparse the code and analyze the scopes.
11232 ZoneScope zone_scope(isolate, DELETE_ON_EXIT);
11233 Handle<Script> script(Script::cast(shared_info->script()));
11234 Scope* scope = NULL;
11235
11236 // Check whether we are in global, eval or function code.
11237 Handle<ScopeInfo> scope_info(shared_info->scope_info());
11238 if (scope_info->Type() != FUNCTION_SCOPE) {
11239 // Global or eval code.
11240 CompilationInfo info(script);
11241 if (scope_info->Type() == GLOBAL_SCOPE) {
11242 info.MarkAsGlobal();
11243 } else {
11244 ASSERT(scope_info->Type() == EVAL_SCOPE);
11245 info.MarkAsEval();
11246 info.SetCallingContext(Handle<Context>(function_->context()));
11247 }
11248 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11249 scope = info.function()->scope();
11250 }
11251 } else {
11252 // Function code
11253 CompilationInfo info(shared_info);
11254 if (ParserApi::Parse(&info, kNoParsingFlags) && Scope::Analyze(&info)) {
11255 scope = info.function()->scope();
11256 }
11257 }
11258
11259 // Retrieve the scope chain for the current position.
11260 if (scope != NULL) {
11261 int source_position = shared_info->code()->SourcePosition(frame_->pc());
11262 scope->GetNestedScopeChain(&nested_scope_chain_, source_position);
11263 } else {
11264 // A failed reparse indicates that the preparser has diverged from the
11265 // parser or that the preparse data given to the initial parse has been
11266 // faulty. We fail in debug mode but in release mode we only provide the
11267 // information we get from the context chain but nothing about
11268 // completely stack allocated scopes or stack allocated locals.
11269 UNREACHABLE();
11270 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011271 }
11272 }
11273
11274 // More scopes?
11275 bool Done() { return context_.is_null(); }
11276
11277 // Move to the next scope.
11278 void Next() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011279 ScopeType scope_type = Type();
11280 if (scope_type == ScopeTypeGlobal) {
11281 // The global scope is always the last in the chain.
11282 ASSERT(context_->IsGlobalContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011283 context_ = Handle<Context>();
11284 return;
11285 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011286 if (nested_scope_chain_.is_empty()) {
11287 context_ = Handle<Context>(context_->previous(), isolate_);
11288 } else {
11289 if (nested_scope_chain_.last()->HasContext()) {
11290 ASSERT(context_->previous() != NULL);
11291 context_ = Handle<Context>(context_->previous(), isolate_);
11292 }
11293 nested_scope_chain_.RemoveLast();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011294 }
11295 }
11296
11297 // Return the type of the current scope.
lrn@chromium.org34e60782011-09-15 07:25:40 +000011298 ScopeType Type() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011299 if (!nested_scope_chain_.is_empty()) {
11300 Handle<ScopeInfo> scope_info = nested_scope_chain_.last();
11301 switch (scope_info->Type()) {
11302 case FUNCTION_SCOPE:
11303 ASSERT(context_->IsFunctionContext() ||
11304 !scope_info->HasContext());
11305 return ScopeTypeLocal;
11306 case GLOBAL_SCOPE:
11307 ASSERT(context_->IsGlobalContext());
11308 return ScopeTypeGlobal;
11309 case WITH_SCOPE:
11310 ASSERT(context_->IsWithContext());
11311 return ScopeTypeWith;
11312 case CATCH_SCOPE:
11313 ASSERT(context_->IsCatchContext());
11314 return ScopeTypeCatch;
11315 case BLOCK_SCOPE:
11316 ASSERT(!scope_info->HasContext() ||
11317 context_->IsBlockContext());
11318 return ScopeTypeBlock;
11319 case EVAL_SCOPE:
11320 UNREACHABLE();
11321 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011322 }
11323 if (context_->IsGlobalContext()) {
11324 ASSERT(context_->global()->IsGlobalObject());
11325 return ScopeTypeGlobal;
11326 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011327 if (context_->IsFunctionContext()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011328 return ScopeTypeClosure;
11329 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011330 if (context_->IsCatchContext()) {
ager@chromium.orga1645e22009-09-09 19:27:10 +000011331 return ScopeTypeCatch;
11332 }
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011333 if (context_->IsBlockContext()) {
11334 return ScopeTypeBlock;
11335 }
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011336 ASSERT(context_->IsWithContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011337 return ScopeTypeWith;
11338 }
11339
11340 // Return the JavaScript object with the content of the current scope.
11341 Handle<JSObject> ScopeObject() {
11342 switch (Type()) {
11343 case ScopeIterator::ScopeTypeGlobal:
11344 return Handle<JSObject>(CurrentContext()->global());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011345 case ScopeIterator::ScopeTypeLocal:
11346 // Materialize the content of the local scope into a JSObject.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011347 ASSERT(nested_scope_chain_.length() == 1);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011348 return MaterializeLocalScope(isolate_, frame_, inlined_frame_index_);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011349 case ScopeIterator::ScopeTypeWith:
11350 // Return the with object.
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011351 return Handle<JSObject>(JSObject::cast(CurrentContext()->extension()));
11352 case ScopeIterator::ScopeTypeCatch:
11353 return MaterializeCatchScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011354 case ScopeIterator::ScopeTypeClosure:
11355 // Materialize the content of the closure scope into a JSObject.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011356 return MaterializeClosure(isolate_, CurrentContext());
whesse@chromium.org4acdc2c2011-08-15 13:01:23 +000011357 case ScopeIterator::ScopeTypeBlock:
11358 return MaterializeBlockScope(isolate_, CurrentContext());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011359 }
11360 UNREACHABLE();
11361 return Handle<JSObject>();
11362 }
11363
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011364 Handle<ScopeInfo> CurrentScopeInfo() {
11365 if (!nested_scope_chain_.is_empty()) {
11366 return nested_scope_chain_.last();
11367 } else if (context_->IsBlockContext()) {
11368 return Handle<ScopeInfo>(ScopeInfo::cast(context_->extension()));
11369 } else if (context_->IsFunctionContext()) {
11370 return Handle<ScopeInfo>(context_->closure()->shared()->scope_info());
11371 }
11372 return Handle<ScopeInfo>::null();
11373 }
11374
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011375 // Return the context for this scope. For the local context there might not
11376 // be an actual context.
11377 Handle<Context> CurrentContext() {
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011378 if (Type() == ScopeTypeGlobal ||
11379 nested_scope_chain_.is_empty()) {
11380 return context_;
11381 } else if (nested_scope_chain_.last()->HasContext()) {
11382 return context_;
11383 } else {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011384 return Handle<Context>();
11385 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011386 }
11387
11388#ifdef DEBUG
11389 // Debug print of the content of the current scope.
11390 void DebugPrint() {
11391 switch (Type()) {
11392 case ScopeIterator::ScopeTypeGlobal:
11393 PrintF("Global:\n");
11394 CurrentContext()->Print();
11395 break;
11396
11397 case ScopeIterator::ScopeTypeLocal: {
11398 PrintF("Local:\n");
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011399 function_->shared()->scope_info()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011400 if (!CurrentContext().is_null()) {
11401 CurrentContext()->Print();
11402 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011403 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011404 if (extension->IsJSContextExtensionObject()) {
11405 extension->Print();
11406 }
11407 }
11408 }
11409 break;
11410 }
11411
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011412 case ScopeIterator::ScopeTypeWith:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011413 PrintF("With:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011414 CurrentContext()->extension()->Print();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011415 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011416
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011417 case ScopeIterator::ScopeTypeCatch:
ager@chromium.orga1645e22009-09-09 19:27:10 +000011418 PrintF("Catch:\n");
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011419 CurrentContext()->extension()->Print();
11420 CurrentContext()->get(Context::THROWN_OBJECT_INDEX)->Print();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011421 break;
ager@chromium.orga1645e22009-09-09 19:27:10 +000011422
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011423 case ScopeIterator::ScopeTypeClosure:
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011424 PrintF("Closure:\n");
11425 CurrentContext()->Print();
11426 if (CurrentContext()->has_extension()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011427 Handle<Object> extension(CurrentContext()->extension());
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011428 if (extension->IsJSContextExtensionObject()) {
11429 extension->Print();
11430 }
11431 }
11432 break;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011433
11434 default:
11435 UNREACHABLE();
11436 }
11437 PrintF("\n");
11438 }
11439#endif
11440
11441 private:
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011442 Isolate* isolate_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011443 JavaScriptFrame* frame_;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011444 int inlined_frame_index_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011445 Handle<JSFunction> function_;
11446 Handle<Context> context_;
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011447 List<Handle<ScopeInfo> > nested_scope_chain_;
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011448
11449 DISALLOW_IMPLICIT_CONSTRUCTORS(ScopeIterator);
11450};
11451
11452
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011453RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011454 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011455 ASSERT(args.length() == 2);
11456
11457 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011458 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011459 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11460 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011461 if (!maybe_check->ToObject(&check)) return maybe_check;
11462 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011463 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
11464
11465 // Get the frame where the debugging is performed.
11466 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011467 JavaScriptFrameIterator it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011468 JavaScriptFrame* frame = it.frame();
11469
11470 // Count the visible scopes.
11471 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011472 for (ScopeIterator it(isolate, frame, 0);
11473 !it.Done();
11474 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011475 n++;
11476 }
11477
11478 return Smi::FromInt(n);
11479}
11480
11481
11482static const int kScopeDetailsTypeIndex = 0;
11483static const int kScopeDetailsObjectIndex = 1;
11484static const int kScopeDetailsSize = 2;
11485
11486// Return an array with scope details
11487// args[0]: number: break id
11488// args[1]: number: frame index
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011489// args[2]: number: inlined frame index
11490// args[3]: number: scope index
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011491//
11492// The array returned contains the following information:
11493// 0: Scope type
11494// 1: Scope object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011495RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScopeDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011496 HandleScope scope(isolate);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011497 ASSERT(args.length() == 4);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011498
11499 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011500 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011501 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11502 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011503 if (!maybe_check->ToObject(&check)) return maybe_check;
11504 }
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011505 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011506 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
11507 CONVERT_NUMBER_CHECKED(int, index, Int32, args[3]);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011508
11509 // Get the frame where the debugging is performed.
11510 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000011511 JavaScriptFrameIterator frame_it(isolate, id);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011512 JavaScriptFrame* frame = frame_it.frame();
11513
11514 // Find the requested scope.
11515 int n = 0;
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011516 ScopeIterator it(isolate, frame, inlined_frame_index);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011517 for (; !it.Done() && n < index; it.Next()) {
11518 n++;
11519 }
11520 if (it.Done()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011521 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011522 }
11523
11524 // Calculate the size of the result.
11525 int details_size = kScopeDetailsSize;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011526 Handle<FixedArray> details = isolate->factory()->NewFixedArray(details_size);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011527
11528 // Fill in scope details.
11529 details->set(kScopeDetailsTypeIndex, Smi::FromInt(it.Type()));
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011530 Handle<JSObject> scope_object = it.ScopeObject();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011531 RETURN_IF_EMPTY_HANDLE(isolate, scope_object);
whesse@chromium.org4a1fe7d2010-09-27 12:32:04 +000011532 details->set(kScopeDetailsObjectIndex, *scope_object);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011533
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011534 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011535}
11536
11537
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011538RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugPrintScopes) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011539 HandleScope scope(isolate);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011540 ASSERT(args.length() == 0);
11541
11542#ifdef DEBUG
11543 // Print the scopes for the top frame.
11544 StackFrameLocator locator;
11545 JavaScriptFrame* frame = locator.FindJavaScriptFrame(0);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011546 for (ScopeIterator it(isolate, frame, 0);
11547 !it.Done();
11548 it.Next()) {
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011549 it.DebugPrint();
11550 }
11551#endif
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011552 return isolate->heap()->undefined_value();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000011553}
11554
11555
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011556RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadCount) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011557 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011558 ASSERT(args.length() == 1);
11559
11560 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011561 Object* result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011562 { MaybeObject* maybe_result = Runtime_CheckExecutionState(
11563 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011564 if (!maybe_result->ToObject(&result)) return maybe_result;
11565 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011566
11567 // Count all archived V8 threads.
11568 int n = 0;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011569 for (ThreadState* thread =
11570 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011571 thread != NULL;
11572 thread = thread->Next()) {
11573 n++;
11574 }
11575
11576 // Total number of threads is current thread and archived threads.
11577 return Smi::FromInt(n + 1);
11578}
11579
11580
11581static const int kThreadDetailsCurrentThreadIndex = 0;
11582static const int kThreadDetailsThreadIdIndex = 1;
11583static const int kThreadDetailsSize = 2;
11584
11585// Return an array with thread details
11586// args[0]: number: break id
11587// args[1]: number: thread index
11588//
11589// The array returned contains the following information:
11590// 0: Is current thread?
11591// 1: Thread id
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011592RUNTIME_FUNCTION(MaybeObject*, Runtime_GetThreadDetails) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011593 HandleScope scope(isolate);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011594 ASSERT(args.length() == 2);
11595
11596 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011597 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011598 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11599 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011600 if (!maybe_check->ToObject(&check)) return maybe_check;
11601 }
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011602 CONVERT_NUMBER_CHECKED(int, index, Int32, args[1]);
11603
11604 // Allocate array for result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011605 Handle<FixedArray> details =
11606 isolate->factory()->NewFixedArray(kThreadDetailsSize);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011607
11608 // Thread index 0 is current thread.
11609 if (index == 0) {
11610 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011611 details->set(kThreadDetailsCurrentThreadIndex,
11612 isolate->heap()->true_value());
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011613 details->set(kThreadDetailsThreadIdIndex,
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011614 Smi::FromInt(ThreadId::Current().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011615 } else {
11616 // Find the thread with the requested index.
11617 int n = 1;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011618 ThreadState* thread =
11619 isolate->thread_manager()->FirstThreadStateInUse();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011620 while (index != n && thread != NULL) {
11621 thread = thread->Next();
11622 n++;
11623 }
11624 if (thread == NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011625 return isolate->heap()->undefined_value();
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011626 }
11627
11628 // Fill the details.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011629 details->set(kThreadDetailsCurrentThreadIndex,
11630 isolate->heap()->false_value());
ager@chromium.orga9aa5fa2011-04-13 08:46:07 +000011631 details->set(kThreadDetailsThreadIdIndex,
11632 Smi::FromInt(thread->id().ToInteger()));
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011633 }
11634
11635 // Convert to JS array and return.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011636 return *isolate->factory()->NewJSArrayWithElements(details);
ager@chromium.orgbb29dc92009-03-24 13:25:23 +000011637}
11638
11639
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011640// Sets the disable break state
11641// args[0]: disable break state
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011642RUNTIME_FUNCTION(MaybeObject*, Runtime_SetDisableBreak) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011643 HandleScope scope(isolate);
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011644 ASSERT(args.length() == 1);
11645 CONVERT_BOOLEAN_CHECKED(disable_break, args[0]);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011646 isolate->debug()->set_disable_break(disable_break);
11647 return isolate->heap()->undefined_value();
whesse@chromium.orge90029b2010-08-02 11:52:17 +000011648}
11649
11650
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011651RUNTIME_FUNCTION(MaybeObject*, Runtime_GetBreakLocations) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011652 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011653 ASSERT(args.length() == 1);
11654
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011655 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11656 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011657 // Find the number of break points
11658 Handle<Object> break_locations = Debug::GetSourceBreakLocations(shared);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011659 if (break_locations->IsUndefined()) return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011660 // Return array as JS array
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011661 return *isolate->factory()->NewJSArrayWithElements(
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011662 Handle<FixedArray>::cast(break_locations));
11663}
11664
11665
11666// Set a break point in a function
11667// args[0]: function
11668// args[1]: number: break source position (within the function source)
11669// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011670RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFunctionBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011671 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011672 ASSERT(args.length() == 3);
ager@chromium.org5aa501c2009-06-23 07:57:28 +000011673 CONVERT_ARG_CHECKED(JSFunction, fun, 0);
11674 Handle<SharedFunctionInfo> shared(fun->shared());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011675 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11676 RUNTIME_ASSERT(source_position >= 0);
11677 Handle<Object> break_point_object_arg = args.at<Object>(2);
11678
11679 // Set break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011680 isolate->debug()->SetBreakPoint(shared, break_point_object_arg,
11681 &source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011682
lrn@chromium.org32d961d2010-06-30 09:09:34 +000011683 return Smi::FromInt(source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011684}
11685
11686
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011687Object* Runtime::FindSharedFunctionInfoInScript(Isolate* isolate,
11688 Handle<Script> script,
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011689 int position) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011690 // Iterate the heap looking for SharedFunctionInfo generated from the
11691 // script. The inner most SharedFunctionInfo containing the source position
11692 // for the requested break point is found.
kasperl@chromium.orga5551262010-12-07 12:49:48 +000011693 // NOTE: This might require several heap iterations. If the SharedFunctionInfo
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011694 // which is found is not compiled it is compiled and the heap is iterated
11695 // again as the compilation might create inner functions from the newly
11696 // compiled function and the actual requested break point might be in one of
11697 // these functions.
11698 bool done = false;
11699 // The current candidate for the source position:
ager@chromium.org236ad962008-09-25 09:45:57 +000011700 int target_start_position = RelocInfo::kNoPosition;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011701 Handle<SharedFunctionInfo> target;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011702 while (!done) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011703 { // Extra scope for iterator and no-allocation.
11704 isolate->heap()->EnsureHeapIsIterable();
11705 AssertNoAllocation no_alloc_during_heap_iteration;
11706 HeapIterator iterator;
11707 for (HeapObject* obj = iterator.next();
11708 obj != NULL; obj = iterator.next()) {
11709 if (obj->IsSharedFunctionInfo()) {
11710 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(obj));
11711 if (shared->script() == *script) {
11712 // If the SharedFunctionInfo found has the requested script data and
11713 // contains the source position it is a candidate.
11714 int start_position = shared->function_token_position();
11715 if (start_position == RelocInfo::kNoPosition) {
11716 start_position = shared->start_position();
11717 }
11718 if (start_position <= position &&
11719 position <= shared->end_position()) {
11720 // If there is no candidate or this function is within the current
11721 // candidate this is the new candidate.
11722 if (target.is_null()) {
11723 target_start_position = start_position;
11724 target = shared;
11725 } else {
11726 if (target_start_position == start_position &&
11727 shared->end_position() == target->end_position()) {
11728 // If a top-level function contain only one function
11729 // declartion the source for the top-level and the
11730 // function is the same. In that case prefer the non
11731 // top-level function.
11732 if (!shared->is_toplevel()) {
11733 target_start_position = start_position;
11734 target = shared;
11735 }
11736 } else if (target_start_position <= start_position &&
11737 shared->end_position() <= target->end_position()) {
11738 // This containment check includes equality as a function
11739 // inside a top-level function can share either start or end
11740 // position with the top-level function.
ager@chromium.orga1645e22009-09-09 19:27:10 +000011741 target_start_position = start_position;
11742 target = shared;
11743 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011744 }
11745 }
11746 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011747 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011748 } // End for loop.
11749 } // End No allocation scope.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011750
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011751 if (target.is_null()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011752 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011753 }
11754
11755 // If the candidate found is compiled we are done. NOTE: when lazy
11756 // compilation of inner functions is introduced some additional checking
11757 // needs to be done here to compile inner functions.
11758 done = target->is_compiled();
11759 if (!done) {
11760 // If the candidate is not compiled compile it to reveal any inner
11761 // functions which might contain the requested source position.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011762 SharedFunctionInfo::CompileLazy(target, KEEP_EXCEPTION);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011763 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000011764 } // End while loop.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011765
11766 return *target;
11767}
11768
11769
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011770// Changes the state of a break point in a script and returns source position
11771// where break point was set. NOTE: Regarding performance see the NOTE for
11772// GetScriptFromScriptData.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011773// args[0]: script to set break point in
11774// args[1]: number: break source position (within the script source)
11775// args[2]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011776RUNTIME_FUNCTION(MaybeObject*, Runtime_SetScriptBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011777 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011778 ASSERT(args.length() == 3);
11779 CONVERT_ARG_CHECKED(JSValue, wrapper, 0);
11780 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
11781 RUNTIME_ASSERT(source_position >= 0);
11782 Handle<Object> break_point_object_arg = args.at<Object>(2);
11783
11784 // Get the script from the script wrapper.
11785 RUNTIME_ASSERT(wrapper->value()->IsScript());
11786 Handle<Script> script(Script::cast(wrapper->value()));
11787
kasperl@chromium.orgd1e3e722009-04-14 13:38:25 +000011788 Object* result = Runtime::FindSharedFunctionInfoInScript(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011789 isolate, script, source_position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011790 if (!result->IsUndefined()) {
11791 Handle<SharedFunctionInfo> shared(SharedFunctionInfo::cast(result));
11792 // Find position within function. The script position might be before the
11793 // source position of the first function.
11794 int position;
11795 if (shared->start_position() > source_position) {
11796 position = 0;
11797 } else {
11798 position = source_position - shared->start_position();
11799 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011800 isolate->debug()->SetBreakPoint(shared, break_point_object_arg, &position);
ricow@chromium.org5ad5ace2010-06-23 09:06:43 +000011801 position += shared->start_position();
11802 return Smi::FromInt(position);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011803 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011804 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011805}
11806
11807
11808// Clear a break point
11809// args[0]: number: break point object
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011810RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearBreakPoint) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011811 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011812 ASSERT(args.length() == 1);
11813 Handle<Object> break_point_object_arg = args.at<Object>(0);
11814
11815 // Clear break point.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011816 isolate->debug()->ClearBreakPoint(break_point_object_arg);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011817
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011818 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011819}
11820
11821
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011822// Change the state of break on exceptions.
11823// args[0]: Enum value indicating whether to affect caught/uncaught exceptions.
11824// args[1]: Boolean indicating on/off.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011825RUNTIME_FUNCTION(MaybeObject*, Runtime_ChangeBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011826 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011827 ASSERT(args.length() == 2);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011828 RUNTIME_ASSERT(args[0]->IsNumber());
11829 CONVERT_BOOLEAN_CHECKED(enable, args[1]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011830
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011831 // If the number doesn't match an enum value, the ChangeBreakOnException
11832 // function will default to affecting caught exceptions.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011833 ExceptionBreakType type =
11834 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011835 // Update break point state.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011836 isolate->debug()->ChangeBreakOnException(type, enable);
11837 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011838}
11839
11840
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011841// Returns the state of break on exceptions
11842// args[0]: boolean indicating uncaught exceptions
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011843RUNTIME_FUNCTION(MaybeObject*, Runtime_IsBreakOnException) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011844 HandleScope scope(isolate);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011845 ASSERT(args.length() == 1);
11846 RUNTIME_ASSERT(args[0]->IsNumber());
11847
11848 ExceptionBreakType type =
11849 static_cast<ExceptionBreakType>(NumberToUint32(args[0]));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011850 bool result = isolate->debug()->IsBreakOnException(type);
fschneider@chromium.orgc20610a2010-09-22 09:44:58 +000011851 return Smi::FromInt(result);
11852}
11853
11854
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011855// Prepare for stepping
11856// args[0]: break id for checking execution state
11857// args[1]: step action from the enumeration StepAction
ager@chromium.orga1645e22009-09-09 19:27:10 +000011858// args[2]: number of times to perform the step, for step out it is the number
11859// of frames to step down.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011860RUNTIME_FUNCTION(MaybeObject*, Runtime_PrepareStep) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011861 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011862 ASSERT(args.length() == 3);
11863 // Check arguments.
lrn@chromium.org303ada72010-10-27 09:33:13 +000011864 Object* check;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011865 { MaybeObject* maybe_check = Runtime_CheckExecutionState(
11866 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000011867 if (!maybe_check->ToObject(&check)) return maybe_check;
11868 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011869 if (!args[1]->IsNumber() || !args[2]->IsNumber()) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011870 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011871 }
11872
11873 // Get the step action and check validity.
11874 StepAction step_action = static_cast<StepAction>(NumberToInt32(args[1]));
11875 if (step_action != StepIn &&
11876 step_action != StepNext &&
11877 step_action != StepOut &&
11878 step_action != StepInMin &&
11879 step_action != StepMin) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011880 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011881 }
11882
11883 // Get the number of steps.
11884 int step_count = NumberToInt32(args[2]);
11885 if (step_count < 1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011886 return isolate->Throw(isolate->heap()->illegal_argument_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011887 }
11888
ager@chromium.orga1645e22009-09-09 19:27:10 +000011889 // Clear all current stepping setup.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011890 isolate->debug()->ClearStepping();
ager@chromium.orga1645e22009-09-09 19:27:10 +000011891
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011892 // Prepare step.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011893 isolate->debug()->PrepareStep(static_cast<StepAction>(step_action),
11894 step_count);
11895 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011896}
11897
11898
11899// Clear all stepping set by PrepareStep.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000011900RUNTIME_FUNCTION(MaybeObject*, Runtime_ClearStepping) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011901 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000011902 ASSERT(args.length() == 0);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011903 isolate->debug()->ClearStepping();
11904 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011905}
11906
11907
11908// Creates a copy of the with context chain. The copy of the context chain is
11909// is linked to the function context supplied.
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011910static Handle<Context> CopyNestedScopeContextChain(Isolate* isolate,
11911 Handle<JSFunction> function,
11912 Handle<Context> base,
11913 JavaScriptFrame* frame,
11914 int inlined_frame_index) {
11915 HandleScope scope(isolate);
11916 List<Handle<ScopeInfo> > scope_chain;
11917 List<Handle<Context> > context_chain;
11918
11919 ScopeIterator it(isolate, frame, inlined_frame_index);
11920 for (; it.Type() != ScopeIterator::ScopeTypeGlobal &&
11921 it.Type() != ScopeIterator::ScopeTypeLocal ; it.Next()) {
11922 ASSERT(!it.Done());
11923 scope_chain.Add(it.CurrentScopeInfo());
11924 context_chain.Add(it.CurrentContext());
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000011925 }
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000011926
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011927 // At the end of the chain. Return the base context to link to.
11928 Handle<Context> context = base;
11929
11930 // Iteratively copy and or materialize the nested contexts.
11931 while (!scope_chain.is_empty()) {
11932 Handle<ScopeInfo> scope_info = scope_chain.RemoveLast();
11933 Handle<Context> current = context_chain.RemoveLast();
11934 ASSERT(!(scope_info->HasContext() & current.is_null()));
11935
11936 if (scope_info->Type() == CATCH_SCOPE) {
11937 Handle<String> name(String::cast(current->extension()));
11938 Handle<Object> thrown_object(current->get(Context::THROWN_OBJECT_INDEX));
11939 context =
11940 isolate->factory()->NewCatchContext(function,
11941 context,
11942 name,
11943 thrown_object);
11944 } else if (scope_info->Type() == BLOCK_SCOPE) {
11945 // Materialize the contents of the block scope into a JSObject.
11946 Handle<JSObject> block_scope_object =
11947 MaterializeBlockScope(isolate, current);
11948 if (block_scope_object.is_null()) {
11949 return Handle<Context>::null();
11950 }
11951 // Allocate a new function context for the debug evaluation and set the
11952 // extension object.
11953 Handle<Context> new_context =
11954 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
11955 function);
11956 new_context->set_extension(*block_scope_object);
11957 new_context->set_previous(*context);
11958 context = new_context;
11959 } else {
11960 ASSERT(scope_info->Type() == WITH_SCOPE);
11961 ASSERT(current->IsWithContext());
11962 Handle<JSObject> extension(JSObject::cast(current->extension()));
11963 context =
11964 isolate->factory()->NewWithContext(function, context, extension);
erikcorry0ad885c2011-11-21 13:51:57 +000011965 }
erikcorry0ad885c2011-11-21 13:51:57 +000011966 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000011967
11968 return scope.CloseAndEscape(context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011969}
11970
11971
11972// Helper function to find or create the arguments object for
11973// Runtime_DebugEvaluate.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011974static Handle<Object> GetArgumentsObject(Isolate* isolate,
11975 JavaScriptFrame* frame,
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000011976 int inlined_frame_index,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011977 Handle<JSFunction> function,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011978 Handle<ScopeInfo> scope_info,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011979 Handle<Context> function_context) {
11980 // Try to find the value of 'arguments' to pass as parameter. If it is not
11981 // found (that is the debugged function does not reference 'arguments' and
11982 // does not support eval) then create an 'arguments' object.
11983 int index;
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011984 if (scope_info->StackLocalCount() > 0) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011985 index = scope_info->StackSlotIndex(isolate->heap()->arguments_symbol());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011986 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011987 return Handle<Object>(frame->GetExpression(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011988 }
11989 }
11990
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000011991 if (scope_info->HasHeapAllocatedLocals()) {
11992 VariableMode mode;
11993 InitializationFlag init_flag;
11994 index = scope_info->ContextSlotIndex(
11995 isolate->heap()->arguments_symbol(), &mode, &init_flag);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011996 if (index != -1) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000011997 return Handle<Object>(function_context->get(index), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000011998 }
11999 }
12000
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012001 FrameInspector frame_inspector(frame, inlined_frame_index, isolate);
12002
12003 int length = frame_inspector.GetParametersCount();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012004 Handle<JSObject> arguments =
12005 isolate->factory()->NewArgumentsObject(function, length);
12006 Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012007
12008 AssertNoAllocation no_gc;
12009 WriteBarrierMode mode = array->GetWriteBarrierMode(no_gc);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012010 for (int i = 0; i < length; i++) {
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012011 array->set(i, frame_inspector.GetParameter(i), mode);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012012 }
kasperl@chromium.org9fe21c62008-10-28 08:53:51 +000012013 arguments->set_elements(*array);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012014 return arguments;
12015}
12016
12017
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012018static const char kSourceStr[] =
12019 "(function(arguments,__source__){return eval(__source__);})";
12020
12021
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012022// Evaluate a piece of JavaScript in the context of a stack frame for
ager@chromium.org32912102009-01-16 10:38:43 +000012023// debugging. This is accomplished by creating a new context which in its
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012024// extension part has all the parameters and locals of the function on the
12025// stack frame. A function which calls eval with the code to evaluate is then
12026// compiled in this context and called in this context. As this context
12027// replaces the context of the function on the stack frame a new (empty)
12028// function is created as well to be used as the closure for the context.
12029// This function and the context acts as replacements for the function on the
12030// stack frame presenting the same view of the values of parameters and
12031// local variables as if the piece of JavaScript was evaluated at the point
12032// where the function on the stack frame is currently stopped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012033RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluate) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012034 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012035
12036 // Check the execution state and decode arguments frame and source to be
12037 // evaluated.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012038 ASSERT(args.length() == 6);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012039 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012040 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12041 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012042 if (!maybe_check_result->ToObject(&check_result)) {
12043 return maybe_check_result;
12044 }
12045 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012046 CONVERT_CHECKED(Smi, wrapped_id, args[1]);
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012047 CONVERT_NUMBER_CHECKED(int, inlined_frame_index, Int32, args[2]);
12048 CONVERT_ARG_CHECKED(String, source, 3);
12049 CONVERT_BOOLEAN_CHECKED(disable_break, args[4]);
12050 Handle<Object> additional_context(args[5]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012051
12052 // Handle the processing of break.
12053 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012054
12055 // Get the frame where the debugging is performed.
12056 StackFrame::Id id = UnwrapFrameId(wrapped_id);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000012057 JavaScriptFrameIterator it(isolate, id);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012058 JavaScriptFrame* frame = it.frame();
12059 Handle<JSFunction> function(JSFunction::cast(frame->function()));
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012060 Handle<ScopeInfo> scope_info(function->shared()->scope_info());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012061
12062 // Traverse the saved contexts chain to find the active context for the
12063 // selected frame.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012064 SaveContext* save = FindSavedContextForFrame(isolate, frame);
12065
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012066 SaveContext savex(isolate);
12067 isolate->set_context(*(save->context()));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012068
12069 // Create the (empty) function replacing the function on the stack frame for
12070 // the purpose of evaluating in the context created below. It is important
12071 // that this function does not describe any parameters and local variables
12072 // in the context. If it does then this will cause problems with the lookup
12073 // in Context::Lookup, where context slots for parameters and local variables
12074 // are looked at before the extension object.
12075 Handle<JSFunction> go_between =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012076 isolate->factory()->NewFunction(isolate->factory()->empty_string(),
12077 isolate->factory()->undefined_value());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012078 go_between->set_context(function->context());
12079#ifdef DEBUG
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012080 Handle<ScopeInfo> go_between_scope_info(go_between->shared()->scope_info());
12081 ASSERT(go_between_scope_info->ParameterCount() == 0);
12082 ASSERT(go_between_scope_info->ContextLocalCount() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012083#endif
12084
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012085 // Materialize the content of the local scope into a JSObject.
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012086 Handle<JSObject> local_scope = MaterializeLocalScope(
12087 isolate, frame, inlined_frame_index);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012088 RETURN_IF_EMPTY_HANDLE(isolate, local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012089
12090 // Allocate a new context for the debug evaluation and set the extension
12091 // object build.
12092 Handle<Context> context =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012093 isolate->factory()->NewFunctionContext(Context::MIN_CONTEXT_SLOTS,
12094 go_between);
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012095 context->set_extension(*local_scope);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012096 // Copy any with contexts present and chain them in front of this context.
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012097 Handle<Context> frame_context(Context::cast(frame->context()));
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012098 Handle<Context> function_context;
12099 // Get the function's context if it has one.
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012100 if (scope_info->HasContext()) {
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012101 function_context = Handle<Context>(frame_context->declaration_context());
12102 }
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012103 context = CopyNestedScopeContextChain(isolate,
12104 go_between,
12105 context,
12106 frame,
12107 inlined_frame_index);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012108
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012109 if (additional_context->IsJSObject()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012110 Handle<JSObject> extension = Handle<JSObject>::cast(additional_context);
vegorov@chromium.org3cf47312011-06-29 13:20:01 +000012111 context =
12112 isolate->factory()->NewWithContext(go_between, context, extension);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012113 }
12114
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012115 // Wrap the evaluation statement in a new function compiled in the newly
12116 // created context. The function has one parameter which has to be called
12117 // 'arguments'. This it to have access to what would have been 'arguments' in
ager@chromium.org32912102009-01-16 10:38:43 +000012118 // the function being debugged.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012119 // function(arguments,__source__) {return eval(__source__);}
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012120
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012121 Handle<String> function_source =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012122 isolate->factory()->NewStringFromAscii(
12123 Vector<const char>(kSourceStr, sizeof(kSourceStr) - 1));
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012124
12125 // Currently, the eval code will be executed in non-strict mode,
12126 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012127 Handle<SharedFunctionInfo> shared =
ager@chromium.org381abbb2009-02-25 13:23:22 +000012128 Compiler::CompileEval(function_source,
12129 context,
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012130 context->IsGlobalContext(),
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012131 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012132 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012133 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012134 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012135 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared, context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012136
12137 // Invoke the result of the compilation to get the evaluation function.
12138 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012139 Handle<Object> receiver(frame->receiver(), isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012140 Handle<Object> evaluation_function =
12141 Execution::Call(compiled_function, receiver, 0, NULL,
12142 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012143 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012144
svenpanne@chromium.org84bcc552011-07-18 09:50:57 +000012145 Handle<Object> arguments = GetArgumentsObject(isolate,
jkummerow@chromium.orgc3b37122011-11-07 10:14:12 +000012146 frame,
12147 inlined_frame_index,
12148 function,
12149 scope_info,
12150 function_context);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012151
12152 // Invoke the evaluation function and return the result.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012153 Handle<Object> argv[] = { arguments, source };
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012154 Handle<Object> result =
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000012155 Execution::Call(Handle<JSFunction>::cast(evaluation_function),
12156 receiver,
12157 ARRAY_SIZE(argv),
12158 argv,
12159 &has_pending_exception);
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012160 if (has_pending_exception) return Failure::Exception();
ager@chromium.orgeadaf222009-06-16 09:43:10 +000012161
12162 // Skip the global proxy as it has no properties and always delegates to the
12163 // real global object.
12164 if (result->IsJSGlobalProxy()) {
12165 result = Handle<JSObject>(JSObject::cast(result->GetPrototype()));
12166 }
12167
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012168 return *result;
12169}
12170
12171
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012172RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugEvaluateGlobal) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012173 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012174
12175 // Check the execution state and decode arguments frame and source to be
12176 // evaluated.
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012177 ASSERT(args.length() == 4);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012178 Object* check_result;
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012179 { MaybeObject* maybe_check_result = Runtime_CheckExecutionState(
12180 RUNTIME_ARGUMENTS(isolate, args));
lrn@chromium.org303ada72010-10-27 09:33:13 +000012181 if (!maybe_check_result->ToObject(&check_result)) {
12182 return maybe_check_result;
12183 }
12184 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012185 CONVERT_ARG_CHECKED(String, source, 1);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012186 CONVERT_BOOLEAN_CHECKED(disable_break, args[2]);
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012187 Handle<Object> additional_context(args[3]);
kasper.lundbd3ec4e2008-07-09 11:06:54 +000012188
12189 // Handle the processing of break.
12190 DisableBreak disable_break_save(disable_break);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012191
12192 // Enter the top context from before the debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012193 SaveContext save(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012194 SaveContext* top = &save;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012195 while (top != NULL && *top->context() == *isolate->debug()->debug_context()) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012196 top = top->prev();
12197 }
12198 if (top != NULL) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012199 isolate->set_context(*top->context());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012200 }
12201
12202 // Get the global context now set to the top context from before the
12203 // debugger was invoked.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012204 Handle<Context> context = isolate->global_context();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012205
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012206 bool is_global = true;
12207
12208 if (additional_context->IsJSObject()) {
ricow@chromium.org27bf2882011-11-17 08:34:43 +000012209 // Create a new with context with the additional context information between
12210 // the context of the debugged function and the eval code to be executed.
12211 context = isolate->factory()->NewWithContext(
12212 Handle<JSFunction>(context->closure()),
12213 context,
12214 Handle<JSObject>::cast(additional_context));
ager@chromium.org5f0c45f2010-12-17 08:51:21 +000012215 is_global = false;
12216 }
12217
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012218 // Compile the source to be evaluated.
ricow@chromium.org83aa5492011-02-07 12:42:56 +000012219 // Currently, the eval code will be executed in non-strict mode,
12220 // even in the strict code context.
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012221 Handle<SharedFunctionInfo> shared =
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012222 Compiler::CompileEval(source,
12223 context,
12224 is_global,
mstarzinger@chromium.org1b3afd12011-11-29 14:28:56 +000012225 CLASSIC_MODE,
jkummerow@chromium.org04e4f1e2011-11-14 13:36:17 +000012226 RelocInfo::kNoPosition);
kmillikin@chromium.org5d8f0e62010-03-24 08:21:20 +000012227 if (shared.is_null()) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012228 Handle<JSFunction> compiled_function =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012229 Handle<JSFunction>(
12230 isolate->factory()->NewFunctionFromSharedFunctionInfo(shared,
12231 context));
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012232
12233 // Invoke the result of the compilation to get the evaluation function.
12234 bool has_pending_exception;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012235 Handle<Object> receiver = isolate->global();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012236 Handle<Object> result =
12237 Execution::Call(compiled_function, receiver, 0, NULL,
12238 &has_pending_exception);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012239 // Clear the oneshot breakpoints so that the debugger does not step further.
12240 isolate->debug()->ClearStepping();
ager@chromium.org3bf7b912008-11-17 09:09:45 +000012241 if (has_pending_exception) return Failure::Exception();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012242 return *result;
12243}
12244
12245
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012246RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetLoadedScripts) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012247 HandleScope scope(isolate);
mads.s.ager31e71382008-08-13 09:32:07 +000012248 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012249
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012250 // Fill the script objects.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012251 Handle<FixedArray> instances = isolate->debug()->GetLoadedScripts();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012252
12253 // Convert the script objects to proper JS objects.
kasperl@chromium.org71affb52009-05-26 05:44:31 +000012254 for (int i = 0; i < instances->length(); i++) {
ager@chromium.org7c537e22008-10-16 08:43:32 +000012255 Handle<Script> script = Handle<Script>(Script::cast(instances->get(i)));
12256 // Get the script wrapper in a local handle before calling GetScriptWrapper,
12257 // because using
12258 // instances->set(i, *GetScriptWrapper(script))
12259 // is unsafe as GetScriptWrapper might call GC and the C++ compiler might
12260 // already have deferenced the instances handle.
12261 Handle<JSValue> wrapper = GetScriptWrapper(script);
12262 instances->set(i, *wrapper);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012263 }
12264
12265 // Return result as a JS array.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012266 Handle<JSObject> result =
12267 isolate->factory()->NewJSObject(isolate->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012268 isolate->factory()->SetContent(Handle<JSArray>::cast(result), instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012269 return *result;
12270}
12271
12272
12273// Helper function used by Runtime_DebugReferencedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012274static int DebugReferencedBy(HeapIterator* iterator,
12275 JSObject* target,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012276 Object* instance_filter, int max_references,
12277 FixedArray* instances, int instances_size,
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012278 JSFunction* arguments_function) {
12279 NoHandleAllocation ha;
12280 AssertNoAllocation no_alloc;
12281
12282 // Iterate the heap.
12283 int count = 0;
12284 JSObject* last = NULL;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012285 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012286 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012287 (max_references == 0 || count < max_references)) {
12288 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012289 if (heap_obj->IsJSObject()) {
12290 // Skip context extension objects and argument arrays as these are
12291 // checked in the context of functions using them.
12292 JSObject* obj = JSObject::cast(heap_obj);
iposva@chromium.org245aa852009-02-10 00:49:54 +000012293 if (obj->IsJSContextExtensionObject() ||
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012294 obj->map()->constructor() == arguments_function) {
12295 continue;
12296 }
12297
12298 // Check if the JS object has a reference to the object looked for.
12299 if (obj->ReferencesObject(target)) {
12300 // Check instance filter if supplied. This is normally used to avoid
12301 // references from mirror objects (see Runtime_IsInPrototypeChain).
12302 if (!instance_filter->IsUndefined()) {
12303 Object* V = obj;
12304 while (true) {
12305 Object* prototype = V->GetPrototype();
12306 if (prototype->IsNull()) {
12307 break;
12308 }
12309 if (instance_filter == prototype) {
12310 obj = NULL; // Don't add this object.
12311 break;
12312 }
12313 V = prototype;
12314 }
12315 }
12316
12317 if (obj != NULL) {
12318 // Valid reference found add to instance array if supplied an update
12319 // count.
12320 if (instances != NULL && count < instances_size) {
12321 instances->set(count, obj);
12322 }
12323 last = obj;
12324 count++;
12325 }
12326 }
12327 }
12328 }
12329
12330 // Check for circular reference only. This can happen when the object is only
12331 // referenced from mirrors and has a circular reference in which case the
12332 // object is not really alive and would have been garbage collected if not
12333 // referenced from the mirror.
12334 if (count == 1 && last == target) {
12335 count = 0;
12336 }
12337
12338 // Return the number of referencing objects found.
12339 return count;
12340}
12341
12342
12343// Scan the heap for objects with direct references to an object
12344// args[0]: the object to find references to
12345// args[1]: constructor function for instances to exclude (Mirror)
12346// args[2]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012347RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugReferencedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012348 ASSERT(args.length() == 3);
12349
12350 // First perform a full GC in order to avoid references from dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012351 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
12352 // The heap iterator reserves the right to do a GC to make the heap iterable.
12353 // Due to the GC above we know it won't need to do that, but it seems cleaner
12354 // to get the heap iterator constructed before we start having unprotected
12355 // Object* locals that are not protected by handles.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012356
12357 // Check parameters.
12358 CONVERT_CHECKED(JSObject, target, args[0]);
12359 Object* instance_filter = args[1];
12360 RUNTIME_ASSERT(instance_filter->IsUndefined() ||
12361 instance_filter->IsJSObject());
12362 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[2]);
12363 RUNTIME_ASSERT(max_references >= 0);
12364
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012365
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012366 // Get the constructor function for context extension and arguments array.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012367 JSObject* arguments_boilerplate =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012368 isolate->context()->global_context()->arguments_boilerplate();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012369 JSFunction* arguments_function =
12370 JSFunction::cast(arguments_boilerplate->map()->constructor());
12371
12372 // Get the number of referencing objects.
12373 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012374 HeapIterator heap_iterator;
12375 count = DebugReferencedBy(&heap_iterator,
12376 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012377 NULL, 0, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012378
12379 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012380 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012381 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012382 if (!maybe_object->ToObject(&object)) return maybe_object;
12383 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012384 FixedArray* instances = FixedArray::cast(object);
12385
12386 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012387 // AllocateFixedArray above does not make the heap non-iterable.
12388 ASSERT(HEAP->IsHeapIterable());
12389 HeapIterator heap_iterator2;
12390 count = DebugReferencedBy(&heap_iterator2,
12391 target, instance_filter, max_references,
iposva@chromium.org245aa852009-02-10 00:49:54 +000012392 instances, count, arguments_function);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012393
12394 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012395 Object* result;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012396 MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012397 isolate->context()->global_context()->array_function());
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012398 if (!maybe_result->ToObject(&result)) return maybe_result;
12399 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012400}
12401
12402
12403// Helper function used by Runtime_DebugConstructedBy below.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012404static int DebugConstructedBy(HeapIterator* iterator,
12405 JSFunction* constructor,
12406 int max_references,
12407 FixedArray* instances,
12408 int instances_size) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012409 AssertNoAllocation no_alloc;
12410
12411 // Iterate the heap.
12412 int count = 0;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012413 HeapObject* heap_obj = NULL;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012414 while (((heap_obj = iterator->next()) != NULL) &&
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012415 (max_references == 0 || count < max_references)) {
12416 // Only look at all JSObjects.
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012417 if (heap_obj->IsJSObject()) {
12418 JSObject* obj = JSObject::cast(heap_obj);
12419 if (obj->map()->constructor() == constructor) {
12420 // Valid reference found add to instance array if supplied an update
12421 // count.
12422 if (instances != NULL && count < instances_size) {
12423 instances->set(count, obj);
12424 }
12425 count++;
12426 }
12427 }
12428 }
12429
12430 // Return the number of referencing objects found.
12431 return count;
12432}
12433
12434
12435// Scan the heap for objects constructed by a specific function.
12436// args[0]: the constructor to find instances of
12437// args[1]: the the maximum number of objects to return
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012438RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugConstructedBy) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012439 ASSERT(args.length() == 2);
12440
12441 // First perform a full GC in order to avoid dead objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012442 isolate->heap()->CollectAllGarbage(Heap::kMakeHeapIterableMask);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012443
12444 // Check parameters.
12445 CONVERT_CHECKED(JSFunction, constructor, args[0]);
12446 CONVERT_NUMBER_CHECKED(int32_t, max_references, Int32, args[1]);
12447 RUNTIME_ASSERT(max_references >= 0);
12448
12449 // Get the number of referencing objects.
12450 int count;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012451 HeapIterator heap_iterator;
12452 count = DebugConstructedBy(&heap_iterator,
12453 constructor,
12454 max_references,
12455 NULL,
12456 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012457
12458 // Allocate an array to hold the result.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012459 Object* object;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012460 { MaybeObject* maybe_object = isolate->heap()->AllocateFixedArray(count);
lrn@chromium.org303ada72010-10-27 09:33:13 +000012461 if (!maybe_object->ToObject(&object)) return maybe_object;
12462 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012463 FixedArray* instances = FixedArray::cast(object);
12464
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012465 ASSERT(HEAP->IsHeapIterable());
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012466 // Fill the referencing objects.
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012467 HeapIterator heap_iterator2;
12468 count = DebugConstructedBy(&heap_iterator2,
12469 constructor,
12470 max_references,
12471 instances,
12472 count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012473
12474 // Return result as JS array.
lrn@chromium.org303ada72010-10-27 09:33:13 +000012475 Object* result;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012476 { MaybeObject* maybe_result = isolate->heap()->AllocateJSObject(
12477 isolate->context()->global_context()->array_function());
lrn@chromium.org303ada72010-10-27 09:33:13 +000012478 if (!maybe_result->ToObject(&result)) return maybe_result;
12479 }
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012480 return JSArray::cast(result)->SetContent(instances);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012481}
12482
12483
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012484// Find the effective prototype object as returned by __proto__.
12485// args[0]: the object to find the prototype for.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012486RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugGetPrototype) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012487 ASSERT(args.length() == 1);
12488
12489 CONVERT_CHECKED(JSObject, obj, args[0]);
12490
ager@chromium.orgddb913d2009-01-27 10:01:48 +000012491 // Use the __proto__ accessor.
12492 return Accessors::ObjectPrototype.getter(obj, NULL);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012493}
12494
12495
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012496RUNTIME_FUNCTION(MaybeObject*, Runtime_SystemBreak) {
mads.s.ager31e71382008-08-13 09:32:07 +000012497 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012498 CPU::DebugBreak();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012499 return isolate->heap()->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000012500}
12501
12502
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012503RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleFunction) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012504#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012505 HandleScope scope(isolate);
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012506 ASSERT(args.length() == 1);
12507 // Get the function and make sure it is compiled.
12508 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012509 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012510 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012511 return Failure::Exception();
12512 }
12513 func->code()->PrintLn();
12514#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012515 return isolate->heap()->undefined_value();
ager@chromium.org65dad4b2009-04-23 08:48:43 +000012516}
ager@chromium.org9085a012009-05-11 19:22:57 +000012517
12518
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012519RUNTIME_FUNCTION(MaybeObject*, Runtime_DebugDisassembleConstructor) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012520#ifdef DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012521 HandleScope scope(isolate);
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012522 ASSERT(args.length() == 1);
12523 // Get the function and make sure it is compiled.
12524 CONVERT_ARG_CHECKED(JSFunction, func, 0);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012525 Handle<SharedFunctionInfo> shared(func->shared());
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000012526 if (!SharedFunctionInfo::EnsureCompiled(shared, KEEP_EXCEPTION)) {
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012527 return Failure::Exception();
12528 }
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000012529 shared->construct_stub()->PrintLn();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012530#endif // DEBUG
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012531 return isolate->heap()->undefined_value();
ager@chromium.org18ad94b2009-09-02 08:22:29 +000012532}
12533
12534
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012535RUNTIME_FUNCTION(MaybeObject*, Runtime_FunctionGetInferredName) {
ager@chromium.org9085a012009-05-11 19:22:57 +000012536 NoHandleAllocation ha;
12537 ASSERT(args.length() == 1);
12538
12539 CONVERT_CHECKED(JSFunction, f, args[0]);
12540 return f->shared()->inferred_name();
12541}
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000012542
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012543
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012544static int FindSharedFunctionInfosForScript(HeapIterator* iterator,
12545 Script* script,
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012546 FixedArray* buffer) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012547 AssertNoAllocation no_allocations;
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012548 int counter = 0;
12549 int buffer_size = buffer->length();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012550 for (HeapObject* obj = iterator->next();
12551 obj != NULL;
12552 obj = iterator->next()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012553 ASSERT(obj != NULL);
12554 if (!obj->IsSharedFunctionInfo()) {
12555 continue;
12556 }
12557 SharedFunctionInfo* shared = SharedFunctionInfo::cast(obj);
12558 if (shared->script() != script) {
12559 continue;
12560 }
12561 if (counter < buffer_size) {
12562 buffer->set(counter, shared);
12563 }
12564 counter++;
12565 }
12566 return counter;
12567}
12568
12569// For a script finds all SharedFunctionInfo's in the heap that points
12570// to this script. Returns JSArray of SharedFunctionInfo wrapped
12571// in OpaqueReferences.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012572RUNTIME_FUNCTION(MaybeObject*,
12573 Runtime_LiveEditFindSharedFunctionInfosForScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012574 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012575 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012576 CONVERT_CHECKED(JSValue, script_value, args[0]);
12577
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012578
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012579 Handle<Script> script = Handle<Script>(Script::cast(script_value->value()));
12580
12581 const int kBufferSize = 32;
12582
12583 Handle<FixedArray> array;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012584 array = isolate->factory()->NewFixedArray(kBufferSize);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012585 int number;
12586 {
12587 isolate->heap()->EnsureHeapIsIterable();
12588 AssertNoAllocation no_allocations;
12589 HeapIterator heap_iterator;
12590 Script* scr = *script;
12591 FixedArray* arr = *array;
12592 number = FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
12593 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012594 if (number > kBufferSize) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012595 array = isolate->factory()->NewFixedArray(number);
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000012596 isolate->heap()->EnsureHeapIsIterable();
12597 AssertNoAllocation no_allocations;
12598 HeapIterator heap_iterator;
12599 Script* scr = *script;
12600 FixedArray* arr = *array;
12601 FindSharedFunctionInfosForScript(&heap_iterator, scr, arr);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012602 }
12603
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012604 Handle<JSArray> result = isolate->factory()->NewJSArrayWithElements(array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012605 result->set_length(Smi::FromInt(number));
12606
12607 LiveEdit::WrapSharedFunctionInfos(result);
12608
12609 return *result;
12610}
12611
12612// For a script calculates compilation information about all its functions.
12613// The script source is explicitly specified by the second argument.
12614// The source of the actual script is not used, however it is important that
12615// all generated code keeps references to this particular instance of script.
12616// Returns a JSArray of compilation infos. The array is ordered so that
12617// each function with all its descendant is always stored in a continues range
12618// with the function itself going first. The root function is a script function.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012619RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditGatherCompileInfo) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012620 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012621 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012622 CONVERT_CHECKED(JSValue, script, args[0]);
12623 CONVERT_ARG_CHECKED(String, source, 1);
12624 Handle<Script> script_handle = Handle<Script>(Script::cast(script->value()));
12625
12626 JSArray* result = LiveEdit::GatherCompileInfo(script_handle, source);
12627
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012628 if (isolate->has_pending_exception()) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012629 return Failure::Exception();
12630 }
12631
12632 return result;
12633}
12634
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012635// Changes the source of the script to a new_source.
12636// If old_script_name is provided (i.e. is a String), also creates a copy of
12637// the script with its original source and sends notification to debugger.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012638RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012639 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012640 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012641 CONVERT_CHECKED(JSValue, original_script_value, args[0]);
12642 CONVERT_ARG_CHECKED(String, new_source, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012643 Handle<Object> old_script_name(args[2], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012644
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012645 CONVERT_CHECKED(Script, original_script_pointer,
12646 original_script_value->value());
12647 Handle<Script> original_script(original_script_pointer);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012648
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012649 Object* old_script = LiveEdit::ChangeScriptSource(original_script,
12650 new_source,
12651 old_script_name);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012652
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012653 if (old_script->IsScript()) {
12654 Handle<Script> script_handle(Script::cast(old_script));
12655 return *(GetScriptWrapper(script_handle));
12656 } else {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012657 return isolate->heap()->null_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012658 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012659}
12660
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012661
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012662RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSourceUpdated) {
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012663 ASSERT(args.length() == 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012664 HandleScope scope(isolate);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012665 CONVERT_ARG_CHECKED(JSArray, shared_info, 0);
12666 return LiveEdit::FunctionSourceUpdated(shared_info);
12667}
12668
12669
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012670// Replaces code of SharedFunctionInfo with a new one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012671RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceFunctionCode) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012672 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012673 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012674 CONVERT_ARG_CHECKED(JSArray, new_compile_info, 0);
12675 CONVERT_ARG_CHECKED(JSArray, shared_info, 1);
12676
ager@chromium.orgac091b72010-05-05 07:34:42 +000012677 return LiveEdit::ReplaceFunctionCode(new_compile_info, shared_info);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012678}
12679
12680// Connects SharedFunctionInfo to another script.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012681RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditFunctionSetScript) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012682 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012683 HandleScope scope(isolate);
12684 Handle<Object> function_object(args[0], isolate);
12685 Handle<Object> script_object(args[1], isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012686
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012687 if (function_object->IsJSValue()) {
12688 Handle<JSValue> function_wrapper = Handle<JSValue>::cast(function_object);
12689 if (script_object->IsJSValue()) {
12690 CONVERT_CHECKED(Script, script, JSValue::cast(*script_object)->value());
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012691 script_object = Handle<Object>(script, isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012692 }
12693
12694 LiveEdit::SetFunctionScript(function_wrapper, script_object);
12695 } else {
12696 // Just ignore this. We may not have a SharedFunctionInfo for some functions
12697 // and we check it in this function.
12698 }
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012699
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012700 return isolate->heap()->undefined_value();
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012701}
12702
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012703
12704// In a code of a parent function replaces original function as embedded object
12705// with a substitution one.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012706RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditReplaceRefToNestedFunction) {
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012707 ASSERT(args.length() == 3);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012708 HandleScope scope(isolate);
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012709
12710 CONVERT_ARG_CHECKED(JSValue, parent_wrapper, 0);
12711 CONVERT_ARG_CHECKED(JSValue, orig_wrapper, 1);
12712 CONVERT_ARG_CHECKED(JSValue, subst_wrapper, 2);
12713
12714 LiveEdit::ReplaceRefToNestedFunction(parent_wrapper, orig_wrapper,
12715 subst_wrapper);
12716
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012717 return isolate->heap()->undefined_value();
kmillikin@chromium.org4111b802010-05-03 10:34:42 +000012718}
12719
12720
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012721// Updates positions of a shared function info (first parameter) according
12722// to script source change. Text change is described in second parameter as
12723// array of groups of 3 numbers:
12724// (change_begin, change_end, change_end_new_position).
12725// Each group describes a change in text; groups are sorted by change_begin.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012726RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditPatchFunctionPositions) {
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012727 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012728 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012729 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
12730 CONVERT_ARG_CHECKED(JSArray, position_change_array, 1);
12731
ager@chromium.orgac091b72010-05-05 07:34:42 +000012732 return LiveEdit::PatchFunctionPositions(shared_array, position_change_array);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012733}
12734
12735
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012736// For array of SharedFunctionInfo's (each wrapped in JSValue)
12737// checks that none of them have activations on stacks (of any thread).
12738// Returns array of the same length with corresponding results of
12739// LiveEdit::FunctionPatchabilityStatus type.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012740RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCheckAndDropActivations) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012741 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012742 HandleScope scope(isolate);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012743 CONVERT_ARG_CHECKED(JSArray, shared_array, 0);
ager@chromium.org357bf652010-04-12 11:30:10 +000012744 CONVERT_BOOLEAN_CHECKED(do_drop, args[1]);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012745
ager@chromium.org357bf652010-04-12 11:30:10 +000012746 return *LiveEdit::CheckAndDropActivations(shared_array, do_drop);
ager@chromium.orgce5e87b2010-03-10 10:24:18 +000012747}
12748
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012749// Compares 2 strings line-by-line, then token-wise and returns diff in form
12750// of JSArray of triplets (pos1, pos1_end, pos2_end) describing list
12751// of diff chunks.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012752RUNTIME_FUNCTION(MaybeObject*, Runtime_LiveEditCompareStrings) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012753 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012754 HandleScope scope(isolate);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012755 CONVERT_ARG_CHECKED(String, s1, 0);
12756 CONVERT_ARG_CHECKED(String, s2, 1);
12757
sgjesse@chromium.orgc6c57182011-01-17 12:24:25 +000012758 return *LiveEdit::CompareStrings(s1, s2);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000012759}
12760
12761
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012762// A testing entry. Returns statement position which is the closest to
12763// source_position.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012764RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFunctionCodePositionFromSource) {
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012765 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012766 HandleScope scope(isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012767 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12768 CONVERT_NUMBER_CHECKED(int32_t, source_position, Int32, args[1]);
12769
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012770 Handle<Code> code(function->code(), isolate);
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012771
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012772 if (code->kind() != Code::FUNCTION &&
12773 code->kind() != Code::OPTIMIZED_FUNCTION) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012774 return isolate->heap()->undefined_value();
kasperl@chromium.orga5551262010-12-07 12:49:48 +000012775 }
12776
12777 RelocIterator it(*code, RelocInfo::ModeMask(RelocInfo::STATEMENT_POSITION));
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012778 int closest_pc = 0;
12779 int distance = kMaxInt;
12780 while (!it.done()) {
12781 int statement_position = static_cast<int>(it.rinfo()->data());
12782 // Check if this break point is closer that what was previously found.
12783 if (source_position <= statement_position &&
12784 statement_position - source_position < distance) {
whesse@chromium.orgb6e43bb2010-04-14 09:36:28 +000012785 closest_pc =
12786 static_cast<int>(it.rinfo()->pc() - code->instruction_start());
fschneider@chromium.org086aac62010-03-17 13:18:24 +000012787 distance = statement_position - source_position;
12788 // Check whether we can't get any closer.
12789 if (distance == 0) break;
12790 }
12791 it.next();
12792 }
12793
12794 return Smi::FromInt(closest_pc);
12795}
12796
12797
ager@chromium.org357bf652010-04-12 11:30:10 +000012798// Calls specified function with or without entering the debugger.
12799// This is used in unit tests to run code as if debugger is entered or simply
12800// to have a stack with C++ frame in the middle.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012801RUNTIME_FUNCTION(MaybeObject*, Runtime_ExecuteInDebugContext) {
ager@chromium.org357bf652010-04-12 11:30:10 +000012802 ASSERT(args.length() == 2);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012803 HandleScope scope(isolate);
ager@chromium.org357bf652010-04-12 11:30:10 +000012804 CONVERT_ARG_CHECKED(JSFunction, function, 0);
12805 CONVERT_BOOLEAN_CHECKED(without_debugger, args[1]);
12806
12807 Handle<Object> result;
12808 bool pending_exception;
12809 {
12810 if (without_debugger) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012811 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012812 &pending_exception);
12813 } else {
12814 EnterDebugger enter_debugger;
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012815 result = Execution::Call(function, isolate->global(), 0, NULL,
ager@chromium.org357bf652010-04-12 11:30:10 +000012816 &pending_exception);
12817 }
12818 }
12819 if (!pending_exception) {
12820 return *result;
12821 } else {
12822 return Failure::Exception();
12823 }
12824}
12825
12826
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012827// Sets a v8 flag.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012828RUNTIME_FUNCTION(MaybeObject*, Runtime_SetFlags) {
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012829 CONVERT_CHECKED(String, arg, args[0]);
kmillikin@chromium.org83e16822011-09-13 08:21:47 +000012830 SmartArrayPointer<char> flags =
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012831 arg->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
12832 FlagList::SetFlagsFromString(*flags, StrLength(*flags));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012833 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012834}
12835
12836
12837// Performs a GC.
12838// Presently, it only does a full GC.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012839RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectGarbage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012840 isolate->heap()->CollectAllGarbage(true);
12841 return isolate->heap()->undefined_value();
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012842}
12843
12844
12845// Gets the current heap usage.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012846RUNTIME_FUNCTION(MaybeObject*, Runtime_GetHeapUsage) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012847 int usage = static_cast<int>(isolate->heap()->SizeOfObjects());
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012848 if (!Smi::IsValid(usage)) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012849 return *isolate->factory()->NewNumberFromInt(usage);
kmillikin@chromium.orgd2c22f02011-01-10 08:15:37 +000012850 }
12851 return Smi::FromInt(usage);
12852}
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012853
12854
12855// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012856RUNTIME_FUNCTION(MaybeObject*, Runtime_HasLOLEnabled) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012857#ifdef LIVE_OBJECT_LIST
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012858 return isolate->heap()->true_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012859#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012860 return isolate->heap()->false_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012861#endif
12862}
12863
12864
12865// Captures a live object list from the present heap.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012866RUNTIME_FUNCTION(MaybeObject*, Runtime_CaptureLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012867#ifdef LIVE_OBJECT_LIST
12868 return LiveObjectList::Capture();
12869#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012870 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012871#endif
12872}
12873
12874
12875// Deletes the specified live object list.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012876RUNTIME_FUNCTION(MaybeObject*, Runtime_DeleteLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012877#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012878 CONVERT_SMI_ARG_CHECKED(id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012879 bool success = LiveObjectList::Delete(id);
kmillikin@chromium.org7c2628c2011-08-10 11:27:35 +000012880 return isolate->heap()->ToBoolean(success);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012881#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012882 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012883#endif
12884}
12885
12886
12887// Generates the response to a debugger request for a dump of the objects
12888// contained in the difference between the captured live object lists
12889// specified by id1 and id2.
12890// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
12891// dumped.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012892RUNTIME_FUNCTION(MaybeObject*, Runtime_DumpLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012893#ifdef LIVE_OBJECT_LIST
12894 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012895 CONVERT_SMI_ARG_CHECKED(id1, 0);
12896 CONVERT_SMI_ARG_CHECKED(id2, 1);
12897 CONVERT_SMI_ARG_CHECKED(start, 2);
12898 CONVERT_SMI_ARG_CHECKED(count, 3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012899 CONVERT_ARG_CHECKED(JSObject, filter_obj, 4);
12900 EnterDebugger enter_debugger;
12901 return LiveObjectList::Dump(id1, id2, start, count, filter_obj);
12902#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012903 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012904#endif
12905}
12906
12907
12908// Gets the specified object as requested by the debugger.
12909// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012910RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012911#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012912 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012913 Object* result = LiveObjectList::GetObj(obj_id);
12914 return result;
12915#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012916 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012917#endif
12918}
12919
12920
12921// Gets the obj id for the specified address if valid.
12922// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012923RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjId) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012924#ifdef LIVE_OBJECT_LIST
12925 HandleScope scope;
12926 CONVERT_ARG_CHECKED(String, address, 0);
12927 Object* result = LiveObjectList::GetObjId(address);
12928 return result;
12929#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012930 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012931#endif
12932}
12933
12934
12935// Gets the retainers that references the specified object alive.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012936RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLObjRetainers) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012937#ifdef LIVE_OBJECT_LIST
12938 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012939 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012940 RUNTIME_ASSERT(args[1]->IsUndefined() || args[1]->IsJSObject());
12941 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsBoolean());
12942 RUNTIME_ASSERT(args[3]->IsUndefined() || args[3]->IsSmi());
12943 RUNTIME_ASSERT(args[4]->IsUndefined() || args[4]->IsSmi());
12944 CONVERT_ARG_CHECKED(JSObject, filter_obj, 5);
12945
12946 Handle<JSObject> instance_filter;
12947 if (args[1]->IsJSObject()) {
12948 instance_filter = args.at<JSObject>(1);
12949 }
12950 bool verbose = false;
12951 if (args[2]->IsBoolean()) {
12952 verbose = args[2]->IsTrue();
12953 }
12954 int start = 0;
12955 if (args[3]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012956 start = args.smi_at(3);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012957 }
12958 int limit = Smi::kMaxValue;
12959 if (args[4]->IsSmi()) {
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012960 limit = args.smi_at(4);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012961 }
12962
12963 return LiveObjectList::GetObjRetainers(obj_id,
12964 instance_filter,
12965 verbose,
12966 start,
12967 limit,
12968 filter_obj);
12969#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012970 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012971#endif
12972}
12973
12974
12975// Gets the reference path between 2 objects.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012976RUNTIME_FUNCTION(MaybeObject*, Runtime_GetLOLPath) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012977#ifdef LIVE_OBJECT_LIST
12978 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000012979 CONVERT_SMI_ARG_CHECKED(obj_id1, 0);
12980 CONVERT_SMI_ARG_CHECKED(obj_id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012981 RUNTIME_ASSERT(args[2]->IsUndefined() || args[2]->IsJSObject());
12982
12983 Handle<JSObject> instance_filter;
12984 if (args[2]->IsJSObject()) {
12985 instance_filter = args.at<JSObject>(2);
12986 }
12987
12988 Object* result =
12989 LiveObjectList::GetPath(obj_id1, obj_id2, instance_filter);
12990 return result;
12991#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000012992 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000012993#endif
12994}
12995
12996
12997// Generates the response to a debugger request for a list of all
12998// previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000012999RUNTIME_FUNCTION(MaybeObject*, Runtime_InfoLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013000#ifdef LIVE_OBJECT_LIST
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013001 CONVERT_SMI_ARG_CHECKED(start, 0);
13002 CONVERT_SMI_ARG_CHECKED(count, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013003 return LiveObjectList::Info(start, count);
13004#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013005 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013006#endif
13007}
13008
13009
13010// Gets a dump of the specified object as requested by the debugger.
13011// This is only used for obj ids shown in live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013012RUNTIME_FUNCTION(MaybeObject*, Runtime_PrintLOLObj) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013013#ifdef LIVE_OBJECT_LIST
13014 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013015 CONVERT_SMI_ARG_CHECKED(obj_id, 0);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013016 Object* result = LiveObjectList::PrintObj(obj_id);
13017 return result;
13018#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013019 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013020#endif
13021}
13022
13023
13024// Resets and releases all previously captured live object lists.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013025RUNTIME_FUNCTION(MaybeObject*, Runtime_ResetLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013026#ifdef LIVE_OBJECT_LIST
13027 LiveObjectList::Reset();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013028 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013029#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013030 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013031#endif
13032}
13033
13034
13035// Generates the response to a debugger request for a summary of the types
13036// of objects in the difference between the captured live object lists
13037// specified by id1 and id2.
13038// If id1 is 0 (i.e. not a valid lol), then the whole of lol id2 will be
13039// summarized.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013040RUNTIME_FUNCTION(MaybeObject*, Runtime_SummarizeLOL) {
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013041#ifdef LIVE_OBJECT_LIST
13042 HandleScope scope;
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013043 CONVERT_SMI_ARG_CHECKED(id1, 0);
13044 CONVERT_SMI_ARG_CHECKED(id2, 1);
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013045 CONVERT_ARG_CHECKED(JSObject, filter_obj, 2);
13046
13047 EnterDebugger enter_debugger;
13048 return LiveObjectList::Summarize(id1, id2, filter_obj);
13049#else
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013050 return isolate->heap()->undefined_value();
ager@chromium.org9ee27ae2011-03-02 13:43:26 +000013051#endif
13052}
13053
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013054#endif // ENABLE_DEBUGGER_SUPPORT
13055
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013056
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013057RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerResume) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013058 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013059 v8::V8::ResumeProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013060 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013061}
13062
13063
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013064RUNTIME_FUNCTION(MaybeObject*, Runtime_ProfilerPause) {
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013065 NoHandleAllocation ha;
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013066 v8::V8::PauseProfiler();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013067 return isolate->heap()->undefined_value();
sgjesse@chromium.orgac6aa172009-12-04 12:29:05 +000013068}
13069
ager@chromium.org65dad4b2009-04-23 08:48:43 +000013070
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013071// Finds the script object from the script data. NOTE: This operation uses
13072// heap traversal to find the function generated for the source position
13073// for the requested break point. For lazily compiled functions several heap
13074// traversals might be required rendering this operation as a rather slow
13075// operation. However for setting break points which is normally done through
13076// some kind of user interaction the performance is not crucial.
13077static Handle<Object> Runtime_GetScriptFromScriptName(
13078 Handle<String> script_name) {
13079 // Scan the heap for Script objects to find the script with the requested
13080 // script data.
13081 Handle<Script> script;
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013082 script_name->GetHeap()->EnsureHeapIsIterable();
13083 AssertNoAllocation no_allocation_during_heap_iteration;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013084 HeapIterator iterator;
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013085 HeapObject* obj = NULL;
13086 while (script.is_null() && ((obj = iterator.next()) != NULL)) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013087 // If a script is found check if it has the script data requested.
13088 if (obj->IsScript()) {
13089 if (Script::cast(obj)->name()->IsString()) {
13090 if (String::cast(Script::cast(obj)->name())->Equals(*script_name)) {
13091 script = Handle<Script>(Script::cast(obj));
13092 }
13093 }
13094 }
13095 }
13096
13097 // If no script with the requested script data is found return undefined.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013098 if (script.is_null()) return FACTORY->undefined_value();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013099
13100 // Return the script found.
13101 return GetScriptWrapper(script);
13102}
13103
13104
13105// Get the script object from script data. NOTE: Regarding performance
13106// see the NOTE for GetScriptFromScriptData.
13107// args[0]: script data for the script to find the source for
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013108RUNTIME_FUNCTION(MaybeObject*, Runtime_GetScript) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013109 HandleScope scope(isolate);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013110
13111 ASSERT(args.length() == 1);
13112
13113 CONVERT_CHECKED(String, script_name, args[0]);
13114
13115 // Find the requested script.
13116 Handle<Object> result =
13117 Runtime_GetScriptFromScriptName(Handle<String>(script_name));
13118 return *result;
13119}
13120
13121
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013122// Determines whether the given stack frame should be displayed in
13123// a stack trace. The caller is the error constructor that asked
13124// for the stack trace to be collected. The first time a construct
13125// call to this function is encountered it is skipped. The seen_caller
13126// in/out parameter is used to remember if the caller has been seen
13127// yet.
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013128static bool ShowFrameInStackTrace(StackFrame* raw_frame,
13129 Object* caller,
13130 bool* seen_caller) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013131 // Only display JS frames.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013132 if (!raw_frame->is_java_script()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013133 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013134 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013135 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
13136 Object* raw_fun = frame->function();
13137 // Not sure when this can happen but skip it just in case.
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013138 if (!raw_fun->IsJSFunction()) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013139 return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013140 }
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013141 if ((raw_fun == caller) && !(*seen_caller)) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013142 *seen_caller = true;
13143 return false;
13144 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013145 // Skip all frames until we've seen the caller.
13146 if (!(*seen_caller)) return false;
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013147 // Also, skip non-visible built-in functions and any call with the builtins
13148 // object as receiver, so as to not reveal either the builtins object or
13149 // an internal function.
13150 // The --builtins-in-stack-traces command line flag allows including
13151 // internal call sites in the stack trace for debugging purposes.
13152 if (!FLAG_builtins_in_stack_traces) {
13153 JSFunction* fun = JSFunction::cast(raw_fun);
13154 if (frame->receiver()->IsJSBuiltinsObject() ||
13155 (fun->IsBuiltin() && !fun->shared()->native())) {
13156 return false;
13157 }
rossberg@chromium.org717967f2011-07-20 13:44:42 +000013158 }
13159 return true;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013160}
13161
13162
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013163// Collect the raw data for a stack trace. Returns an array of 4
13164// element segments each containing a receiver, function, code and
13165// native code offset.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013166RUNTIME_FUNCTION(MaybeObject*, Runtime_CollectStackTrace) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013167 ASSERT_EQ(args.length(), 2);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013168 Handle<Object> caller = args.at<Object>(0);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013169 CONVERT_NUMBER_CHECKED(int32_t, limit, Int32, args[1]);
13170
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013171 HandleScope scope(isolate);
13172 Factory* factory = isolate->factory();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013173
kmillikin@chromium.org13bd2942009-12-16 15:36:05 +000013174 limit = Max(limit, 0); // Ensure that limit is not negative.
13175 int initial_size = Min(limit, 10);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013176 Handle<FixedArray> elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013177 factory->NewFixedArrayWithHoles(initial_size * 4);
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013178
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013179 StackFrameIterator iter(isolate);
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013180 // If the caller parameter is a function we skip frames until we're
13181 // under it before starting to collect.
13182 bool seen_caller = !caller->IsJSFunction();
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013183 int cursor = 0;
13184 int frames_seen = 0;
13185 while (!iter.done() && frames_seen < limit) {
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013186 StackFrame* raw_frame = iter.frame();
sgjesse@chromium.org0b6db592009-07-30 14:48:31 +000013187 if (ShowFrameInStackTrace(raw_frame, *caller, &seen_caller)) {
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013188 frames_seen++;
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013189 JavaScriptFrame* frame = JavaScriptFrame::cast(raw_frame);
vegorov@chromium.org74f333b2011-04-06 11:17:46 +000013190 // Set initial size to the maximum inlining level + 1 for the outermost
13191 // function.
13192 List<FrameSummary> frames(Compiler::kMaxInliningLevels + 1);
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013193 frame->Summarize(&frames);
13194 for (int i = frames.length() - 1; i >= 0; i--) {
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013195 if (cursor + 4 > elements->length()) {
13196 int new_capacity = JSObject::NewElementsCapacity(elements->length());
13197 Handle<FixedArray> new_elements =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013198 factory->NewFixedArrayWithHoles(new_capacity);
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013199 for (int i = 0; i < cursor; i++) {
13200 new_elements->set(i, elements->get(i));
13201 }
13202 elements = new_elements;
13203 }
13204 ASSERT(cursor + 4 <= elements->length());
13205
kasperl@chromium.orga5551262010-12-07 12:49:48 +000013206 Handle<Object> recv = frames[i].receiver();
13207 Handle<JSFunction> fun = frames[i].function();
13208 Handle<Code> code = frames[i].code();
13209 Handle<Smi> offset(Smi::FromInt(frames[i].offset()));
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013210 elements->set(cursor++, *recv);
13211 elements->set(cursor++, *fun);
13212 elements->set(cursor++, *code);
13213 elements->set(cursor++, *offset);
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013214 }
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013215 }
kasperl@chromium.org86f77b72009-07-06 08:21:57 +000013216 iter.Advance();
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013217 }
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013218 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
sgjesse@chromium.orgb302e562010-02-03 11:26:59 +000013219 result->set_length(Smi::FromInt(cursor));
kasperl@chromium.org2abc4502009-07-02 07:00:29 +000013220 return *result;
13221}
13222
13223
ager@chromium.org3811b432009-10-28 14:53:37 +000013224// Returns V8 version as a string.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013225RUNTIME_FUNCTION(MaybeObject*, Runtime_GetV8Version) {
ager@chromium.org3811b432009-10-28 14:53:37 +000013226 ASSERT_EQ(args.length(), 0);
13227
13228 NoHandleAllocation ha;
13229
13230 const char* version_string = v8::V8::GetVersion();
13231
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013232 return isolate->heap()->AllocateStringFromAscii(CStrVector(version_string),
13233 NOT_TENURED);
ager@chromium.org3811b432009-10-28 14:53:37 +000013234}
13235
13236
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013237RUNTIME_FUNCTION(MaybeObject*, Runtime_Abort) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013238 ASSERT(args.length() == 2);
svenpanne@chromium.org6d786c92011-06-15 10:58:27 +000013239 OS::PrintError("abort: %s\n",
13240 reinterpret_cast<char*>(args[0]) + args.smi_at(1));
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013241 isolate->PrintStack();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013242 OS::Abort();
13243 UNREACHABLE();
13244 return NULL;
13245}
13246
13247
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013248RUNTIME_FUNCTION(MaybeObject*, Runtime_GetFromCache) {
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013249 // This is only called from codegen, so checks might be more lax.
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013250 CONVERT_CHECKED(JSFunctionResultCache, cache, args[0]);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013251 Object* key = args[1];
13252
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013253 int finger_index = cache->finger_index();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013254 Object* o = cache->get(finger_index);
13255 if (o == key) {
13256 // The fastest case: hit the same place again.
13257 return cache->get(finger_index + 1);
13258 }
13259
13260 for (int i = finger_index - 2;
13261 i >= JSFunctionResultCache::kEntriesIndex;
13262 i -= 2) {
13263 o = cache->get(i);
13264 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013265 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013266 return cache->get(i + 1);
13267 }
13268 }
13269
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013270 int size = cache->size();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013271 ASSERT(size <= cache->length());
13272
13273 for (int i = size - 2; i > finger_index; i -= 2) {
13274 o = cache->get(i);
13275 if (o == key) {
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013276 cache->set_finger_index(i);
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013277 return cache->get(i + 1);
13278 }
13279 }
13280
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013281 // There is no value in the cache. Invoke the function and cache result.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013282 HandleScope scope(isolate);
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013283
13284 Handle<JSFunctionResultCache> cache_handle(cache);
13285 Handle<Object> key_handle(key);
13286 Handle<Object> value;
13287 {
13288 Handle<JSFunction> factory(JSFunction::cast(
13289 cache_handle->get(JSFunctionResultCache::kFactoryIndex)));
13290 // TODO(antonm): consider passing a receiver when constructing a cache.
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013291 Handle<Object> receiver(isolate->global_context()->global());
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013292 // This handle is nor shared, nor used later, so it's safe.
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013293 Handle<Object> argv[] = { key_handle };
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013294 bool pending_exception;
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013295 value = Execution::Call(factory,
13296 receiver,
svenpanne@chromium.orga8bb4d92011-10-10 13:20:40 +000013297 ARRAY_SIZE(argv),
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013298 argv,
13299 &pending_exception);
13300 if (pending_exception) return Failure::Exception();
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013301 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013302
13303#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013304 if (FLAG_verify_heap) {
13305 cache_handle->JSFunctionResultCacheVerify();
13306 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013307#endif
13308
13309 // Function invocation may have cleared the cache. Reread all the data.
13310 finger_index = cache_handle->finger_index();
13311 size = cache_handle->size();
13312
13313 // If we have spare room, put new data into it, otherwise evict post finger
13314 // entry which is likely to be the least recently used.
13315 int index = -1;
13316 if (size < cache_handle->length()) {
13317 cache_handle->set_size(size + JSFunctionResultCache::kEntrySize);
13318 index = size;
13319 } else {
13320 index = finger_index + JSFunctionResultCache::kEntrySize;
13321 if (index == cache_handle->length()) {
13322 index = JSFunctionResultCache::kEntriesIndex;
13323 }
13324 }
13325
13326 ASSERT(index % 2 == 0);
13327 ASSERT(index >= JSFunctionResultCache::kEntriesIndex);
13328 ASSERT(index < cache_handle->length());
13329
13330 cache_handle->set(index, *key_handle);
13331 cache_handle->set(index + 1, *value);
13332 cache_handle->set_finger_index(index);
13333
13334#ifdef DEBUG
erik.corry@gmail.com394dbcf2011-10-27 07:38:48 +000013335 if (FLAG_verify_heap) {
13336 cache_handle->JSFunctionResultCacheVerify();
13337 }
erik.corry@gmail.com0511e242011-01-19 11:11:08 +000013338#endif
13339
13340 return *value;
ricow@chromium.orgc9c80822010-04-21 08:22:37 +000013341}
13342
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013343
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013344RUNTIME_FUNCTION(MaybeObject*, Runtime_NewMessageObject) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013345 HandleScope scope(isolate);
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013346 CONVERT_ARG_CHECKED(String, type, 0);
13347 CONVERT_ARG_CHECKED(JSArray, arguments, 1);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013348 return *isolate->factory()->NewJSMessageObject(
13349 type,
13350 arguments,
13351 0,
13352 0,
13353 isolate->factory()->undefined_value(),
13354 isolate->factory()->undefined_value(),
13355 isolate->factory()->undefined_value());
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013356}
13357
13358
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013359RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetType) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013360 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13361 return message->type();
13362}
13363
13364
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013365RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetArguments) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013366 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13367 return message->arguments();
13368}
13369
13370
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013371RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetStartPosition) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013372 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13373 return Smi::FromInt(message->start_position());
13374}
13375
13376
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013377RUNTIME_FUNCTION(MaybeObject*, Runtime_MessageGetScript) {
kmillikin@chromium.org31b12772011-02-02 16:08:26 +000013378 CONVERT_CHECKED(JSMessageObject, message, args[0]);
13379 return message->script();
13380}
13381
13382
kasper.lund44510672008-07-25 07:37:58 +000013383#ifdef DEBUG
13384// ListNatives is ONLY used by the fuzz-natives.js in debug mode
13385// Exclude the code in release mode.
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013386RUNTIME_FUNCTION(MaybeObject*, Runtime_ListNatives) {
mads.s.ager31e71382008-08-13 09:32:07 +000013387 ASSERT(args.length() == 0);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013388 HandleScope scope;
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013389#define COUNT_ENTRY(Name, argc, ressize) + 1
13390 int entry_count = 0
13391 RUNTIME_FUNCTION_LIST(COUNT_ENTRY)
13392 INLINE_FUNCTION_LIST(COUNT_ENTRY)
13393 INLINE_RUNTIME_FUNCTION_LIST(COUNT_ENTRY);
13394#undef COUNT_ENTRY
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013395 Factory* factory = isolate->factory();
13396 Handle<FixedArray> elements = factory->NewFixedArray(entry_count);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013397 int index = 0;
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013398 bool inline_runtime_functions = false;
ager@chromium.orga1645e22009-09-09 19:27:10 +000013399#define ADD_ENTRY(Name, argc, ressize) \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013400 { \
13401 HandleScope inner; \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013402 Handle<String> name; \
13403 /* Inline runtime functions have an underscore in front of the name. */ \
13404 if (inline_runtime_functions) { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013405 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013406 Vector<const char>("_" #Name, StrLength("_" #Name))); \
13407 } else { \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013408 name = factory->NewStringFromAscii( \
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013409 Vector<const char>(#Name, StrLength(#Name))); \
13410 } \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013411 Handle<FixedArray> pair_elements = factory->NewFixedArray(2); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013412 pair_elements->set(0, *name); \
13413 pair_elements->set(1, Smi::FromInt(argc)); \
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013414 Handle<JSArray> pair = factory->NewJSArrayWithElements(pair_elements); \
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013415 elements->set(index++, *pair); \
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013416 }
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013417 inline_runtime_functions = false;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013418 RUNTIME_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013419 inline_runtime_functions = true;
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013420 INLINE_FUNCTION_LIST(ADD_ENTRY)
vegorov@chromium.orgf8372902010-03-15 10:26:20 +000013421 INLINE_RUNTIME_FUNCTION_LIST(ADD_ENTRY)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013422#undef ADD_ENTRY
karlklose@chromium.org8f806e82011-03-07 14:06:08 +000013423 ASSERT_EQ(index, entry_count);
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013424 Handle<JSArray> result = factory->NewJSArrayWithElements(elements);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013425 return *result;
13426}
kasper.lund44510672008-07-25 07:37:58 +000013427#endif
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013428
13429
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013430RUNTIME_FUNCTION(MaybeObject*, Runtime_Log) {
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013431 ASSERT(args.length() == 2);
ager@chromium.org381abbb2009-02-25 13:23:22 +000013432 CONVERT_CHECKED(String, format, args[0]);
13433 CONVERT_CHECKED(JSArray, elms, args[1]);
ricow@chromium.orgddd545c2011-08-24 12:02:41 +000013434 String::FlatContent format_content = format->GetFlatContent();
13435 RUNTIME_ASSERT(format_content.IsAscii());
13436 Vector<const char> chars = format_content.ToAsciiVector();
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013437 LOGGER->LogRuntime(chars, elms);
13438 return isolate->heap()->undefined_value();
christian.plesner.hansen@gmail.com37abdec2009-01-06 14:43:28 +000013439}
13440
13441
kmillikin@chromium.orgc36ce6e2011-04-04 08:25:31 +000013442RUNTIME_FUNCTION(MaybeObject*, Runtime_IS_VAR) {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013443 UNREACHABLE(); // implemented as macro in the parser
13444 return NULL;
13445}
13446
13447
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013448#define ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(Name) \
13449 RUNTIME_FUNCTION(MaybeObject*, Runtime_Has##Name) { \
13450 CONVERT_CHECKED(JSObject, obj, args[0]); \
13451 return isolate->heap()->ToBoolean(obj->Has##Name()); \
13452 }
13453
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013454ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastSmiOnlyElements)
ricow@chromium.org4f693d62011-07-04 14:01:31 +000013455ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastElements)
13456ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(FastDoubleElements)
13457ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(DictionaryElements)
13458ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalPixelElements)
13459ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalArrayElements)
13460ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalByteElements)
13461ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedByteElements)
13462ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalShortElements)
13463ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedShortElements)
13464ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalIntElements)
13465ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalUnsignedIntElements)
13466ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalFloatElements)
13467ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION(ExternalDoubleElements)
13468
13469#undef ELEMENTS_KIND_CHECK_RUNTIME_FUNCTION
13470
rossberg@chromium.orgb4b2aa62011-10-13 09:49:59 +000013471
13472RUNTIME_FUNCTION(MaybeObject*, Runtime_HaveSameMap) {
13473 ASSERT(args.length() == 2);
13474 CONVERT_CHECKED(JSObject, obj1, args[0]);
13475 CONVERT_CHECKED(JSObject, obj2, args[1]);
13476 return isolate->heap()->ToBoolean(obj1->map() == obj2->map());
13477}
13478
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013479// ----------------------------------------------------------------------------
13480// Implementation of Runtime
13481
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013482#define F(name, number_of_args, result_size) \
13483 { Runtime::k##name, Runtime::RUNTIME, #name, \
13484 FUNCTION_ADDR(Runtime_##name), number_of_args, result_size },
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013485
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013486
13487#define I(name, number_of_args, result_size) \
13488 { Runtime::kInline##name, Runtime::INLINE, \
13489 "_" #name, NULL, number_of_args, result_size },
13490
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013491static const Runtime::Function kIntrinsicFunctions[] = {
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013492 RUNTIME_FUNCTION_LIST(F)
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013493 INLINE_FUNCTION_LIST(I)
13494 INLINE_RUNTIME_FUNCTION_LIST(I)
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013495};
13496
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013497
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013498MaybeObject* Runtime::InitializeIntrinsicFunctionNames(Heap* heap,
13499 Object* dictionary) {
13500 ASSERT(Isolate::Current()->heap() == heap);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013501 ASSERT(dictionary != NULL);
13502 ASSERT(StringDictionary::cast(dictionary)->NumberOfElements() == 0);
13503 for (int i = 0; i < kNumFunctions; ++i) {
lrn@chromium.org303ada72010-10-27 09:33:13 +000013504 Object* name_symbol;
13505 { MaybeObject* maybe_name_symbol =
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013506 heap->LookupAsciiSymbol(kIntrinsicFunctions[i].name);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013507 if (!maybe_name_symbol->ToObject(&name_symbol)) return maybe_name_symbol;
13508 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013509 StringDictionary* string_dictionary = StringDictionary::cast(dictionary);
lrn@chromium.org303ada72010-10-27 09:33:13 +000013510 { MaybeObject* maybe_dictionary = string_dictionary->Add(
13511 String::cast(name_symbol),
13512 Smi::FromInt(i),
13513 PropertyDetails(NONE, NORMAL));
13514 if (!maybe_dictionary->ToObject(&dictionary)) {
13515 // Non-recoverable failure. Calling code must restart heap
13516 // initialization.
13517 return maybe_dictionary;
13518 }
13519 }
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013520 }
13521 return dictionary;
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013522}
13523
13524
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013525const Runtime::Function* Runtime::FunctionForSymbol(Handle<String> name) {
13526 Heap* heap = name->GetHeap();
13527 int entry = heap->intrinsic_function_names()->FindEntry(*name);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013528 if (entry != kNotFound) {
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013529 Object* smi_index = heap->intrinsic_function_names()->ValueAt(entry);
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013530 int function_index = Smi::cast(smi_index)->value();
13531 return &(kIntrinsicFunctions[function_index]);
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013532 }
13533 return NULL;
13534}
13535
13536
sgjesse@chromium.orgea88ce92011-03-23 11:19:56 +000013537const Runtime::Function* Runtime::FunctionForId(Runtime::FunctionId id) {
erik.corry@gmail.comd88afa22010-09-15 12:33:05 +000013538 return &(kIntrinsicFunctions[static_cast<int>(id)]);
13539}
13540
13541
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013542void Runtime::PerformGC(Object* result) {
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013543 Isolate* isolate = Isolate::Current();
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013544 Failure* failure = Failure::cast(result);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013545 if (failure->IsRetryAfterGC()) {
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013546 if (isolate->heap()->new_space()->AddFreshPage()) {
13547 return;
13548 }
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013549 // Try to do a garbage collection; ignore it if it fails. The C
13550 // entry stub will throw an out-of-memory exception in that case.
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013551 isolate->heap()->CollectGarbage(failure->allocation_space());
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013552 } else {
13553 // Handle last resort GC and make sure to allow future allocations
13554 // to grow the heap without causing GCs (if possible).
fschneider@chromium.org7979bbb2011-03-28 10:47:03 +000013555 isolate->counters()->gc_last_resort_from_js()->Increment();
erik.corry@gmail.comc3b670f2011-10-05 21:44:48 +000013556 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags);
kasperl@chromium.org9bbf9682008-10-30 11:53:07 +000013557 }
christian.plesner.hansen43d26ec2008-07-03 15:10:15 +000013558}
13559
13560
13561} } // namespace v8::internal